RS485 Modbus RTU Interfaces

Using RS845 Modbus RTU Devices with the Widgetlords Electronics Products

The RS485 standard is widely accepted in industrial automation along with the Modbus RTU protocol. Here is an excerpt from Wikipedia:

RS-485, also known as TIA-485(-A) or EIA-485, is a standard defining the electrical characteristics of drivers and receivers for use in serial communications systems. Electrical signaling is balanced, and multipoint systems are supported. The standard is jointly published by the Telecommunications Industry Association and Electronic Industries Alliance (TIA/EIA). Digital communications networks implementing the standard can be used effectively over long distances and in electrically noisy environments. Multiple receivers may be connected to such a network in a linear, multidrop bus. These characteristics make RS-485 useful in industrial control systems and similar applications.

In the Widgetlords Electronics product lines that include a RS485 driver, the direction whether Receive or Transmit is controlled directly via a GPIO line. Most programs available such as libmodbus or minimalmodbus for the Raspberry Pi assume the direction control is performed by the RS845 driver circuit. Typically this would be done by a 555 timer, a FTDI chip or similar circuit.

The driver chip used in our circuits is the standard half duplex RS485 chip, the Texas Instrument SN65HVD75D or equivalent:

The /RE and DE lines are tied together, when set high the transceiver is in receive mode, when set low, the transceiver is in transmit mode.

Userspace application code normally drives the direction bit of the RS845 transceiver. However, when using Modbus application libraries that do not have direct access to the direction control GPIO line, we have come up with a solution.

We have available an executable program that runs in the background which takes over the serial port and automatically controls the direction control for all standard baud rates. This program has been tested with minimalmodbus and Node-Red.

The program is called "modbusd"  and can be downloaded here:

Download the executable file "modbusd"

The following code examples were created using a Raspberry Pi 4, the PI-SPI-DIN-RTC-RS485 module, the VP-EC-8AI 8 Channel Analog Input RS485 Modbus RTU Interface (Modbus ID 1), and the VP-EC-RDU-MINI LCD Display (Modbus ID 100). All units are running Modbus RTU protocol, 19200 Baud, 8N1.

RS845 Modbus RTU Test Rig

 

Installation

Follow these installation steps:

1. Install the gpiod2 library

sudo apt install libgpiod2

2. load the "modbusd" executable program into a file folder or desktop

3. In the RPi config, ensure the uart is enabled

4. In the RPi config, ensure the serial console is disabled

5. Change the permissions for the modbusd program

chmod +x modbusd

6. For help, run

./modbusd --help

-d, --driver=GPIO GPIO pin used for transmit enable
-s, --stty=FILE Specify serial TTY
-v, --vtty=FILE Specify virtual TTY
-?, --help Give this help list
--usage Give a short usage message

7. For applications using Modbus RS485 (including Node-Red) and Widgetlords products, run in the background the program:

./modbusd -d 25 -s /dev/serial0

This will create the "/tmp/modbus" program that controls the GPIO Direction Control Pin automatically.

The various modules that support RS485 have the Direction Control GPIO Pin defined as:

GPIO 25 = PI-SPI-RS485
GPIO 25 = PI-SPI-DIN-RTC-RS485
GPIO 25 = PI-SPI-DIN-2x4MIO (Require GPIO Pin 17 set high for RS485)
GPIO 25 = PI-SPI-DIN-4AI-4KO-8DI )Requires GPIO 17 set high for RS485)
GPIO 17 = PI-SPI-DIN-4000

Applications

This method works equally well with libmodbus or minimalmodbus

Using minimalmodbus-1.0.2

The following code examples assumes the end user has gone thru and understands the minimalmodbus documentation.

These code examples use the VP-EC-8AI Modbus RTU RS485 interface as a test unit.

