Embedded 如何在微控制器上处理GSM缓冲区?

Embedded 如何在微控制器上处理GSM缓冲区?,embedded,microcontroller,gsm,at-command,Embedded,Microcontroller,Gsm,At Command,我有一个连接到PIC18F87J11的GSM模块,它们通信很好。我可以从微控制器发送AT命令并读取响应。但是,我必须知道响应中有多少个字符,这样我才能让PIC等待那么多字符。但是如果发生错误,响应长度可能会改变。处理这种情况的最佳方法是什么 例如: AT+CMGF=1 将导致以下响应 \r\nOK\r\n 所以我不得不告诉照片等6个字符。但是,如果有响应,则显示错误消息。应该是这样的 \r\nERROR\r\n 如果我已经告诉PIC只等待6个字符,那么它将弄乱其余的字符,因此它们可能会

我有一个连接到PIC18F87J11的GSM模块,它们通信很好。我可以从微控制器发送AT命令并读取响应。但是,我必须知道响应中有多少个字符,这样我才能让PIC等待那么多字符。但是如果发生错误,响应长度可能会改变。处理这种情况的最佳方法是什么

例如:

AT+CMGF=1  
将导致以下响应

\r\nOK\r\n
所以我不得不告诉照片等6个字符。但是,如果有响应,则显示错误消息。应该是这样的

\r\nERROR\r\n
如果我已经告诉PIC只等待6个字符,那么它将弄乱其余的字符,因此它们可能会在下次我告诉PIC读取新AT命令的响应时出现

自动查找行尾并处理任何错误消息的最佳方法是什么?


谢谢

让我们将问题分解为一些抽象层

最顶层是您的应用程序。应用层将响应消息作为一个整体处理,并理解消息的含义。它不应该被诸如预期接收多少字符这样的细节所困扰

下一层负责从字符流中构建消息。框架是通过标识消息的开头和结尾从流中提取消息

底层负责从端口读取单个字符

应用程序可以调用一个函数,如GetResponse(),它实现了框架层。GetResponse()可以调用GetChar(),它实现了底层。听起来你已经控制了底层,你的问题是关于框架层

将字符流框架化为消息的一个好模式是使用状态机。在您的情况下,状态机包括诸如BEGIN_DELIM、MESSAGE_BODY和END_DELIM等状态。例如,对于更复杂的串行协议,其他状态可能包括消息头和消息校验和

下面是一些非常基本的代码,让您了解如何在GetResponse()中实现状态机。您应该添加各种类型的错误检查,以防止缓冲区溢出并处理丢弃的字符等

void GetResponse(char *message_buffer)
{
  unsigned int state = BEGIN_DELIM1;
  bool is_message_complete = false;

  while(!is_message_complete)
  {
    char c = GetChar();
    switch(state)
    {
      case BEGIN_DELIM1:
        if (c = '\r')
          state = BEGIN_DELIM2;
        break;

      case BEGIN_DELIM2:
        if (c = '\n')
          state = MESSAGE_BODY:
        break;

      case MESSAGE_BODY:
        if (c = '\r')
          state = END_DELIM;
        else
          *message_buffer++ = c;
        break;

      case END_DELIM:
        if (c = '\n')
          is_message_complete = true;
        break;
    }
  }
}

让我们把这个问题分解成一些抽象层

最顶层是您的应用程序。应用层将响应消息作为一个整体处理,并理解消息的含义。它不应该被诸如预期接收多少字符这样的细节所困扰

下一层负责从字符流中构建消息。框架是通过标识消息的开头和结尾从流中提取消息

底层负责从端口读取单个字符

应用程序可以调用一个函数,如GetResponse(),它实现了框架层。GetResponse()可以调用GetChar(),它实现了底层。听起来你已经控制了底层,你的问题是关于框架层

将字符流框架化为消息的一个好模式是使用状态机。在您的情况下,状态机包括诸如BEGIN_DELIM、MESSAGE_BODY和END_DELIM等状态。例如,对于更复杂的串行协议,其他状态可能包括消息头和消息校验和

下面是一些非常基本的代码,让您了解如何在GetResponse()中实现状态机。您应该添加各种类型的错误检查,以防止缓冲区溢出并处理丢弃的字符等

void GetResponse(char *message_buffer)
{
  unsigned int state = BEGIN_DELIM1;
  bool is_message_complete = false;

  while(!is_message_complete)
  {
    char c = GetChar();
    switch(state)
    {
      case BEGIN_DELIM1:
        if (c = '\r')
          state = BEGIN_DELIM2;
        break;

      case BEGIN_DELIM2:
        if (c = '\n')
          state = MESSAGE_BODY:
        break;

      case MESSAGE_BODY:
        if (c = '\r')
          state = END_DELIM;
        else
          *message_buffer++ = c;
        break;

      case END_DELIM:
        if (c = '\n')
          is_message_complete = true;
        break;
    }
  }
}
一行 没有单一的最佳方式,只有取舍

详细地 该问题可分为两个相关的子问题

1.接收任意有限长度的消息 权衡:

  • 可用内存与实现复杂性
  • 带宽开销与实现复杂性
在最简单的情况下,可用RAM的数量不受限制。我们只是使用一个足够宽的缓冲区来容纳尽可能长的消息,并保持按字节接收消息。然后,我们必须以某种方式确定已接收到完整的消息,并且可以将其传递给进一步的处理。这本质上意味着分析接收到的数据

2.解析接收到的消息 分析数据以搜索其语法结构是按定义进行的。这就是子任务相关的地方。一般来说,解析是一个非常复杂的话题,处理它的成本很高,无论是在计算上还是在费力的感觉上。如果我们限制数据的通用性,通常可以降低成本:数据结构越简单,解析就越容易。这种限制被称为“限制”

因此,我们必须读取数据来解析它,然后解析数据来读取它。这类联锁问题一般用计算机来解决

就你的情况而言,我们必须处理这个问题。它很古老,设计以人为本。这是个坏消息,因为正确地解析它可能是一个挑战,尽管它有时看起来很简单。它有一些非常不方便的特性,比如“+++”转义计时

当你记性不足时,事情会变得更糟。在这种情况下,我们不能将解析延迟到消息的末尾,因为它甚至可能不适合可用的RAM——我们必须对其进行分块解析

…我们甚至还没有接近打开TCP连接或拨打电话!你也会遇到一些意想不到的麻烦,比如这些可怕的“未经请求的结果代码”。这件事涉及面广,足以写一整本书。请至少在这里看一下: . 维基百科披露了更多关于Hayes协议的问题,并描述了一些解决这些问题的方法