Arduino Uno与Windows PC串口通信出现意外字符的原因及解决方法
Arduino Uno与Windows PC串口通信出现意外字符问题
问题概述
Arduino Uno通过RS-232转TTL适配器连接Windows PC,使用Python发送ASCII数据,Arduino回传时出现非ASCII错误字符(0xFE/0xFF),且错误字符数量与输入中的空格数一致。实际需求是通过Arduino向TEOM控制单元发送[STX][数据][ETX]格式命令,额外字节会导致通信失败。树莓派运行相同逻辑代码可正常通信,但Arduino Uno无法正常工作。
代码片段
Python代码
import serial import time port = 'COM3' # 替换为实际串口 baud_rate = 9600 try: with serial.Serial(port, baud_rate, timeout=1) as ser: data = 'TEST as you go test and test again\r\n' encoded_data = data.encode('ascii') ser.write(encoded_data) time.sleep(1) response = ser.read_all() response = response.decode('ascii') print("Response:", response) except serial.SerialException as e: print("Error opening serial port:", e)
Arduino代码
#include <SoftwareSerial.h> SoftwareSerial SIM900(2, 3); void setup() { SIM900.begin(9600); Serial.begin(9600); Serial.println("Enter command"); } void loop() { if (Serial.available()) { String command = Serial.readStringUntil('\n'); Serial.println("C: " + command); sendCommand(command); } if (SIM900.available()) { String response = SIM900.readStringUntil('\n'); Serial.println("Response: " + response); SIM900.flush(); SIM900.print(response); } } void sendCommand(String command) { const char STX = '\x02'; const char ETX = '\x03'; SIM900.print(STX); SIM900.print(command); SIM900.print(ETX); SIM900.println(); }
报错信息
UnicodeDecodeError Traceback (most recent call last) 14 time.sleep(1) 15 response = ser.read_all() ---> 16 response = response.decode('ascii') 17 print("Response:", response) 19 except serial.SerialException as e: UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128)
补充测试中未指定编码解码时的报错:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
打印原始字节示例:
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffTEST as you go test and test again\r\r\n'
已尝试的解决方法
- 在Arduino中调用
serial.flush(),无改善 - Python发送数据后调用
ser.reset_input_buffer(),无变化 - 切换Python解码编码为
latin1或utf-8,结果更差 - 对比字节值,确认意外字符出现在响应开头
关键现象
- 意外字符(0xFE/0xFF)的数量与输入中的空格数完全一致
- 发送无空格的单个单词(如
Test)时,无意外字符 - 树莓派运行相同逻辑代码可正常通信
软件版本
- Python 3.9.12
- Arduino IDE 2.0.3(CLI版本0.29.0)
问题原因分析
- 串口引脚接反:SoftwareSerial的RX和TX引脚与RS-232转TTL适配器的接线接反,导致电平反转,接收数据时将空格字符错误识别为0xFE/0xFF。
- 代码逻辑错误:Arduino代码中错误监听硬件串口(
Serial)的输入,而非用于连接PC的软串口(SIM900),导致数据流向混乱,回传时产生错误字节。 - SoftwareSerial局限性:Arduino Uno的SoftwareSerial库在9600波特率下可靠性较低,易受中断影响,导致数据读取错误。
解决方案
1. 修正硬件接线
确保RS-232转TTL适配器的TX引脚连接到Arduino软串口的RX引脚(代码中SoftwareSerial SIM900(2,3)的第一个参数是RX,即引脚2),适配器的RX引脚连接到Arduino软串口的TX引脚(引脚3),绝对不能接反。
2. 修正Arduino代码逻辑
调整代码,让软串口负责接收PC的命令并回传,硬件串口仅用于调试:
#include <SoftwareSerial.h> // 软串口连接PC:RX=2,TX=3 SoftwareSerial PC_Serial(2, 3); void setup() { PC_Serial.begin(9600); Serial.begin(9600); // 硬件串口用于调试输出 Serial.println("Ready to receive commands"); } void loop() { // 监听PC通过软串口发来的命令 if (PC_Serial.available()) { String command = PC_Serial.readStringUntil('\n'); Serial.println("Received from PC: " + command); // 包装为[STX][数据][ETX]格式(若连接TEOM,此处改为发送给TEOM串口) const char STX = '\x02'; const char ETX = '\x03'; PC_Serial.print(STX); PC_Serial.print(command); PC_Serial.print(ETX); PC_Serial.println(); } // 若连接TEOM,添加监听TEOM响应并回传PC的逻辑 // if (TEOM_Serial.available()) { // String teom_response = TEOM_Serial.readStringUntil('\n'); // PC_Serial.println(teom_response); // } }
3. 替换更可靠的软串口库
Arduino Uno的SoftwareSerial库存在可靠性问题,建议改用AltSoftSerial库(Uno上仅支持引脚8(TX)和9(RX)),它使用硬件定时器实现,抗干扰能力更强。
4. 优化Python代码
移除不必要的time.sleep(),改用latin1解码避免报错:
import serial port = 'COM3' baud_rate = 9600 try: with serial.Serial(port, baud_rate, timeout=2) as ser: ser.reset_input_buffer() # 清空输入缓冲区 data = 'TEST as you go test and test again\r\n' ser.write(data.encode('ascii')) response = ser.read_all() print("Raw response bytes:", response) # 使用latin1解码所有字节,避免Unicode错误 response_str = response.decode('latin1') print("Decoded response:", response_str) except serial.SerialException as e: print("Serial port error:", e)
内容的提问来源于stack exchange,提问作者Richard Djarbeng
相关产品推荐
相关产品推荐

