Python与Arduino串口通信异常:仅收到1字节响应而非完整数据
问题排查与解决方案
看起来你遇到的核心问题出在Python端的串口读取逻辑上,另外咱们也可以优化下Arduino的代码让通信更可靠。我来一步步拆解:
1. 为什么只收到1字节?
你的Python代码里用了ser.read(),但这个方法默认只读取1个字节!所以哪怕Arduino发来了16字节的完整响应,你也只取了第一个(也就是0xA1,对应十进制161)。
看这段问题代码:
if ser.inWaiting(): for Val in ser.read(): Response.append(Val)
ser.read()不带参数时返回1字节的bytes对象,遍历它自然只能得到一个值。
2. 修复Python的读取逻辑
你需要指定读取的字节数,或者循环读取直到缓冲区为空。两种方案任你选:
方案A:读取指定长度的响应(推荐)
因为你明确知道Arduino会返回16字节,所以直接读16个即可:
time.sleep(1) if ser.inWaiting() >= 16: # 确保缓冲区有足够数据 Response = list(ser.read(16)) # 一次性读取16字节并转成列表 print(*Response) print(len(Response)) # 现在应该输出16了
方案B:循环读取所有可用数据
如果后续响应长度可能变化,可以循环读取直到缓冲区为空:
time.sleep(1) while ser.inWaiting(): Response.append(ser.read()[0]) # 每次读1字节并添加到列表 print(*Response) print(len(Response))
3. Arduino代码的优化建议
你的Arduino代码虽然能工作,但有几个可以提升可靠性的点:
- 原代码里的
while(!Serial.available())会阻塞程序,万一串口数据丢失会一直卡在这里。可以加个超时判断:unsigned long timeout = millis(); while (!Serial.available()) { if (millis() - timeout > 1000) { // 1秒超时就重置 memset(SerialBuf, 0, sizeof(SerialBuf)); i = 0; return; } } - 原
loop()每次都会强制读11字节,容易残留旧数据。改成按索引逐步读取更合理:static int i = 0; // 用静态变量保持索引状态 void loop() { if (Serial.available() && i < 11) { SerialBuf[i++] = Serial.read(); } // 读完11字节后再判断是否发送响应 if (i == 11) { if(SerialBuf[8] == 0xEF){ Serial.write(FullResponse, sizeof(FullResponse)); Serial.flush(); // 确保数据全部发送完成 } i = 0; // 重置索引准备下一次接收 memset(SerialBuf, 0, sizeof(SerialBuf)); // 清空缓冲区 } }
4. 额外调试技巧
在Arduino里加打印,确认是否触发了响应发送:
if(SerialBuf[8] == 0xEF){ Serial.println("Sending full response..."); // 调试用 Serial.write(FullResponse, sizeof(FullResponse)); Serial.flush(); }打开Arduino IDE的串口监视器,看是否打印了这句话,就能确认Arduino确实发送了响应。
Python端可以先打印串口缓冲区的可用字节数,看看有没有16字节:
print("Available bytes:", ser.inWaiting())
按照上面的方法修改后,应该就能收到完整的16字节响应了。
内容的提问来源于stack exchange,提问作者Terrence
相关产品推荐
相关产品推荐

