【问题标题】:How to read GSM AT command response on arduino Serial port for long response?如何在 arduino 串行端口上读取 GSM AT 命令响应以获得长响应?
【发布时间】:2020-04-08 14:33:17
【问题描述】:

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

    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

但是我不知道当我以编程方式执行它时会发生什么,它搞砸了,我试图改变波特率并改变接收方法并逐个读取字符,我确实在接收之间设置了延迟,我试图做@ 987654325@ 或 for 而不是 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已解锁,可以发送接收短信和电话等。

【问题讨论】:

  • 所以您在抱怨第一行的“LAC”字段中的响应似乎已损坏?
  • @RobertoCaboni 是的,看起来,在 LAC 字段附近发生了一些不好的事情,其余的行没有打印或保存在变量中。
  • Operator:"XXXX",MCC:XXX,MNC:XX,Rxlev:XX,Cellid:XX,Arfcn:XX,Lac:... 中的“X”是否替代了 1vs1 的实际字符?响应中的第一个意外字符是什么?该消息是由Serial.print(c); 还是由另一个外部调用打印缓冲区2 打印的?
  • 我注意到大约 64 个字符后的输出很奇怪。 PS:serial.read() 返回一个 int 类型变量(错误时为 -1,所以你应该检查它的返回值)
  • @RobertoCaboni 的输出类似于 ::Operator:"405803",MCC:405,MNC:803,Rxlev:62,Cellid:51A5,Arfcn:702 和串行打印什么都没有。

标签: arduino serial-port gsm at-command sim800l


【解决方案1】:

两个提示:

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

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

【讨论】:

  • 我确实消除了读取延迟,我尝试逐个字符地读取字符,但没有运气!
【解决方案2】:

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

在串口上停留 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 上工作得最好 但是 这个设备太快了!将其波特率设置为 9600

【讨论】:

  • 好的,所以您没有等待足够的时间来阅读所有回复。您发现的只是一种解决方法。你需要的是找到正确的延迟和阅读策略。由于您只等待 10 毫秒的延迟,因此在第一个 serial.available() == 0 之后返回可能太快了。您可能应该做的是等到至少 200 毫秒没有输入字符。
  • 谈论波特率:115200 是自 2000 年以来调制解调器的默认速度。问题可能出在 Arduino 方面(从更快的串行接收更困难,并且还有硬件后果,因为电流消耗更大)。
  • 最后在附加的代码中不清楚timeElapsed是如何在循环中更新的。
【解决方案3】:

根据 OP 的回答,问题在于 serial.available() 返回 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() 返回 0 时都会增加。每次接收到字符时都会重置。这样我们在MAX_DELAY_MS毫秒后退出循环。
  • read() 返回一个整数,所以我将它放在一个整数变量上,并在需要时将其转换为 char。此外,它在失败时返回 -1。在处理可能无效的数据之前,最好先检查返回值。
  • 我还用定义替换了10ms 延迟。这样就可以轻松地与几对 LOOP_DELAY_MSMAX_DELAY_MS 一起玩,以找到最合适的人选。

【讨论】:

    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多