PySerial读取串口数据前出现空字节的原因及相关逻辑疑问
串口通信问题解答
问题描述
Arduino发送代码
void setup() { Serial.begin(9600); } void loop() { for(int i = 0; i < 10; i++){ Serial.print(i); delay(200); } }
Python接收代码
import serial usbport = 'COM3' ser = serial.Serial(usbport, 9600, timeout=1) count = 0 while ser.in_waiting < 1 and count < 5: p = ser.read(10) p = p.decode() print(p, type(p)) count += 1 ser.close()
现象与疑问
每次启动串口通信时Arduino会复位(此情况可接受),但Python代码总会在读取有效串口数据前读到空字节,示例输出如下:
<class 'str'> 0123456789 <class 'str'> 0123456789 <class 'str'> 0123456789 <class 'str'> 0123456789 <class 'str'>
疑问:
- 为何会读到空字节?
- 为何必须使用
while ser.in_waiting < 1 and count < 5才能正常工作,而非while ser.in_waiting?
问题解答
1. 读取到空字节的原因
这是因为Arduino串口连接后复位的过程中,串口还未准备好发送数据。Python代码打开串口后立刻尝试读取,此时Arduino正处于复位初始化阶段,还没有进入loop循环发送0-9字符,加上代码设置了timeout=1,当1秒内没有读到数据时,ser.read(10)就会返回空字节,解码后就是空字符串。
等Arduino完成复位流程,进入loop循环后,就会开始持续发送数据,后续的读取操作就能拿到完整的0123456789序列。
2. while条件的差异原因
先明确两个条件的逻辑差异:
while ser.in_waiting < 1 and count < 5:当串口接收缓冲区中没有待读取的数据,且循环次数未到5次时,执行读取操作。它的作用是主动轮询缓冲区,即使没数据也会触发读取(因为有timeout设置),等Arduino复位完成开始发数据后,后续读取就能命中有效内容。- 如果换成
while ser.in_waiting:这个条件是只有当缓冲区有数据时才执行循环体,而你的读取操作写在循环体内,这会导致缓冲区没数据时直接跳出循环,根本不会执行读取动作,自然拿不到任何数据。
其实这个写法逻辑比较绕,更合理的方式是先等待Arduino复位完成(比如加一段延时),再开始读取,或者循环读取直到拿到有效数据。
内容的提问来源于stack exchange,提问作者DrBwts
相关产品推荐
相关产品推荐

