1

我正在使用连接到 Arduino Uno 的 SIM900 GPS/GPRS 模块扩展板,我将如何解析我的 AT 命令的响应?或者我如何能够在发送 AT 命令后删除串行中打印的第一行

AT+CMGL="ALL"

+CMGL: 1,"REC READ","+XXXXXXXXXX","","16/04/25,15:20:59+32"
Hilp akp si ralphh the pogi one mmalit mi pizza hehehehehe

+CMGL: 2,"REC READ","+XXXXXXXXXX","","16/04/25,21:51:33+32"
Yow!!!

OK

上面输出的示例,我想摆脱AT+CMGL="ALL"然后解析剩下的数据。解析的最佳方法是什么?

4

3 回答 3

8

我将如何解析我的 AT 命令的响应?

是的,这是正确的问题。

发送 AT 命令后,如何删除串行中打印的第一行?

不,这是一个错误的问题,因为如果您关心 echo 是否打开,那么您做错了。

解析AT命令输出的正确策略如下:

  • 发送 AT 命令行(以 正确终止"\r")。
  • 读取从调制解调器接收到的一个字符和一个字符,直到您有一个完整的行终止,"\r\n"然后解析该行。
    • 如果该行等于最终结果代码,则命令行的所有输出都已完成(并且调制解调器已准备好接收新命令)。这一定是你测试的第一件事!
    • 如果运行的 AT 命令对其信息文本响应行有前缀(几乎所有都有),请检查该行是否以该前缀开头,如果是则处理该行,否则忽略它。
    • 如果运行的 AT 命令没有前缀,您可能希望打印所有内容,直到收到最终结果代码。这仅适用于像 之类的遗留命令ATI,并且对于解析这些命令,您可能会合理地关心 echo 与否。

现在对于AT+CMGL命令来说,它需要做更多的工作,因为响应被分成多行。

首先,最好的信息来源应该是制造商特定的 AT 文档,其次是标准化命令的官方 3GPP 27.005规范。AT+CMGL

文本模式下 AT+CMGL 的响应指定为

+CMGL: <index>,<stat>,<oa/da>,[<alpha>],[<scts>][,<tooa/toda>,
<length>]<CR><LF><data>[<CR><LF>
+CMGL: <index>,<stat>,<da/oa>,[<alpha>],[<scts>][,<tooa/toda>,
<length>]<CR><LF><data>[...]]

因此,在收到以“+CMGL:”开头的行之后,直到您读取空行(“\r\n”)之前的所有行都属于此。

请参阅有关一般代码结构和流程的答案,尽管如上所述,响应的多行属性需要更多处理。我会使用类似以下的东西(未经测试的代码):

enum CMGL_state {
    CMGL_NONE,
    CMGL_PREFIX,
    CMGL_DATA
};

// Extra prototype needed because of Arduino's auto-prototype generation which often breaks compilation when enums are used.
enum CMGL_state parse_CMGL(enum CMGL_state state, String line);
enum CMGL_state parse_CMGL(enum CMGL_state state, String line)
{
    if (line.equals("\r\n") {
        return CMGL_NONE;
    }
    if (line.startsWith("+CMGL: ") {
        return CMGL_PREFIX;
    }
    if (state == CMGL_PREFIX || state == CMGL_DATA) {
        return CMGL_DATA;
    }
    return CMGL_NONE;
}

...

write_to_modem("AT+CMGL=\"ALL\"\r");
CMGL_state = CMGL_NONE;
goto start;
do {
    CMGL_state = parse_CMGL(CMGL_state, line);
    switch (CMGL_state) {
    case CMGL_PREFIX:
        process_prefix(line); // or whatever you want to do with this line
        break;
    case CMGL_DATA:
        process_data(line); // or whatever you want to do with this line
        break;
    case CMGL_NONE:
    default:
        break;
    }
start:
    line = read_line_from_modem();
} while (! is_final_result_code(line))
于 2016-04-26T19:11:58.453 回答
3

第一行AT+CMGL="ALL"似乎是回声。您可以通过在函数中发送ATE0到您的模块来禁用它。setup

至于其余的数据,它们都具有相同的格式。您可以使用不同的字符串操作函数轻松编写解析器。

于 2016-04-26T12:54:58.410 回答
1

如果您正在使用,arduino我建议您使用一个好的库!你不需要处理这些东西。试试 http://www.gsmlib.org/或者你可以找到任何你喜欢的。

我将在这里举一个例子。

#include "SIM900.h"
#include <SoftwareSerial.h>
//If not used, is better to exclude the HTTP library,
//for RAM saving.
//If your sketch reboots itself proprably you have finished,
//your memory available.
//#include "inetGSM.h"

//If you want to use the Arduino functions to manage SMS, uncomment the lines below.
#include "sms.h"
SMSGSM sms;

//To change pins for Software Serial, use the two lines in GSM.cpp.

//GSM Shield for Arduino
//www.open-electronics.org
//this code is based on the example of Arduino Labs.

//Simple sketch to send and receive SMS.

int numdata;
boolean started=false;
char smsbuffer[160];
char n[20];

void setup() 
{
  //Serial connection.
  Serial.begin(9600);
  Serial.println("GSM Shield testing.");
  //Start configuration of shield with baudrate.
  //For http uses is raccomanded to use 4800 or slower.
  if (gsm.begin(2400)){
    Serial.println("\nstatus=READY");
    started=true;  
  }
  else Serial.println("\nstatus=IDLE");

  if(started){
    //Enable this two lines if you want to send an SMS.
    //if (sms.SendSMS("3471234567", "Arduino SMS"))
      //Serial.println("\nSMS sent OK");
  }

};

void loop() 
{
  if(started){
    //Read if there are messages on SIM card and print them.
    if(gsm.readSMS(smsbuffer, 160, n, 20))
    {
      Serial.println(n);
      Serial.println(smsbuffer);
    }
    delay(1000);
  }
};
于 2016-04-27T05:15:57.123 回答