You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

树莓派3 Python MODBUS设备读取代码返回数组问题求助

嘿,刚接触树莓派3上的Python Modbus编程对吧?别着急,咱们一步步来排查你遇到的问题——代码本来该返回整数,结果却拿到数组,大概率是在读取串口数据后的解析处理环节出了问题。结合你给出的代码片段,我整理了几个核心排查点和解决方案:

1. 串口读取返回的是字节对象,未做整数转换

ser.read()方法默认返回的是字节数组(比如b'\x00\xff'),如果直接把这个结果赋值给变量或者没做解析,就会看起来像数组。你需要把读取到的字节按照Modbus的字节规则转换成整数:

Modbus寄存器通常用大端字节序存储16位数值,所以可以用struct模块来做转换:

# 假设你读取到了响应中的数据段(比如2字节的寄存器值)
raw_data = ser.read(2)  # 读取2字节数据
# 把大端字节转换成无符号16位整数
Value1 = struct.unpack('>H', raw_data)[0]
# 如果是有符号整数,就用'>h'
# Value1 = struct.unpack('>h', raw_data)[0]

2. 没有正确提取响应帧中的有效数据

Modbus响应帧是有固定结构的,比如读取保持寄存器(功能码03)的响应格式为:

从站地址(1字节) + 功能码(1字节) + 数据长度(1字节) + 寄存器数据(N*2字节) + CRC(2字节)

如果你直接把整个响应返回,或者没截取到真正的寄存器数据部分,得到的自然是包含地址、功能码等的完整数组。必须先解析帧结构,提取出对应的数据段再转换:

# 读取完整响应(假设读1个寄存器,响应总长度为7字节)
response = ser.read(7)
# 确认功能码正确(没有返回错误)
if response[1] == 0x03:
    # 提取寄存器数据部分(第3-4字节,索引从0开始)
    raw_value = response[3:5]
    # 转换为整数
    Value1 = struct.unpack('>H', raw_value)[0]
else:
    print(f"Modbus错误: 功能码={response[1]}")

3. 变量赋值逻辑存在混乱

看你代码里一开始给Value1=65635,后来又赋值Value1=0xFF,这部分逻辑会干扰最终结果。应该在读取并解析完响应数据后,再给Value1赋值最终的整数值,而不是提前设置固定值。

补全后的完整示例代码

结合你的代码片段,我补全了一个可参考的完整版本:

import serial
import struct

# 标准Modbus CRC16计算函数
def CRCcal(message):
    crc = 0xFFFF
    for byte in message:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc >>= 1
    return (crc & 0xFF, crc >> 8)  # 返回低字节、高字节

def ReadParameter(Parameter):
    # 初始化串口(根据你的设备调整参数)
    ser = serial.Serial(
        '/dev/ttyUSB0', 
        9600, 
        parity=serial.PARITY_NONE, 
        stopbits=serial.STOPBITS_ONE, 
        bytesize=serial.EIGHTBITS, 
        timeout=1
    )
    
    # 构造Modbus读取请求帧(从站地址01,读1个保持寄存器)
    message = [0x01, 0x03, 0x00, Parameter, 0x00, 0x01, 0x00, 0x00]
    message[3] = Parameter  # 设置目标寄存器地址
    
    # 计算并填充CRC
    CRC = CRCcal(message[:-2])
    message[-2] = CRC[0]
    message[-1] = CRC[1]
    
    # 发送请求
    for item in message:
        ser.write(struct.pack('>B', item))
    
    # 读取响应并解析
    response = ser.read(7)
    if len(response) < 7:
        print("读取超时或响应不完整")
        ser.close()
        return None
    
    if response[1] == 0x03:
        raw_value = response[3:5]
        Value1 = struct.unpack('>H', raw_value)[0]
        ser.close()
        return Value1
    else:
        print(f"Modbus错误: 功能码={response[1]}")
        ser.close()
        return None

# 调用示例
result = ReadParameter(0x0001)
print(f"读取到的整数数值: {result}")

额外注意事项

  • 确认串口参数(波特率、奇偶校验、停止位)和你的Modbus设备完全匹配
  • 检查CRC计算是否正确,Modbus使用的是CRC16-IBM标准(多项式0xA001),别混用其他CRC规则
  • 如果读取多个寄存器,要调整响应长度和struct.unpack的格式(比如读2个寄存器用>HH,会返回整数元组)

内容的提问来源于stack exchange,提问作者Kiran Sutar

火山引擎 最新活动