如何读取 arduino 串口上的 GSM AT 命令响应以获得长响应?

How to read GSM AT command response on arduino Serial port for long response?

我有 Arduino UNO 和一个 Sim800L 模块,我知道读取串行的方法,它类似于 ,但是当我执行此功能时:

    String GetRegData()
    {
      Serial.println("Get nearby antenna info ...");
      SIM800L.print("AT+CNETSCAN=1\r");
      delay(1000);

      SIM800L.print("AT+CNETSCAN\r"); 
      delay(1000);

      String buffer2;

      while (SIM800L.available())
       {
          char c = SIM800L.read();
          Serial.print(c);
          buffer2.concat(c);
          delay(10);
       }
       //Serial.println();
       return buffer2;
    }

输出为:

AT+CMGF=1

OK
AT+CNMI=2,2,0,0,0

OK
AT+CNETSCAN=1

OK
AT+CNETSCAN

Operator:"XXXX",MCC:XXX,MNC:XX,Rxlev:XX,Cellid:XX,Arfcn:XX,Lac:q5er32xlAair32xlAacrseifcca,Nvdc00

当我在此设备上手动执行此命令时,此 AT 命令 (AT+CNETSCAN) 应扫描所有附近的天线并以多行打印一些信息(根据数据表) (SIM800L) ,我得到多行这样的:

Operator:"XXXX",MCC:XXX,MNC:XX,Rxlev:XX,Cellid:XX,Arfcn:XX,Lac:XX,Bsic:XX
Operator:"XXXX",MCC:XXX,MNC:XX,Rxlev:XX,Cellid:XX,Arfcn:XX,Lac:XX,Bsic:XX
Operator:"XXXX",MCC:XXX,MNC:XX,Rxlev:XX,Cellid:XX,Arfcn:XX,Lac:XX,Bsic:XX
OK

但是我不知道当我以编程方式执行时会发生什么,它一团糟,我尝试更改波特率并更改接收方法并逐个读取字符,我确实在接收之间设置了延迟,我试图做 iffor 而不是 while 但运气不好。

我想接收每一行之间有延迟,它破坏了串行可用性,但我不知道该怎么办!任何帮助将不胜感激。

顺便说一句,我的设置函数:

void setup() {
  SIM800L.begin(9600);
  Serial.begin(9600); 
  delay(3000);

  SIM800L.print("AT+CMGF=1\r"); 
  delay(100);

  SIM800L.print("AT+CNMI=2,2,0,0,0\r");
  delay(100);
  GetRegData();

  delay(1000);
}

Ps:整个东西(Arduino+Sim800L)工作正常,没有错误,Simcard 已解锁,可以发送接收短信和电话,等等

两个提示:

  • 删除接收函数中的所有延迟(),它停止处理每个字符 10 毫秒,这可能会导致长 运行
  • 上的串行缓冲区溢出
  • 去掉 String class,读入一个足够大的字符缓冲区以获取最大的预期消息。可以在 stackexchange 上找到示例。

如果您使用双向 com,serial.available() 会很方便,但您需要自己检查结束符或其他外部信号。

通过花费数小时思考整个过程,我想出了一个主意:

在串行端口上等待 10 秒,得到它吐出的内容! NO 串口断线 NO while (SIM800L.available() != 0)

elapsedMillis 是库,这是代码:

String buffer2;

elapsedMillis timeElapsed;
unsigned int interval = 10000; 

while(timeElapsed < interval){
    if (SIM800L.available() != 0){ // for ignoring the NULLs
        char c = SIM800L.read();
        Serial.print(c);
        buffer2.concat(c);
      }
}

虽然这个过程中有一些亮点:

1-旧循环没有得到全部输出的主要原因是,SIM800L.available()在多行接收期间变为零!

2- String 数据类型或 SIM800L.read(); 不要做错任何事情,理论上它们没有读取设备输出(如 64 字节)字符的限制,它们全部读取

3- 有时电子设备的行为很奇怪 Sim800L 又旧又便宜!

4- 如果您要通过 SMS 发送此数据(网络天线扫描),请注意 SMS 最大字符限制,并考虑到服务提供商将向您收取大约每发送 150 个字符的费用!并从响应中删除 \r\n 个字符,并在 SIM800L 上发送短信之前删除 运行 AT+CSMP=17,167,0,0 否则它将发送空白短信!

5- Sim800L 数据表说它在端口 115200 上效果最好 BUT 它也是快为这个设备!将其波特率设置为 9600.

根据 OP 的回答,问题在于 serial.available() returning 0 并使循环过早结束。

这可能是因为两次连续 serial.read() 调用之间的延迟太低,并且等待一些副场景(例如在更多行中呈现的 AT 响应)是不够的。

增加延迟是错误的,因为响应是逐个字符读取的,这种更改会影响总时间。可以做的是在总 字符间延迟 后退出循环。以下示例使用了 200ms 的值:

#define MAX_DELAY_MS  200
#define LOOP_DELAY_MS 10

String GetRegData()
{
  int intercharTime = 0;

  Serial.println("Get nearby antenna info ...");
  SIM800L.print("AT+CNETSCAN=1\r");
  delay(1000);

  SIM800L.print("AT+CNETSCAN\r"); 
  delay(1000);

  String buffer2;

  while (  intercharTime < MAX_DELAY_MS  )
   {
      if( SIM800L.available() )
      {
          int c = SIM800L.read();

          /* read() return -1 on fail. Make sure it read something before using c */
          if( c != -1 )
          {
              Serial.print( (char)c );
              buffer2.concat( (char)c );

              /* Something received: reset intercharTime */
              intercharTime = 0;
          }
      }
      else
      {
          intercharTime += LOOP_DELAY_MS;
      }

      delay(LOOP_DELAY_MS);
   }

   //Serial.println();
   return buffer2;
}

变化:

    勾选
  • intercharTime退出循环。每次 serial.available() returned 0 时增加。每次接收到字符时重置。这样我们在 MAX_DELAY_MS 毫秒后退出循环。
  • read() returns 是一个整数,所以我把它放在一个整数变量上,在需要时将它转换为 char。此外它 returns -1 失败。最好在处理可能无效的数据之前检查 return 值。
  • 我还用定义替换了 10ms 延迟。这样就很容易玩几对 LOOP_DELAY_MSMAX_DELAY_MS 来找到最合适的。