How to Use Modbus With Raspberry Pi

198K6113

Intro: How to Use Modbus With Raspberry Pi

Modbus is a serial communication standard and has become a de facto standard communication protocol and is now a commonly available means of connecting industrial electronic devices. In Modbus RTU and Modbus ASCII RS485 is used as the physical layer. Its possible to use a Raspberry Pi as Master or Slave in Modbus applications, but a RS485 interface is needed. Our RS422 / RS485 Serial HAT is a fully galvanic isolated serial communication HAT designed for use with the Raspberry Pi and the perfect choice for such kind of applications.

The objective of this document is to show how to configure the HAT and the Raspberry Pi to be used for Modbus serial communication.

Check out our instructable about MODBUS & Arduino too!

STEP 1: Bill of Material


STEP 2: Wiring

The wiring is very simple. You have to connect only the A and B terminals of the HAT with the A and B line of the Modbus system. Y and Z terminals are not used for this kind of application. For long distances it is recommend to use twisted pairs for A and B.

STEP 3: DIP Switch Setting

Our RS422/RS485 HAT comes with 3 DIP switch banks. You have to set these DIP switches for Modbus as shown in the picture above.
Switch 1: 1-OFF 2-ON 3-ON 4-OFF

Switch 2: 1-OFF 2-OFF 3-ON 4-ON

Switch 3: 1-OFF or ON* 2-OFF 3-OFF 4-OFF

*Depending of the position of the RS422/RS485 HAT in the Modbus line you have to switch the terminating resistor ON or OFF. Please switch the resistor to ON position only if the HAT is on one end of the bus line. In all other cases switch the terminating resistor OFF:

STEP 4: Free Up Serial Line and Enable UART

The easiest way is to use the raspi-config tool to switch the
UART to the GPIO14/15 pins.

  1. take a fresh Raspbian image
  2. sudo raspi-config
  3. goto '5 Interfacing Options'
  4. goto 'P6 Serial'
  5. 'Would you like a login shell to be accessible over serial?' --> NO
  6. 'Would you like the serial port hardware to be enabled?' --> YES
  7. Finish raspi-config
  8. reboot the Raspberry Pi

Now you can access the UART via /dev/serial0

STEP 5: Software Python

You will find an easy-to-use and tested Modbus RTU and Modbus
ASCII implementation for Python on:

http://minimalmodbus.readthedocs.io/en/master/inst...

http://minimalmodbus.readthedocs.io/en/master/usag...

STEP 6: Software C++

To implement Modbus communication under c++, the use of libmodbus is recommended.

Installation:

sudo apt update
sudo apt install libmodbus-dev


Compilation of the attached demo program:

cc modbusRTU.c -o modbusRTU `pkg-config --cflags --libs libmodbus`


Start the program with:

./modbusRTU



9 Comments

Hi. I hope this question finds you well. :-) I appreaciate the quality of the documentation and instructions. Trying to read Gavazzi EM340 energymeter via modbus, I have followed the instructions ( https://www.instructables.com/How-to-Use-Modbus-Wi... ) but am unable to read any data from the meter.

The meter should be accessible via /dev/ttyAMA0:
------------
$ minimalmodbus# python -m serial.tools.list_ports
/dev/ttyAMA0
1 ports found
------------
But the script just throws an error:
------------
$ minimalmodbus# python ./minimalmodbus_testi.py
minimalmodbus.Instrument<id=0xb66d1c88, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=False, serial=Serial<id=0xb66d1ca0, open=True>(port='/dev/ttyAMA0', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=0.05, xonxoff=False, rtscts=False, dsrdtr=False)>
Traceback (most recent call last):
File "/home/pi/minimalmodbus/./minimalmodbus_testi.py", line 9, in <module>
energy = instrument.read_register(35, 1) # Registernumber, number of decimals
File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 480, in read_register
returnvalue = self._generic_command(
File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1245, in _generic_command
payload_from_slave = self._perform_command(functioncode, payload_to_slave)
File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1322, in _perform_command
response_bytes = self._communicate(request_bytes, number_of_bytes_to_read)
File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1436, in _communicate
self.serial.write(request)
File "/usr/local/lib/python3.9/dist-packages/serial/serialposix.py", line 636, in write
raise SerialTimeoutException('Write timeout')
serial.serialutil.SerialTimeoutException: Write timeout
------------
script:
------------
#!/usr/bin/env python3
import minimalmodbus

#instrument = minimalmodbus.Instrument('/dev/ttyAMA0', 1, minimalmodbus.MODE_ASCII)
instrument = minimalmodbus.Instrument('/dev/ttyAMA0', 1)
print(instrument)

## Read temperature (PV = ProcessValue) ##
energy = instrument.read_register(35, 1) # Registernumber, number of decimals
print(energy)

exit()
------------
Boot log:
------------
$ minimalmodbus# dmesg | grep tty
[ 0.000000] Kernel command line: coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 smsc95xx.macaddr=E4:5F:01:A6:85:8E vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 console=tty1 root=PARTUUID=20bc7b3e-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
[ 0.000433] printk: console [tty1] enabled
[ 1.654651] fe201000.serial: ttyAMA0 at MMIO 0xfe201000 (irq = 34, base_baud = 0) is a PL011 rev2
[ 1.663816] fe215040.serial: ttyS0 at MMIO 0xfe215040 (irq = 35, base_baud = 62500000) is a 16550
[ 3.362842] systemd[1]: Created slice system-getty.slice.
------------
Any pointers / help is highly appreciate. :-)
I also spent a while figuring out the A and B terminal labels printed on the HAT are reversed.

I'm struggling to make the HAT work with AWS Greengrass and its Modbus component. I'm not sure which part of the overall solution isn't configured right.

I have a Raspberry Pi 4B with the HAT attached, and a "WT901C High Accuracy 9 Axis RS485 Modbus" accellerometer attached to the A and B terminals (with A and B swapped as per earlier comments about the labelling being reversed on the HAT).

If I do this the Rx LED on the HAT comes on and remains constantly on. The Tx LED is off.

1) is this normal for the Rx LED to remain constantly on? I would expect that Tx and Rx would flash on and off rather than be constantly on or off?

