Raspberry Pi RS485/Uart Modbus
Asked Answered
I

1

6

I'm attempting to get an RS485 adapter connected at the UART to communicate via modbus on a Raspberry Pi. My end goal is to have all this working with a Node application, but so far my dev has been with Python.

My hardware connection looks like:

[Modbus-Device] <===> [RS485 chip <==> Raspberry PI GPIO] pins. The RS485 has three wires (Transmit, Receive, Direction) they are connected as follows

RaspiPi <=> Adapter

GPIO 14 (8) - Tx <=> Data+

GPIO 15 (10)- Rx <=>- Data-

GPIO 18 (12) - Direction

The RS485 isn't a typical 9-pin adapter. I have three wires running off a chip. A twisted pair that serves as differential set and a ground wire.

I have been able to send serial communications between this adpater and a USB-RS485 adapter by manually flipping GPIO18 for send/recieve. (Code below)[1]. This code is purely for proving the adapter works

I'm stuck at getting modbus to work on GPIO adapter. I've tried using minimalmodbus, which works well with the USB-RS485 adapter, but fails with the GPIO adapter. I suspect this is because the direction pin isn't being set.

The ideal resolution would be to find an RS485 driver for GPIO on the pi, but short of that I see three options

1 - Make my own driver (Something I am completely unfamiliar with) 2 - Somehow get a modbus library to flip the GPIO pin in Kernel space 3 - Manually send modbus messages over serial and adjust the GPIO pin in user space. This seems the easiest but also the worst in terms of speed and reliability. My code attempt is below [2]

Any advice on this topic would be very appreciated. If someone has done something similar before and could weigh in on my options that would be helpful. I've never worked on software at this level so I wouldn't find it surprising if there were some obvious answer I'm completely overlooking.

[1] This code communicates with another RS485 adapter on the raspberry pi connected with USB. This was written to prove the GPIO adapter is working and that I can control direction with Pin 12 on the Raspberry pi

import time
import serial
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT);

ser = serial.Serial(
       port= '/dev/ttyS0',
       baudrate= 57600,
       parity= serial.PARITY_NONE,
       stopbits= serial.STOPBITS_ONE,
       bytesize= serial.EIGHTBITS,
       timeout=1
)



def write_add():
 counter = 0;
 message = 0
 while (True):
    print "writing",
    GPIO.output(12,1) #set high/transmit
    ser.write('%d \n'%(message))
    time.sleep(0.005) #baud for 57600
    #time.sleep(0.5) #baud for 9600
    GPIO.output(12, 0) #pin set to low/receive


    loop_count = 0
    res =""
    while (res == ""):
       res =ser.readline();
       if(res != ""):
         print ""
         print "Read Cycles: "+str(loop_count)+" Total: "+str(counter)
         print res
         message = int(res) + 1
         counter = counter + 1
       elif(loop_count > 10):
         res = "start over"
       else:
         print ".",
         loop_count = loop_count + 1

write_add()

[2] This code is attempting to communicate with another modbus device. My message is being sent, but the response is garabge. My assumption is that the GPIO direction pin is being flipped either too soon and cutting off the message or too late and missing some of the response.

import serial 
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)

ser = serial.Serial(
    port='/dev/ttyS0',
    baudrate = 57600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)


GPIO.output(12,1) #set high/transmit
ByteStringToSend = "\x00\x03\x01\xb8\x00\x01\x04\x02"
ser.write(ByteStringToSend)
time.sleep(0.005) #baud for 57600
GPIO.output(12, 0) #pin set to low/receive
ReceivedData = ""
while (ReceivedData == ""):
   RecievedData = ser.readline();
   print RecievedData

[3] Working USB-RS-485 code. USB adapter on Pi connected to Modbus device This code reads register 440 every second.

#1/usr/bin/env python
import minimalmodbus
import time

print minimalmodbus._getDiagnosticString()

