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

Python与Arduino串口整数收发异常问题及全局读取咨询

串口通信异常排查与全局变量实现方案

问题描述

  • Python与Arduino串口通信时,发送整数后Arduino回传的值经常为0或顺序错乱,简化测试案例仍未解决。
  • 希望在Arduino中仅读取一次Python发送的整数并将其设为全局变量,此前尝试未成功。

测试代码

Arduino代码

uint32_t val1;
uint32_t val2;
uint32_t val3;

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (Serial.available() > 0) {
    // read values from Python
    val1 = Serial.parseInt();
    val2 = Serial.parseInt();
    val3 = Serial.parseInt();
  }
  
  if (Serial.available() > 0) {
    // Print received values for reading back to Python
    Serial.println(val1);
    Serial.println(val2);
    Serial.println(val3);
  }
}

Python代码

import serial
import time

port = '/dev/cu.usbmodem14301'
ser = serial.Serial(port, baudrate=115200, timeout=None)

# Wait for Arduino to initialize
time.sleep(2)

#flush input buffer
ser.reset_input_buffer()

# define three parameters/integers to send in a list
numbers = [123, 60000, 789] #max integer is 2^15-1 for normal int in Arduino, we use uint32_t in Arduino, which is an unsigned 32bit -> 2^32-1

# send to Arduino as csv
for num in numbers:
    ser.write(str(num).encode())
    ser.write(b',')  # Send comma as delimiter

# Read the response from Arduino
response = []
for _ in range(len(numbers)):
    data = ser.readline().strip()
    response.append(data.decode())

# Close the serial port
ser.close()

# Print the response
print("Response from Arduino:", response)

问题分析与解决方案

1. 串口通信异常问题

核心问题

  • Arduino端:Serial.parseInt()会等待有效数字或超时(默认1秒),若串口数据未完全传输就开始读取,会因超时返回0;且回传逻辑错误,仅当串口还有剩余数据时才回传,触发时机混乱。
  • Python端:发送数据后无结束标记,Arduino无法判断传输完成;发送后立刻读取,可能Arduino尚未完成解析流程。

修改方案

Arduino代码(修正读取与回传逻辑)
uint32_t val1;
uint32_t val2;
uint32_t val3;

void setup() {
  Serial.begin(115200);
  // 缩短超时时间,避免不必要的等待
  Serial.setTimeout(500);
}

void loop() {
  // 等待足够长度的数据,确保三个整数的完整传输
  if (Serial.available() >= 8) {
    val1 = Serial.parseInt();
    val2 = Serial.parseInt();
    val3 = Serial.parseInt();
    
    // 读取完成后立即回传,无需判断串口剩余数据
    Serial.println(val1);
    Serial.println(val2);
    Serial.println(val3);
    
    // 清空缓冲区残留数据,避免干扰下一次读取
    while(Serial.available() > 0) {
      Serial.read();
    }
  }
}
Python代码(添加结束标记,优化读取时机)
import serial
import time

port = '/dev/cu.usbmodem14301'
ser = serial.Serial(port, baudrate=115200, timeout=2)

time.sleep(2)
ser.reset_input_buffer()

numbers = [123, 60000, 789]
# 拼接成完整字符串,添加换行作为传输结束标记
send_str = ','.join(map(str, numbers)) + '\n'
ser.write(send_str.encode())

# 短暂等待Arduino处理数据
time.sleep(0.1)

response = []
for _ in range(len(numbers)):
    data = ser.readline().strip()
    if data:
        response.append(data.decode())

ser.close()
print("Response from Arduino:", response)

2. 仅读取一次并设为全局变量

通过添加初始化标志位,实现仅第一次读取数据,后续直接复用全局变量:

uint32_t val1;
uint32_t val2;
uint32_t val3;
bool is_initialized = false; // 初始化完成标志

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(1000);
}

void loop() {
  if (!is_initialized && Serial.available() >= 8) {
    // 仅执行一次数据读取
    val1 = Serial.parseInt();
    val2 = Serial.parseInt();
    val3 = Serial.parseInt();
    
    is_initialized = true; // 标记初始化完成
    // 回传一次确认读取结果
    Serial.println(val1);
    Serial.println(val2);
    Serial.println(val3);
    
    while(Serial.available() > 0) Serial.read();
  }
  
  // 后续可直接使用全局变量val1/val2/val3,示例:每隔2秒打印一次
  static unsigned long last_print = 0;
  if (is_initialized && millis() - last_print >= 2000) {
    Serial.print("Stored values: ");
    Serial.print(val1);
    Serial.print(", ");
    Serial.print(val2);
    Serial.print(", ");
    Serial.println(val3);
    last_print = millis();
  }
}

对应的Python代码无需修改,只需确保发送一次数据即可,Arduino会将其存储为全局变量持续使用。

内容的提问来源于stack exchange,提问作者Nikolaij

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:58:12