二进制串行通信协议 - 得到意外响应

Posted

技术标签:

【中文标题】二进制串行通信协议 - 得到意外响应【英文标题】:Protocol for Serial Communication in binary - getting unexpected response 【发布时间】:2020-01-06 20:48:13 【问题描述】:

我正在尝试在 Raspberry 上使用 Python3 与串行设备进行通信。协议如下:

    主机发送命令字节(包含地址和数据类型) 设备回显命令字节 主机发送操作数字节(更多数据类型信息) 设备回显操作数字节以及数据的第一个字节 主机回显数据的第一个字节。设备发送第二个字节的数据。重复直到 5 个总数据字节

设备应该只接收和发送二进制文件(根据我一直在参考的过时手册),但是当我要求第二个数据字节时,我得到“\t”或其他一些奇怪的字符。命令、操作数和第一个数据字节似乎都可以正常工作。但在那之后,我开始得到一些意想不到的角色。

设备实际上是否以二进制以外的方式进行通信?

我的编码天赋仍处于初级阶段,因此请忽略过度使用打印命令。我是新手,请随意挑剔..

import serial
import time
import binascii

ser = serial.Serial(
    port='/dev/ttyUSB0',\
    baudrate=9600,\
    parity=serial.PARITY_NONE,\
    stopbits=serial.STOPBITS_ONE,\
    bytesize=serial.EIGHTBITS,\
    timeout = 2)

command=b"\x92"
operand =b"\x02"
sleepy = 0.2
data = bytearray()



while True:
    ser.write(command) #send command byte
    time.sleep(sleepy)
    print(ser.read(1)) #recieve command byte
    time.sleep(sleepy)


    ser.write(operand) #send operand byte
    time.sleep(sleepy)
    echo = ser.read(2)#recieve operand byte & first data byte
    print(echo)        
    time.sleep(sleepy)
    data.append(echo[1])

    ser.write(bytearray([echo[-1]])) #send first data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve second data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send second data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve third data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send third data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve fourth data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send fourth data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve 5th data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])
    print(data)




ser.close()

例如,当我运行它时,我得到数据数组“(b'\x04\x08hT^')”。 我总是得到第一个 \x04 但之后的字符是随机的。

【问题讨论】:

【参考方案1】:

我已经让这个程序工作了。我仍在获取包含一些意外字符的数据,但使用 binascii.hexlify 后跟 ":08b".format(int(c[1], base=16)) 将其转换为我需要的 8 位二进制文​​件。下面来看看似乎有效的方法。就上下文而言,该程序从水分分析仪收集数据。所以底部的数学是将 40 位二进制转换为浮点值。

def get_h20():
data = bytearray()
echo = bytearray()
command=bytearray([146])
operand =bytearray([1])
sleepy = 0.02

ser = serial.Serial(
port='/dev/ttyUSB1',\
baudrate=9600,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout = 0)

data = bytearray()
ser.write(command) #send command byte
time.sleep(sleepy)
echo = ser.read(1) #recieve command byte
data = data + echo


ser.write(operand)
time.sleep(sleepy)
echo = ser.read(2)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo


ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo
return(data)

ser.close()

将原始 h2o 数据转换为 ppb

def raw_to_ppb(数据):

raw_hex = str(binascii.hexlify(data[2:]))
c = [raw_hex[i:i+2] for i in range (0, len(raw_hex), 2)]
try:
    byte1 = ":08b".format(int(c[1], base=16))
    byte2 = ":08b".format(int(c[2], base=16))
    byte3 = ":08b".format(int(c[3], base=16))
    byte4 = ":08b".format(int(c[4], base=16))
    byte5 = ":08b".format(int(c[5], base=16))

    h20_bin = byte1+byte2+byte3+byte4+byte5

    m1 = h20_bin[14:16]
    m2 = h20_bin[17:24]
    m3 = h20_bin[25:32]
    m4 = h20_bin[33:40]
    m = m1+m2+m3+m4

    mantissa =      (int(m[0])*2**22+int(m[1])*2**21+int(m[2])*2**20+int(m[3])*\
                2**19+int(m[4])*2**18+int(m[5])*2**17+int(m[6])*2**16+int(m[7])*\
                2**15+int(m[8])*2**14+int(m[9])*2**13+int(m[10])*2**12+int(m[11])*\
                2**11+int(m[12])*2**10+int(m[13])*2**9+int(m[14])*2**8+int(m[15])*\
                 2**7+int(m[16])*2**6+int(m[17])*2**5+int(m[18])*2**4+int(m[19])*\
                 2**3+int(m[20])*2**2+int(m[21])*2**1+int(m[22])*2**0)/8388608

    e1 = h20_bin[5:8]
    e2 = h20_bin[9:14]
    e = e1+e2
    exponent = int(e,2)
    sign = (-1)**(int(h20_bin[4],2))

    h20_ppb = sign*(2**(exponent-127))*(1+mantissa)

    return(str(h20_ppb))
except:
    pass

我仍然想进一步了解从分析仪收到的数据格式。如果我从 get_h2o 函数打印数据变量,那么我仍然会得到奇怪的 "b'\x04\x08hT^" 响应......但 python 似乎知道如何处理它。

【讨论】:

以上是关于二进制串行通信协议 - 得到意外响应的主要内容,如果未能解决你的问题,请参考以下文章

一篇文章读懂什么是串口通信及其工作原理

12.串口通讯

正确实现C#<-> Arduino串行通信

硬件设计基础----通信协议UART

硬件设计基础----通信协议UART

串行通信协议