Holding Registers 0 thru 7 are the Calibration FAULT AD COUNTS for inputs 1 thru 8
Holding Registers 8 thru 15 are the Calibration 4mA AD COUNTS for inputs 1 thru 8
Holding Registers 16 thru 23 are the Calibratoon 20mA AD COUNTS for inputs 1 thru 8

Input Registers 0 thru 7 are the Raw AD COUNTS for inputs 1 thru 8
Input Registers 8 thru 15 are the Percentage values (x10) for inputs 1 thru 8
Holding Registers 16 thru 23 are the mA Reading (x100) for inputs 1 thru 8

Example 1: Read Channel 1, Modbus ID 1 of the VP-EC-8AI

NOTE: In each example, the serial port is set to /tmp/modbus which is set by the modbusd program which controls the RS485 Direction Control GPIO pin

#!/usr/bin/env python3
import minimalmodbus

instrument = minimalmodbus.Instrument('/tmp/modbus', 1)  # port name, slave address (in decimal)

a1_ad = instrument.read_register(0, 0, 4)  # Uses Function 4
a1_percent = instrument.read_register(8, 0, 4) # Uses Function 4
a1_mA = instrument.read_register(16, 0, 4) # Uses Function 4

print("a1 = %d ad counts" % a1_ad)
print("a1 = %.2f %% " % (a1_percent/10))
print("a1 = %.2f mA" % (a1_mA/100))

Example 2: Read Channel 1 Calibration Values

#!/usr/bin/env python3
import minimalmodbus

instrument = minimalmodbus.Instrument('/tmp/modbus', 1)  # port name, slave address (in decimal)

a1_cal_ad_fault = instrument.read_register(0, 0)
a1_cal_ad_4ma = instrument.read_register(8, 0)
a1_cal_ad_20ma = instrument.read_register(16, 0)

print("a1 cal fault = %d ad counts" % a1_cal_ad_fault)
print("a1 cal 4 mA  = %d ad counts" % a1_cal_ad_4ma)
print("a1 cal 20 mA = %d ad counts" % a1_cal_ad_20ma)\

Example 3: Write Default "Fault AD Counts" into Holding Registers

#!/usr/bin/env python3
import minimalmodbus

instrument = minimalmodbus.Instrument('/tmp/modbus', 1)  # port name, slave address (in decimal)

for i in range(0,8):
    instrument.write_register(i,325)

a1_cal_ad_fault = instrument.read_register(0, 0)
a1_cal_ad_4ma = instrument.read_register(8, 0)
a1_cal_ad_20ma = instrument.read_register(16, 0)

print("a1 cal fault = %d ad counts" % a1_cal_ad_fault)
print("a1 cal 4 mA  = %d ad counts" % a1_cal_ad_4ma)
print("a1 cal 20 mA = %d ad counts" % a1_cal_ad_20ma)

Example 4: Read mA Input Value and Display on the VP-EC-RDU-MINI LCD Display

This example is shown in the test rig picture above.

#!/usr/bin/env python3
import minimalmodbus
import time

instrument = minimalmodbus.Instrument('/tmp/modbus', 1)  # port name, slave address (in decimal)
display = minimalmodbus.Instrument('/tmp/modbus', 100)  # port name, slave address (in decimal)

display.serial.timeout = .1

a1 = instrument.read_register(16, 0, 4)  # Registernumber, number of decimals

lcd_line_1 = ("a1= %6.2f mA " % (a1/100))

print(lcd_line_1)

# write the display with spaces
for i in range(0, 40):
    display.write_register(i, 0x2020, 0)

display.write_string(0, lcd_line_1, 7)

Node-Red and Modbus RTU RS485

1. Start Node-Red and access via a web browser

2. Under pallettes, install node-red-contrib-modbus

3. NOTE: When setting up the Modbus Server Serial Port, ensure to enter the "/tmp/modbus" port name as shown in the following example

Simple Flow reading the first 8 Holding Registers of the VP-EC-8AI using Function 3

 

Setup of the Modbus Read Node

 

Setup of the Modbus Serial Node