Pyserial读取未遵循指定字节数问题求助
嘿,我之前也遇到过串口读取参数没按预期工作的情况,咱们一步步来排查解决这个问题:
先搞清楚核心问题:为啥读2字节却得到超过16位的值?
大概率是这几个原因导致的,咱们逐个排查:
1. 串口缓冲区残留了旧数据
如果之前的串口会话没清空缓冲区,你调用read(2)时可能会把之前残留的字节和新字节一起读进来,结果自然超过2字节。
解决办法:读取前强制清空输入缓冲区
比如用pySerial的话:
ser.flushInput() # 读取数据前先清空缓冲区
如果是bash脚本:
stty -F /dev/ttyUSB0 flush
2. 对read命令的参数理解有误
很多串口库的read(n)是「最多读n字节」而非「恰好读n字节」,或者受超时设置影响。比如pySerial如果设置了timeout=0(非阻塞),可能会返回少于2字节,但如果设备一直在连续发数据,而你没处理帧边界,就会读到连续的多字节数据。
解决办法:
- 确保超时设置正确:如果要阻塞到读够2字节,把timeout设为
None(pySerial) - 验证读取的字节长度:每次读取后检查返回的字节数是不是2,比如:
ans_bytes = ser.read(2) if len(ans_bytes) != 2: print(f"Warning: Read {len(ans_bytes)} bytes instead of 2") # 这里可以加重试逻辑
3. 字节转整数时没处理字节序或截断错误
就算你真的读了2字节,如果转整数时用错了字节序,或者不小心把多个读取结果拼接了,也会得到超过16位的值。
正确的转换方式(以pySerial为例):
# 假设设备发送的是小端无符号16位整数 ans = int.from_bytes(ans_bytes, byteorder='little', signed=False) # 如果是大端,就改成byteorder='big'
要是你把多次读取的结果存在同一个变量里没重置,比如循环里ans += new_value,那肯定会累积成大数,记得每次读取前重置变量。
4. 串口配置和设备不匹配
波特率、奇偶校验、停止位、数据位这些参数必须和发送设备完全一致,否则会出现字节同步错误,导致读取的字节混乱,看起来像是读多了。
比如pySerial的正确配置示例:
import serial ser = serial.Serial( port='/dev/ttyUSB0', # 你的串口端口 baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=None # 阻塞直到读够指定字节数 )
5. 设备发送的是带帧头/帧尾的多字节帧
如果设备发送的不是单纯的2字节数据,而是包含帧头、校验位的完整帧,你直接读2字节就会读到帧头+部分数据,或者连续的多帧数据,自然超过16位。
解决办法:先用串口调试工具(比如minicom、串口助手)监听设备发送的原始数据,确认帧格式,比如是不是0xAA + 2字节数据 + 0xBB这种格式,然后先读取帧头,再读取2字节有效数据。
最后验证的小技巧
读取到字节后,先打印原始字节的十六进制值,而不是直接转成整数,这样能直观看到是不是真的读了2字节:
print(f"Raw bytes: {ans_bytes.hex()}")
如果输出是4个十六进制字符(比如1234),那就是2字节,转成整数就是16位;如果是更多字符,那就是读多了,回到前面的步骤排查。
内容的提问来源于stack exchange,提问作者Raizen

