【问题标题】:How to handle GSM buffer on the Microcontroller?如何处理微控制器上的 GSM 缓冲区?
【发布时间】:2014-09-15 17:20:13
【问题描述】:

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

例如:

AT+CMGF=1  

将导致以下响应。

\r\nOK\r\n

所以我必须告诉 PIC 等待 6 个字符。但是,如果有响应是错误消息。会是这样的。

\r\nERROR\r\n

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

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

谢谢!

【问题讨论】:

  • 欢迎来到parsing!
  • @vines:如果您想稍微扩展您的评论,它希望成为一个答案。如果您确实将您的评论升级为答案,请在此处联系我,这样我就可以回到这里投票了。
  • 如何自动找到每个响应的行尾?我也进行解析,但我想知道人们是否有一种有效的方式来解析响应。如果你能一步一步地解释它会回答我的问题。
  • @Ammar 好的,我现在就做。但这需要一段时间——这个话题相当广泛:)
  • 您期望响应“AT”命令的最长响应是多少?还是可以任意长?

标签: embedded microcontroller gsm at-command


【解决方案1】:

单行

没有最好的方法,只有权衡。

详细说明

问题可以分为两个相关的子问题。

1。接收任意有限长度的消息

取舍:

  • 可用内存vs实现复杂度;
  • 带宽开销vs实现复杂度。

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

2。解析收到的消息

分析数据以查找其句法结构是parsing 的定义。这就是子任务相关的地方。一般来说,解析是一个非常复杂的话题,处理它的成本很高,无论是在计算上还是在费力的意义上。如果我们限制数据的通用性,通常可以降低成本:数据结构越简单,解析就越容易。这种限制称为“transport layer protocol”。

因此,我们必须读取数据来解析它,并解析数据来读取它。这种环环相扣的问题一般用coroutines解决。

在您的情况下,我们必须处理AT protocol。它是旧的,并且在设计上以人为本。这是个坏消息,因为尽管有时看起来很简单,但正确解析它可能具有挑战性。它有一些非常不方便的功能,例如'+++'转义时间!

当你记忆力不足时,事情会变得更糟。在这种情况下,我们不能将解析推迟到消息末尾,因为它很可能甚至不适合可用的 RAM——我们必须逐块解析它。

...而且我们甚至还没有接近打开 TCP 连接或拨打电话!你也会在那里遇到一些意想不到的麻烦,比如这些可怕的“不请自来的结果代码”。这件事足以写一整本书。请至少在这里看看: http://en.wikibooks.org/wiki/Serial_Programming/Modems_and_AT_Commands。 wikibook 揭示了 Hayes 协议的更多问题,并描述了一些解决这些问题的方法。

【讨论】:

  • 您解释得很好,很抱歉没有将您的答案标记为解决方案。我标记了另一个答案以提供一些代码,但是您的答案也非常有帮助。给你的 cmets +1。感谢您的宝贵时间!
【解决方案2】:

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

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

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

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

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

将字符流构建成消息的一个很好的模式是使用状态机。在您的情况下,状态机包括 BEGIN_DELIM、MESSAGE_BODY 和 END_DELIM 等状态。例如,对于更复杂的串行协议,其他状态可能包括 MESSAGE_HEADER 和 MESSAGE_CHECKSUM。

这里有一些非常基本的代码,让您了解如何在 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;
    }
  }
}

【讨论】:

  • 这个“状态机”,一个状态变量实际上只是选择入口点,实际上是在 C 中表达 coroutine 的一种丑陋方式,它没有对它们的内置支持。
猜你喜欢
  • 2021-11-26
  • 2012-01-21
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多