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
相关产品推荐
相关产品推荐

