我有一个电能表,我正在尝试通过RS485从树莓派的电表中获取电压,频率值
我对树莓派和rs485的连接如下 Rs485 DI-树莓派的TX Rs485 R0-树莓派Rx Rs485 DE / RE-树莓派的第7针
我的代码如下:
导入序列 将RPi.GPIO导入为GPIO从pymodbus.client.sync导入ModbusSerialClient作为ModbusClient
从pymodbus.register_read_message导入ReadInputRegistersResponse从pymodbus.register_read_message导入ReadInputRegistersRequest
导入日志记录
logging.basicConfig()日志= logging.getLogger() log.setLevel(logging.DEBUG)
GPIO.setmode(GPIO.BOARD)GPIO.setup(7,GPIO.OUT,initial = GPIO.LOW)
client = ModbusClient(方法='rtu',port ='/ dev / ttyS0',停止位= 1,超时= 0.3,字节大小= 8,奇偶校验='N',波特率='9600')
connection = client.connect()
打印“连接”打印连接
同时1:
volt=0 freq=0 if connection: try: voltage1= client.read_input_registers(0x000,4,unit=0x03) print voltage1 except: print "Error: No message Received" client.close()
我正在收到如下输出
DEBUG:pymodbus.transaction:Current transaction state - TRANSACTION_COMPLETE
DEBUG:pymodbus.transaction:Running transaction 4
DEBUG:pymodbus.transaction:SEND: 0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b
DEBUG:pymodbus.framer.rtu_framer:Changing state to IDLE - Last Frame End - None, Current Time stamp - 1557304284.88
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
DEBUG:pymodbus.transaction:Current transaction state - TRANSACTION_COMPLETE
DEBUG:pymodbus.transaction:Running transaction 5
DEBUG:pymodbus.transaction:Clearing current Frame : - 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.framer.rtu_framer:Resetting frame - Current Frame in buffer - 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.transaction:SEND: 0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b
DEBUG:pymodbus.framer.rtu_framer:Changing state to IDLE - Last Frame End - None, Current Time stamp - 1557304284.98
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
WARNING:pymodbus.client.sync:Cleanup recv buffer before send: 0x37 0x2e 0x35 0x35 0x20 0x33
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Incomplete message received, Expected 13 bytes Recieved 7 bytes !!!!
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x2e 0x30 0x36 0x20 0x7d 0xd 0xa
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
答案 0 :(得分:0)
如果我没弄错的话,则说明您正确定义了GPIO引脚,但从未将其高低切换。为了能够驱动RS485芯片上的DE /〜RE信号,您应该在写入总线之前将GPIO设为高电平,然后在读取仪表的答案之后将GPIO设为低电平。
不幸的是,恐怕开箱即用pyModbus无法实现您要执行的操作。您可以查看以下链接:
https://github.com/riptideio/pymodbus/issues/33
您也许可以调整pyModbus并在Pi上使用RTS替代功能(请参见此处:https://github.com/mholling/rpirtscts),但我认为这条路线不会给您带来很大的可靠性。
正如我在这里写的:RS485: Inappropriate ioctl for device,您最好选择硬件解决方案。如果您无法获得新的硬件,则可以随时尝试使用555计时器解决方案,至少作为一种临时解决方案。
祝您好运,并确保发布您的进度或任何其他想法。
编辑:使用 libmodbus 的解决方案
使用 libmodbus 的建议非常成功。如果要尝试(通过Raspberry Pi 3B测试),请按照以下步骤操作:
1)将具有GPIO支持的libmodbus分支克隆到您的Pi:
git clone https://github.com/dhruvvyas90/libmodbus
2)配置,编译和安装libmodbus库(与主库相同的命令):
./autogen.sh && ./configure --prefix=/usr && make && sudo make install
3)转到rpi-test
文件夹并编译示例:
gcc -o test -I/usr/include/modbus test.c -lmodbus
4)运行测试,您将需要更改权限或对其进行伪装:sudo ./test
您得到的实际上比我预期的要好得多,并且可能对于大多数Modbus硬件来说已经足够好了:
蓝色,表示从Pi的UART发送的TX(连接器上的引脚号8),黄色,表示应连接到RS485芯片的DE /〜RE(引脚号11,GPIO17)。如您所见,从Modbus数据帧的末尾到总线空闲,从站可以应答之前有0.6 ms的延迟。以我使用的速度(9600 bps),您需要符合Modbus规范的最小延迟约为3毫秒(3.5个字符),因此对于大多数情况来说应该没问题。
唯一要做的就是将所有这些GPIO函数添加到pylibmodbus包装器中,但这应该很容易。我计划不久后在我的Pocket Chip计算机上使用来自Python real的该库,将其用作Modbus手持式测试仪,因此,如果您或其他人设法找到时间,我将非常高兴对其进行测试。 / p>
一旦我有更多的时间,我将尝试将libmodbus与FTDI串行端口一起使用,并进行几次示波器捕获以比较硬件和软件信号。
我忘了提到我对test.c
所做的唯一更改是:
第13行:#define UART_PORT "/dev/serial0"
第14行:#define BAUD_RATE 9600
第一个只是我Pi上嵌入式串行端口的名称,第二个就是我一直用于测试目的的速度。
编辑:软件与硬件信令
正如我所承诺的,我已经测试了使用 libmodbus 提出的解决方案,但我不是将Raspberry Pi上的嵌入式UART与我的FTDI USB适配器一起使用,以比较释放总线所需的时间
您可以看到TXEN(洋红色迹线)如何在停止位后约250微秒处变低,而Pi上的GPIO(蓝色)花费的时间与上述捕获时间大致相同(500-600)微秒)。
因此,在进行更广泛的测试之前,我的结论是 libmodbus 对于没有可用的TX使能信号的UART发挥了出色的作用。我认为在大多数情况下应该有可靠的Modbus通信。
答案 1 :(得分:0)
使用 pylibmodbus
的解决方案我为 pylibmodbus 库编写了缺少的功能。
参见此处:https://github.com/marcosgatcomputer/pylibmodbus
一旦安装完所有组件( libmodbus 分支,它从上面的链接支持GPIO和 pylibmodbus ),您可以尝试测试文件:
from pylibmodbus import ModbusRtu
#Define Modbus RTU client (Python 2.x)
client=ModbusRtu(device="/dev/serial0", baud=19200, parity="N", data_bit=8, stop_bit=1)
# For Python 3.x you have to explicitly indicate ASCII enconding
#client=ModbusRtu(device="/dev/serial0".encode("ascii"), baud=19200, parity="N".encode("ascii"), data_bit=8, stop_bit=1)
#Read and set timeout
timeout_sec = client.get_response_timeout()
client.set_response_timeout(timeout_sec+1)
#Connect
client.connect()
SERVER_ID=0
BCM_PIN_DE=17
BCM_PIN_RE=9
#Set Slave ID number
client.set_slave(SERVER_ID)
#Enable RPi GPIO Functions
client.enable_rpi(1)
#Define pin numbers to be used as Read Enable (RE) and Drive Enable (DE)
client.configure_rpi_bcm_pins(BCM_PIN_DE,BCM_PIN_RE)
#Export pin direction (set as outputs)
client.rpi_pin_export_direction()
#Write Modbus registers, 10 starting from 0
client.write_registers(0, [0]*10)
#Read 10 input registers starting from number 0
result=(client.read_registers(0, 10))
#Show register values
print result
#Release pins and close connection
client.rpi_pin_unexport_direction()
client.close()
此代码适用于Rpi 3B。对于Pocket Chip,我必须修改 libmodbus 来说明GPIO引脚号(原始代码无法在/ sys / class / gpio / export文件中写入以创建gpio1015设备)。具有4位数字的硬件(如果您在/ sys / class / gpio /上看到类似gpiochipxxxx的文件夹)可能会发生此问题