如何将串口读取的二进制数据转换为有效ASCII字符串?
串口秤数据解码问题及解决方法
问题描述
通过USB-TTL将秤的UART连接至树莓派,秤以8位ASCII块形式发送数据。使用serial库读取串口时得到b'\xfb\x9b\xa3...'这类二进制数据,尝试ASCII解码触发UnicodeDecodeError,无法获取预期的'ST, GS 0.0 g'有效字符串。此前用USR-TCP232-T2转换器可正常获取类似'S 0.0 g\nST, GS 0.0 g...'的数据,用binascii.hexlify处理后解码结果仍不符合预期。
附操作代码及错误信息:
>>> ser = serial.Serial('/dev/ttyUSB1', 9600, timeout=0.5) >>> ser.isOpen() True >>> ser.inWaiting() 4095 >>> ser.read() b'\xfb' >>> ser.read(200) b'\xfb\x9b\xa3\x8d\x9b\xbf1\xbf\xe5\xac\x00V\xd5Ze\xfd\xbf\xbf\xbfL\xa3\x8d\x9b\xbf1\xbf\xe5\xeb\x00V\xd5Ze\xfd\xbf\xbf\xbf\x93\xa3\x8d\x9b\xfc1\xbf\xe5\xeb\x00V\xd5Ze\xfd\xbf\xbf\xbf\x93\xa3\x8d\x9b\xbf1\xfc\xe5\xeb\x00V\x15Ze\xfd\xbf\xbf\xbf\x93\xa3\x8d\x9b\xbf\xc4\xbf\xe5\xeb\x00V\xd5Ze\xfd\xbf\xbf\xbf\x93\x8c\x8d\x9b\xbf1\xbf\xe5\xeb\x00V\xd5Ze\xfd\xbf\xbf\xbf\x93\xa3\x8d\x9b\xbf\xc4\xbf\xe5\xeb\x00V\xd5Ze\xfd\xfc\xbf\xbf\x93\xa3\x8d\x9b\xbf1\xbf\xe5\xeb\x00V\xd5\x1a\\V\xfb\xfb\xfb\x9b\xa3\x8d\x9b\xbf1\xfc\xe5\xeb\x00V\xd5Ze\xfd\xbf\xfc\xbf\x93\xa3\x8d\x9b\xbf1\xbf\xe5\xeb\x00V\xd5Z\xc9\xfd\xbf\xbf\xbf\x93\xa3\x8d\x9b\xbf1\xbf\x94\xeb\x00V\x15Ze\xfd\xbf\xbf\xbf\x93' >>> ser.read(200).decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xa3 in position 0: ordinal not in range(128)
解决步骤
匹配完整串口参数:USR-TCP232-T2能正常工作,说明秤的串口参数正确,但树莓派端可能遗漏了奇偶校验、停止位等配置。工业秤常用偶校验,调整serial初始化代码:
import serial ser = serial.Serial( port='/dev/ttyUSB1', baudrate=9600, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_1, bytesize=serial.EIGHTBITS, timeout=0.5 )可根据秤的说明书微调奇偶校验和停止位参数。
用Latin-1解码并过滤无效字符:秤发送的8位ASCII包含超出0-127范围的控制字符,ascii解码会失败。用
latin-1解码(每个字节对应唯一Unicode字符,无报错)后过滤不可打印字符:raw_data = ser.read(200) decoded = raw_data.decode('latin-1') # 提取仅打印字符 valid_str = ''.join([c for c in decoded if c.isprintable()]) print(valid_str)此方法可直接提取出
'ST, GS 0.0 g'这类有效内容。排查硬件兼容性:USB-TTL模块可能存在电平不匹配(秤为RS232电平,模块为TTL电平需转换)或接线错误。确认TX接RX、RX接TX、GND共地,或更换质量可靠的USB-TTL模块测试。
解析数据帧结构:秤发送的是块数据,可能含帧头(如
0xfb)、帧尾标识。先定位帧边界再提取有效数据:buffer = b'' while True: chunk = ser.read(1024) if not chunk: break buffer += chunk # 假设帧尾为换行符,根据实际有效数据调整 if b'\n' in buffer: frames = buffer.split(b'\n') for frame in frames[:-1]: # 跳过帧头控制字符,解码有效部分 decoded_frame = frame.decode('latin-1').strip('\xfb\x9b\xa3') print(decoded_frame) buffer = frames[-1]
内容的提问来源于stack exchange,提问作者Viktor Kuryshev
相关产品推荐
相关产品推荐