minimalmodbus.BAUDRATE=57600
minimalmodbus.PARITY='N'
minimalmodbus.BYTESIZE=8
minimalmodbus.STOPBITS=1
minimalmodbus.TIMEOUT=0.1

instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 0)  #port and slave
#instrument.debug = True
while True:
    batterVolt = instrument.read_register(440, 2) #register number, number decimals
    print batterVolt
    time.sleep(1)

Edit: Clarified scheme. Edit2: Further clarified scheme and added/edited code

Isbella answered 16/5, 2018 at 17:19 Comment(8)
From your description I'm not able to completely imagine your hardware setup. Still, I would assume you are facing some kind of hardware layer incompatibility. Did you connected your RPI USART port to an RS485 device?Ranchod
I too am trying to understand your hardware setup. Are you doing this: Computer <-> (USB to RS485) <-> (RS485 to Serial) <-> Raspbery PI GPIO?Umbra
I've edited and I hope that sufficiently clears things up. I have an RS485 board connected directly to the RasPi GPIO pins. On the board those pins are 8,10,12 (Tx, Rx, PWM) respectively. I can get serial communication working on this adapter with the first function I wrote. But as you can see I'm manually changing the direction pin.Isbella
I still don't get it completely. Are you trying to communicate with an actual modbus device, or you are doing just an loopback? If you are communicating with an actual modbus device, the problem might be in your datagram you are sending, since the CRC is wrong. The CRC should be 0x45 0xD2 (yours is ox39 0x15).Ranchod
So the RS485 chip is between the PI GPIO and a USB-RS485 converter which is connected to a computer? I'm trying to understand how you know that TXing/RXing on the PI works.Umbra
Oh my apologies. In the first example I'm doing a loopback. <Gpio485-ttyS0> <==> <USB-485-ttyUSB0> Then end goal is to communicate with a modbus device. I've edited in my second example with a junk repsonse I'm getting. I am able to communicate with the modbus device viaUSB485. I will add the working code for that.Isbella
Maybe you are driving the GPIO pin high for too much time. The transmission is over in approximately 1.5 ms. It is possible, that the modbus device responds within those 5 ms you are waiting to drive the pin low again. And therefor you miss the message.Ranchod
Just noticed in your second example, looking at your message \"x00\x03\x01\xb8\x00\x01\x04\x02", you are sending a broadcast message (first byte = address = 0)? Realistically, you should not get a response from a broadcast message (at least on three wire half duplex) so you should not try a broadcast read. See broadcast mode on page 7: modbus.org/docs/Modbus_over_serial_line_V1_02.pdfUmbra
I
2

The code in example-2 actually works correctly. I just needed to format the response.

print RecievedData.encode('hex')

This will give the hex string in a modbus response format. As Andrej Debenjak alluded to time.sleep(x) will be dependent on baud rate and message size.

Side note: I found this page helpful in deciphering the modbus transmission.

http://www.modbustools.com/modbus.html

Edit: The ByteString I'm sending should not work on a proper modbus setup. The first byte x00 is the broadcast byte and should not solicit a response. It seems the hardware I'm working with has something funky going on. In a typical modbus setup you would need to address which device you're trying to communicate with. Thanks Marker for pointing this out.

Isbella answered 17/5, 2018 at 19:12 Comment(3)
That's interesting that it works. As I said above (unless I am missing something) "\x00\x03\x01\xb8\x00\x01\x04\x02" is a broadcasted Read Holding Registers command that requests 1 register starting at address 440. There should never be a response to a broadcast packet.Umbra
You're right. I looked at some other code written that communicates with the same slave device and it's broadcasting too. I'm wondering if the mod bus implementation on the slave machine isn't configured properly. Thanks for pointing this out.Isbella
This could certainly be problematic if you have more than 1 device on your Modbus network. It could just be a bug they missed. In practice, you should never really do a broadcast read anyway, only broadcast writes.Umbra

© 2022 - 2025 — McMap. All rights reserved.