如何清除Arduino软件串口输出窗口乱码?附收发代码求助
解决SoftwareSerial通信乱码与ACK逻辑问题
让我来帮你排查并修复代码里的问题,乱码和异常输出主要来自波特率选择、数据收发逻辑的漏洞,还有字符串处理的不规范,下面是具体的分析和修正后的代码:
核心问题分析
- 非标准波特率:你用了1000这个非标准波特率,SoftwareSerial对这类波特率的时序支持很差,很容易出现数据丢包或者乱码,换成9600这种标准波特率就能解决大部分底层通信问题。
- 字符串终止符处理:C语言的字符串需要以
\0结尾才能正常打印,你的接收缓冲区没有预留终止符位置,打印时会读取内存里的随机内容,造成乱码。 - 接收逻辑漏洞:原接收端直接连续调用
read(),但串口数据可能分批到达,当缓冲区数据不足时,会读入无效值(比如-1),导致乱码;发送端判断available() ==3太严格,容易错过分批到达的数据。 - ACK触发逻辑错误:接收端用
sizeof(mystr) ==3作为触发ACK的条件,而sizeof是编译时确定的固定值(永远等于3),导致只要进入loop就会不断发送ACK,造成发送端收到重复数据。
修正后的发送端代码
#include <SoftwareSerial.h> SoftwareSerial mySerial(2, 3); // RX, TX const char* sendMsg = "CAT"; // 待发送的字符串,自带终止符 char ackBuf[4]; // 存储ACK的缓冲区(3个字符+1个终止符) const int ACK_LEN = 3; void setup() { Serial.begin(9600); mySerial.begin(9600); // 改用标准波特率9600 } void loop() { // 发送3个字符(不包含终止符) mySerial.write(sendMsg, ACK_LEN); Serial.println("已发送: CAT"); delay(1000); // 接收ACK:累计接收够3个字符再处理 if (mySerial.available() >= ACK_LEN) { for (int i = 0; i < ACK_LEN; i++) { ackBuf[i] = mySerial.read(); } ackBuf[ACK_LEN] = '\0'; // 手动添加字符串终止符 Serial.print("收到ACK: "); Serial.println(ackBuf); } }
修正后的接收端代码
#include <SoftwareSerial.h> SoftwareSerial mySerial_1(2, 3); // RX, TX char recvBuf[4]; // 接收缓冲区(3个字符+1个终止符) const int PACKET_LEN = 3; int recvCount = 0; // 记录已接收的字符数 const char* ackMsg = "YES"; // ACK字符串 void setup() { Serial.begin(9600); mySerial_1.begin(9600); // 和发送端保持相同的标准波特率 } void loop() { // 逐个读取串口数据,累计够3个再处理 while (mySerial_1.available() > 0 && recvCount < PACKET_LEN) { char c = mySerial_1.read(); // 这里可以加字符校验,比如只接收预期的C/A/T,也可以直接存储所有有效字符 if (c >= 'A' && c <= 'Z') { // 过滤无效字符,可选 recvBuf[recvCount++] = c; } } // 当接收够3个字符时,处理数据并发送ACK if (recvCount == PACKET_LEN) { recvBuf[PACKET_LEN] = '\0'; // 添加终止符,确保正常打印 Serial.print("收到数据: "); Serial.println(recvBuf); // 发送ACK(3个字符,不带终止符) mySerial_1.write(ackMsg, PACKET_LEN); Serial.println("已发送ACK: YES"); recvCount = 0; // 重置计数器,准备接收下一包数据 } }
关键改动说明
- 波特率统一为9600:标准波特率能保证SoftwareSerial的通信稳定性,避免底层时序错误导致的乱码。
- 缓冲区预留终止符位置:所有存储字符串的数组都多开一个字节,手动添加
\0,确保打印时不会出现乱码。 - 累计接收逻辑:不再假设数据一次性到达,用计数器记录接收的字符数,够数后再处理,避免读入无效数据。
- 修复ACK触发条件:用实际接收的字符数
recvCount == PACKET_LEN代替sizeof,只有真正收到完整数据包才发送ACK,避免重复发送。 - 可选的字符过滤:接收端添加了字母过滤,能进一步减少无效乱码的影响,如果你不需要可以删掉这个判断。
内容的提问来源于stack exchange,提问作者Abd
相关产品推荐
相关产品推荐

