如果字符串太长,则无法从功率计获得响应

Not getting a response from a power meter if the string is too long

我正在使用此代码与功率计通信:

def Hello() :
    answer = SendMessage("\x10\x49\x01\x00\x4A\x16","100b01000c16")
    if answer == 1:
        answer = SendMessage("\x10\x40\x01\x00\x41\x16","100001000116")
    if answer == 1:
        answer = SendMessage("\x10\x49\x01\x00\x4A\x16","100b01000c16")
    if answer == 1:
        answer = SendMessage("\x68\x0D\x0D\x68\x73\x01\x00\xB7\x01\x06\x01\x00\x00\x01\x00\x00\x00\x34\x16","100001000116")   
    if answer ==  1:
        input3 = input ("progress")

def SendMessage(message, expected):
    out = ''
    while out == '':
        # send the character to the device
        print (message)
        ser.write(message.encode())
        #Let's wait one second before reading output (let's give device time to answer)
        time.sleep(0.02)
        while ser.inWaiting() > 0:
            out += ser.readline().hex()
            if out != '':
                print (">>>>" + out)
                if out == expected:
                    print("Correct response")
                    out = ''
                    answer = 1
                    return answer
                else:
                    print("Incorrect response")
                    answer = 0
                    return answer

OpenComm = Hello()

代码远非理想。现在只是概念验证。

根据我从同一个功率计获得的日志,当我发送

68 0D 0D 68 73 01 00 B7 01 06 01 00 00 01 00 00 00 34 16

它应该回复

10 00 01 00 01 16

但是现在当我发送特定消息时它没有做任何事情(尽管它确实响应了之前的消息)。可能是十六进制太长了吗?如果是这样,我有什么解决办法吗?

我是这样配置串口的:

ser = serial.Serial(
    port = "COM3",
    baudrate=9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_TWO,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

您的代码中存在一个很小但很重要的问题。

您将原始字节用作字符串的符号 "\x10\x49\x01\x00\x4A\x16" 实际上应该是 b"\x10\x49\x01\x00\x4A\x16".

当您发送短命令时这没有问题,因为这些命令没有任何非 ASCII 字符。但是根据您的长命令,您有 \xB7。如果您尝试以下操作:

>>> b"\xb7"=="\xb7".encode()

在您的 Python 解释器上,您将得到:False

如果你这样做:

>>> "\x68\x0D\x0D\x68\x73\x01\x00\xB7\x01\x06\x01\x00\x00\x01\x00\x00\x00\x34\x16".encode()

你会得到:

b'h\r\rhs\x01\x00\xc2\xb7\x01\x06\x01\x00\x00\x01\x00\x00\x004\x16'

所以当你编码时你会看到"\xB7:

>>> "\xb7".encode()

你得到 b'\xc2\xb7' 意味着你发送了一个虚假字节。

要修复它,只需更正在命令中添加 b"... 的符号,并在写入端口时删除 .encode()

在意识到问题之前,我认为您的命令语法可能有问题。但是检查 this document,一切似乎都是有序的(除了设备地址和校验和之外,您的命令与第 83 页上的命令完全相同)。我不能 100% 确定修复符号会解决您的问题,但我非常乐观。

编辑:正如下面评论中所讨论的,还有一个事实是 serial.write() 是非阻塞的,所以它会立即 returns。由于将一定数量的字节写入总线(以波特率指示的速度)需要一些时间。针对您的情况进行粗略计算,如果您等待 20 毫秒(使用 time.sleep(0.02)),缓冲区将写入大约 9600 bps*(20ms/1000ms)*0.1bytes/1bit=19 字节。

这对于您的短命令可能就足够了,但考虑到您应该留出一小段时间让仪表有时间对命令做出反应并发回它的答案,对于长命令,您可能需要增加延迟到 50-100 毫秒。