Before starting
Modbus RTU is a widely used protocol to interact with slave devices, to write and read over their registers and control multiple end-points at the time. For a basic introduction to Modbus RTU, check out the following blog posts:
Basic setup
In this example, we used a Touchberry Panel, but the configuration and performance of the UPSafePi is the same, as it used the same GPIOs.
The Touchberry Panel will act as the master, because the screen that incorporates can be very useful to show the current states of all devices connected over Modbus RTU, such as other Industrial Shields PLCs, generic controllers or sensors.
To connect the devices, wire all the A+ pins and all the B- pins using twisted wire pairs to minimize signal reflections. Then, power up the Touchberry Panel and connect a keyboard and a mouse using the USB ports under it.
First of all, open a terminal and install the libgpiod-dev depencendy:
sudo apt install libgpiod-dev
Then, create a folder to store all the files:
mkdir modbusrtu && cd modbusrtu
Then download the corresponding files and store them under the modbusrtu directory.
This two files compose the Modbus RTU library for Touchberry Panel / UPSafePi. The Raspberry Pi port which is used to work over RS-485 is the /dev/ttyAMA0.
OS related configuration
Before starting, ensure you Operative System version is updated to the newest version (Bookworm 12 at the moment of writing this post). You can check your own version with cat /etc/os-release.
Then, add the following line in /boot/firmware/config.txt. You can open this file with:
sudo nano /boot/firmware/config.txt
By default, the Raspberry Pi serial port is /dev/ttyS0, but it is a miniUART and, because of its hardware limitations, lacks parity control, leading to incompatibility with most of Modbus RTU slave devices. The UART that has parity control is automatically occupied by the Bluetooth device.
In order to change that, we use the previous configuration. We specify the Raspberry Pi's Bluetooth device to use this miniUART, so the RPI's serial port can automatically occupy the UART, which has parity control. This serial port in specific is /dev/ttyAMA0.
Finally, reboot the device.
Test code
To test the functionality of the library we can use a script that takes as parameters the next variables:
- Slave ID
- Baudrate
- Serial configuration
- Function Code
- Address
- Value to write / Quantity to read
The code is the following:
From what can be seen, the library adapts this Function Codes:
- FC 1: Read Coils.
- FC 2: Read Discrete Inputs.
- FC 3: Read Holding Registers.
- FC 4: Read Input Registers.
- FC 5: Write Single Coil.
- FC 6: Write Single Register.
- FC 15: Write Multiple Coils.
- FC 16: Write Multiple Registers.
To compile the code, use:
gcc -o main main.c modbus.c -lgpiod
And to run:
./test <slave_id> <baudrate> <serial_config> <fc> <address> <value/quantity>
For instance, take a look at the next image:
- The first commands are with FC: 5, write coils. This set coils 0, 1 and 3 to 1.
- When reading the coils (FC: 1), it can be seen that they are written correctly.
- Next, FC: 6, which is write registers. We write 100 to register 0, 512 to register 1 and 0 to register 2.
- FC: 3 is read holding registers, and we can clearly see that it works.
This method of setting the parameters in the command line can be very useful when calling the script from a python application or Node-RED, as this script is very flexible and can be called multiple times to interact with more that one slave, changing Slave ID, Baud rate or the function code.
Code alternative
Instead of setting the parameters on the command line, we can create a script to do some petitions sequentially. For example, let's do the same as seen in the image above:
Using this code and compiling just like the other (gcc -o main2 main.c modbus.c -lgpiod), we get this result:
The result is the same, we have successfully written and read accordingly to the test we did previously.
A step further
Thanks to the flexibility of the library, it can be possible to create and develop an User Interface with Node-RED. For instance, take a look at this simple design:
This is only a basic approach. It can be taken as a starting sketch, but should be adapted to the user needs. The sketch flow is attached below. Remember to use the first code seen in this post, and compile it naming the executable file "main" (gcc -o main main.c modbus.c -lgpiod).
flows.json
How to use Modbus RTU with Touchberry Panel / UPSafePI