I dont understand how to set DIP switch 3. I only have the Pi, the HAT, and the WT901C connected together with AB wires that are just dupont wires - i.e. a few cms long and not twisted or shielded. I also don't have a terminating resistor at the end of the bus.

2) I assume this is OK for a proof of concept setup like this? The WT901C came with a single cable wired into a plug that fits in the side. It has the same connector on the other side to chain devices together. Do I need to get another plug with A B cables and solder a resistor between them to terminate the bus or will it work without, albeit in a sub-optimal way?

3) The WT901C requires 5v and Gnd but the HAT doesnt provide these. I have a USB cable providing these, also plugged into the Pi. This seems like a feature the HAT should have? Wouldnt all Rs485 devices require some form of power? I realise maybe I should have got the stackable HAT and then i could use the 5v from that instead...

4) For the DIP switches I tried 2 sets of configuration:
a) The suggested RS484 settings in the HAT manual for automatic send/receive control:
Switch 1: 1-OFF 2-ON 3-ON 4-OFF
Switch 2: 1-OFF 2-OFF 3-ON 4-ON
Switch 3: 1-ON 2-OFF 3-ON 4-ON

b) https://www.instructables.com/How-to-Use-Modbus-With-Raspberry-Pi/
Switch 1: 1-OFF 2-ON 3-ON
4-OFF


Switch 2: 1-OFF 2-OFF 3-ON
4-ON


Switch 3: 1-OFF or ON*
2-OFF 3-OFF 4-OFF


*Depending of the position
of the RS422/RS485 HAT in the Modbus line you have to switch the terminating
resistor ON or OFF. Please switch the resistor to ON position only if the HAT
is on one end of the bus line. In all other cases switch the terminating
resistor OFF:

I must admit I'm confused by how all these settings are related.

Cheers
Steve


Hi Steve,

thx for your comment. About your question:
What is the version of your HAT? The problem with wrong marked AB terminals is solved since years!!! If your HAT is marked with "B A ..." the terminal labeling is right....

1.) No, RX will usually only flash if another device is sending on the RS485 bus. If this LED is always on something is wrong with the bus wiring and/or the connected device... do you have configured the UART of the Pi via raspiconfig ? Is the tx led flashing if you try to send modbus protocols? Baudrate in the RPI firmware and your device are equal?

2.) Terminating resistors are only important for long cables and high data rates. If you have only some meters distance this is not so important.....

3.) RS485 bus length can be over 1km and up to 256 devices. It makes no sense to supply other devices over this distance with 5V. Furthermore powering by the RPI makes the isolation senseless...

4.) I would prefer a)

BR

Hartmut
Hi Hartmut,

Thanks so much for your speedy and detailed reply!

My HAT is 01-04-00 and its labelled B A Z Y shield.

Ok so i will swap the cables back to match the labelling on the board then based on your comments.

1) I enabled serial comms via raspi-config. The device and Greengrass are defaulting to 9600 baud. I havent noticed Tx flashing at all.

2) Ok thanks thats good to know.

3) Ok yes I see, that makes sense.

4) OK I will use:

Switch 1: 1-OFF 2-ON 3-ON 4-OFF
Switch 2: 1-OFF 2-OFF 3-ON 4-ON
Switch 3: 1-ON 2-OFF 3-ON 4-ON

So with all these settings made the Greengrass Modbus service stops and goes into broken state when I request my device to respond. At least I can focus on that part now knowing the RS485 part is configured correctly.

Cheers,
Steve
Is there a minimalmodbus module for the Golang instead of Python?
There is a major issue with the hat: the print on the pcb for the terminal block connector A and B should be switched; took me while to figure out, but found the issue when I looked into your schematics at https://www.hwhardsoft.de/app/download/11143497697/RPI_RS485+Schematic+V01-01-00.pdf?t=1551555753 . The print for pin 1 on the terminal should be B and for pin 2 should be A.

Switching the cables (e.g. A to B and B to A) solved the issue for me.

For reference, I have board version 01-01-00
Yes, you are right. There is a small issue in the printing. We will fix it in the next batch. The workaround for this is ver simple - interchanging of A and B wire will solve this issue.
Yes; it took me an hour to figure out, so maybe you can put a warning in the current manual or something to save time of other users :)

Anyway, thanks for building the product, I find it very usefull!
This is nothing more than what's written in the designers' documentation.
Perhaps you could add some example code or a video showing the thing working.