基于GSM900模块的半双工UART串口嵌入式通信程序故障排查
GSM900短信通信程序问题排查与修复
先梳理代码里的核心问题,对应给出修复方案:
1. 初始发送短信内容错误
你需求里要发送的是please go,但代码里写的是sendSMS("please allez");,内容不符会直接导致对方收到错误指令,影响后续交互逻辑。
2. 未正确解析GSM模块的短信回复格式
GSM模块通过AT+CNMI=2,2返回新短信时,输出格式是带头部的,示例如下:
+CMT: "+212xxxxxx","","24/05/20,12:34:56+08" B
你的代码直接读取第一个串口字符就判断是否为b/p,但实际最先收到的是+(来自+CMT头),根本碰不到真正的短信内容字符。必须跳过短信头,提取有效回复内容后再判断。
3. 大小写判断不兼容
你要求对方回复B或P,但代码里只判断小写的'b'和'p',如果对方回复大写字母,程序会完全无响应,需要同时兼容大小写。
4. AT指令处理依赖固定延迟,可靠性差
不管是setup里的AT指令,还是sendSMS里的流程,都用固定delay()等待模块响应,这很不稳定——模块处理速度受信号、状态影响,固定延迟要么浪费时间要么不足以完成操作。正确做法是等待模块返回的OK或特定提示符再执行下一步。
5. sendSMS函数冗余操作+流程错误
- 每次发短信都重复执行
AT+CMGF=1,setup里已经设置过短信模式,没必要重复操作; - 发送
AT+CMGS后,模块会返回>提示符,应该等待这个提示符再发送短信内容,直接用delay后发送会导致短信发送失败概率极高。
修复后的完整代码
#include <SoftwareSerial.h> SoftwareSerial SIM900(7, 8); String incomingBuffer = ""; bool waitForResponse = false; const String TARGET_PHONE = "+212684174580"; void setup() { SIM900.begin(19200); Serial.begin(19200); delay(1000); // 等待模块就绪,确认短信模式 while (!sendATCommand("AT+CMGF=1\r", "OK")) { delay(500); } // 设置新短信直接转发到串口 while (!sendATCommand("AT+CNMI=2,2,0,0,0\r", "OK")) { delay(500); } // 发送初始指令短信 if (sendSMS("please go")) { waitForResponse = true; Serial.println("初始短信已发送,等待回复..."); } else { Serial.println("初始短信发送失败"); } } void loop() { if (waitForResponse && SIM900.available() > 0) { char c = SIM900.read(); incomingBuffer += c; Serial.print(c); // 检测短信结束(以换行+回车为标志,可根据实际调整) if (incomingBuffer.endsWith("\r\n")) { // 提取短信内容:找到+CMT后的第二行就是回复内容 int cmtIndex = incomingBuffer.indexOf("+CMT:"); if (cmtIndex != -1) { // 跳过+CMT行,取下一行的内容 int contentStart = incomingBuffer.indexOf("\r\n", cmtIndex) + 2; String responseContent = incomingBuffer.substring(contentStart).trim(); // 兼容大小写判断 if (responseContent == "B" || responseContent == "b") { waitForResponse = false; if (sendSMS("bravo")) { Serial.println("回复B,已发送bravo"); } } else if (responseContent == "P" || responseContent == "p") { waitForResponse = false; if (sendSMS("already sent")) { Serial.println("回复P,已发送already sent"); } } } incomingBuffer = ""; // 清空缓存,准备接收下一条 } } } // 封装AT指令发送与响应等待函数 bool sendATCommand(const char* cmd, const char* expectedResponse) { SIM900.print(cmd); unsigned long startTime = millis(); while (millis() - startTime < 3000) { // 3秒超时 if (SIM900.available()) { String response = SIM900.readStringUntil('\n'); if (response.indexOf(expectedResponse) != -1) { return true; } } } return false; } // 封装短信发送函数 bool sendSMS(const String& message) { // 发送AT+CMGS指令,指定目标号码 if (!sendATCommand("AT+CMGS=\"" + TARGET_PHONE + "\"\r", ">")) { Serial.println("等待>提示符失败"); return false; } // 发送短信内容 SIM900.print(message); // 发送结束符Ctrl+Z(ASCII 26) SIM900.write(26); // 等待发送成功的响应 return sendATCommand("", "OK"); }
额外优化建议
- 如果你的Arduino有多余的硬件串口,尽量用硬件串口连接GSM模块,SoftwareSerial在高波特率下容易丢数据;
- 可以增加信号强度检测(
AT+CSQ),确保模块处于正常信号状态再执行操作; - 增加错误重试机制,比如短信发送失败后自动重试1-2次。
内容的提问来源于stack exchange,提问作者manal bouroukba
相关产品推荐
相关产品推荐

