You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:58:12