1

我有一个电能表,我正在尝试通过 RS485 从树莓派 uart 上的仪表中检索电压、频率值

我对树莓派和 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() log = logging.getLogger() log.setLevel(logging.DEBUG)

GPIO.setmode(GPIO.BOARD) GPIO.setup(7,GPIO.OUT,initial=GPIO.LOW)

客户端= ModbusClient(方法='rtu',端口='/dev/ttyS0',停止位=1,超时=0.3,字节大小=8,奇偶校验='N',波特率='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
4

2 回答 2

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 硬件来说可能已经足够好了:

示波器捕获,蓝色是 TX 线(Pi 上的引脚 8),黄色是 GPIO17(引脚 11)

在蓝色中,您可以看到来自 Pi 的 UART 的 TX(连接器上的引脚 8),在黄色中,您会看到应该连接到 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 适配器一起工作,以比较释放总线所需的时间。

*libmodbus* 延迟 500-600 微秒*

FTDI TXEN 硬件信号,延迟 250 微秒

您可以看到 TXEN(洋红色迹线)如何在停止位后大约 250 微秒后变低,而 Pi 上的 GPIO(蓝色)与上面的捕获时间(500-600 微秒)大致相同。

因此,在进行更广泛的测试之前,我的结论是libmodbus对于您没有可用的 TX 启用信号的 UART 做得很好。我认为在大多数情况下应该可以进行可靠的 Modbus 通信。

于 2019-05-13T05:34:50.287 回答
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 之类的文件夹)

于 2019-05-16T09:55:21.753 回答