树莓派GPIO外接RS485芯片实现Modbus通信问题求助
树莓派GPIO RS485适配Modbus通信的问题求助
我最近在折腾树莓派通过GPIO连接RS485芯片实现Modbus通信,最终目标是适配Node应用,目前先用Python做前期开发,遇到了棘手的问题,想请教大家的建议:
硬件连接方式
整体链路是:[Modbus设备] <===> [RS485芯片 <==> 树莓派GPIO]
具体接线细节:
- 树莓派GPIO14(引脚8,Tx)<=> RS485适配器Data+
- 树莓派GPIO15(引脚10,Rx)<=> RS485适配器Data-
- 树莓派GPIO18(引脚12)<=> RS485适配器方向控制引脚
注:这个RS485是芯片引出的三线(差分对+地线),不是标准9针适配器
已完成的功能验证
我已经通过手动切换GPIO18的收发状态,实现了这个GPIO-RS485适配器和USB-RS485适配器之间的串口通信,验证代码如下:
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()
遇到的核心问题
现在卡在Modbus通信适配这块:
- 用
minimalmodbus库时,USB-RS485适配器能正常和Modbus设备通信(工作代码如下),但换成GPIO-RS485适配器就完全不行,我推测是方向引脚没有被正确控制。
#!/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)
- 我尝试过在用户态手动发送Modbus消息并切换GPIO引脚,但返回的都是乱码,估计是方向引脚的切换时机不对——要么过早切换导致发送的消息被截断,要么切换太晚错过了设备的响应。代码如下:
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
目前想到的三种解决方案
- 自行开发树莓派GPIO RS485驱动:但我完全不熟悉驱动开发,门槛太高
- 让Modbus库在内核态切换GPIO引脚:不知道怎么实现,有没有现成的方法?
- 用户态手动处理消息与GPIO切换:虽然容易实现,但速度和可靠性都差,担心长期运行出问题
希望有类似经验的朋友能给我一些建议,帮我选个靠谱的方案,或者有其他更优的解决办法也欢迎告诉我,非常感谢!
内容的提问来源于stack exchange,提问作者David Ryan




