Pymodbus - 在 raspberry pi3 的 uart 上通过 rs485 读取电能表的输入寄存器
Posted
技术标签:
【中文标题】Pymodbus - 在 raspberry pi3 的 uart 上通过 rs485 读取电能表的输入寄存器【英文标题】:Pymodbus - Read input register of Energy meter over rs485 on uart of raspberry pi3 【发布时间】:2019-09-25 22:35:56 【问题描述】:我有一个电能表,我正在尝试通过 RS485 从 raspberry pi uart 上的仪表中检索电压、频率值
我对树莓派和 rs485 的连接如下 Rs485 DI - 树莓派的 Tx Rs485 R0 - 树莓派的 Rx Rs485 DE/RE - 覆盆子 pi 引脚 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(method = 'rtu', port='/dev/ttyS0',stopbits = 1,timeout =0.3, bytesize = 8, parity = 'N', baudrate = '9600')
连接 = client.connect()
print "Connection" 打印连接
而 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
【问题讨论】:
【参考方案1】:pylibmodbus
的解决方案我为 pylibmodbus 库编写了缺少的函数。
请看这里:https://github.com/marcosgatcomputer/pylibmodbus
一旦你安装了所有东西(上面链接中支持 GPIO 和 pylibmodbus 的 libmodbus 分支),你可以尝试测试文件:
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 之类的文件夹)
【讨论】:
无法安装 pylibmodbus 它显示以下错误 # Failed building wheel for cffi Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build- 0ex017yi/cffi/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', ' \n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-6eyx2evi-record/install-record.txt --single-version-externally-managed --compile" 失败,错误代码 1 在 /tmp/pip-build-0ex017yi/cffi/ 您没有发布错误,但很可能与缺少库有关。你编译安装了 libmodbus 吗?您还需要使用 apt-get 安装 libmodbus-dev 目前我的硬件连接方式如下:RE/DE 引脚短接 GPIO 引脚 7,DI 连接 GPIO 引脚 14,RI 连接 GPIO 引脚 15 您可以保留自己的线路,只需更改此行:client.configure_rpi_bcm_pins(BCM_PIN_DE,BCM_PIN_RE) 并且不要忘记那些是 BCM 引脚编号raspberrypi.org/forums/viewtopic.php?t=105200 好的,我现在看到了错误。你必须更新cffi,我认为应该是pip install cffi --upgrade【参考方案2】:如果我没有弄错的话,您正确定义了您的 GPIO 引脚,但您永远不会切换它的高低。为了能够在您的 RS485 芯片上驱动 DE/~RE 信号,您应该在总线上写入之前将 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) 为您的 Pi 克隆带有 GPIO 支持的 libmodbus 分支:
git clone https://github.com/dhruvvyas90/libmodbus
2) 配置、编译和安装 libmodbus 库(与主 repo 相同的命令):
./autogen.sh && ./configure --prefix=/usr && make && sudo make install
3) 进入rpi-test
文件夹并编译示例:
gcc -o test -I/usr/include/modbus test.c -lmodbus
4) 运行测试,您将需要更改权限或 sudo 它:sudo ./test
你得到的实际上比我预期的要好得多,并且对于大多数 Modbus 硬件来说可能已经足够了:
蓝色表示来自 Pi 的 UART(连接器上的引脚 8)的 TX,黄色表示应连接到 RS485 芯片的 DE/~RE(引脚 11,GPIO17)。如您所见,从 Modbus 数据帧结束到总线空闲供从机应答之间有 0.6 毫秒的延迟。在我使用的速度(9600 bps)下,符合 Modbus 规范所需的最小延迟约为 3 毫秒(3.5 个字符),因此在大多数情况下应该没问题。
唯一未决的是将所有这些 GPIO 功能添加到 pylibmodbus 包装器中,但这应该很容易。我计划很快在现场使用 Python 的这个库和我的袖珍芯片计算机作为 Modbus 手持测试仪工作,所以如果你或其他任何人设法找到时间,我会非常乐意测试它。
一旦我有更多时间,我将尝试将 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 通信。
【讨论】:
谢谢您,先生,您的回复我试图切换方向销,但仍然无法与 pymodbus 库一起使用,我读过一些博客,如果他们提到 libmodbus 库会帮助我解决这种问题情况是方向销需要手动切换,你能帮我处理任何这样的库吗 既然你提到了,似乎 libmodbus 项目上有一个分支可以做你想做的事。看看这里:github.com/dhruvvyas90/libmodbus。在某个地方还有一个用于 libmodbus 的 Python 包装器。我现在没有任何带 GPIO 的硬件要检查,但我会尽快尝试。以上是关于Pymodbus - 在 raspberry pi3 的 uart 上通过 rs485 读取电能表的输入寄存器的主要内容,如果未能解决你的问题,请参考以下文章
树莓派(Raspberry Pi)4B无界面安装 Raspberry Pi 系统篇
树莓派(Raspberry Pi)4B无界面安装 Raspberry Pi 系统篇
在树莓派2代B型/3代 上安装Fedora23 - Installing Fedora 23 on Raspberry Pi 2 model B or Raspberry Pi 3