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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:51:16