10

我一直在开发一个应用程序,它使用 GSM 调制解调器来做两件事之一;通过向服务器发送 GET 请求或向服务器发送数据(使用 UDP),使用内置 HTTP 堆栈检查其状态。我已经尝试了几种不同的方法来尽可能地保持它的可靠性,我终于准备好寻求帮助了。

我的应用程序是为 SIMCOM908 模块和 PIC18 平台编写的(我使用 PIC18 Explorer 进行开发)。

所以问题有时是调制解调器忙于做某事,并错过了一个命令。作为人类,我会看到并重新发送命令。为我的 MCU 添加超时和重新发送功能不是问题。

问题是调制解调器在不同事件之后发送未经请求的响应。当调制解调器更改注册状态(与手机信号塔)时,它会+CGREG: 1, ...在 GPS 就绪时或当 GPS 就绪时做出响应GPS Ready。这些响应可以随时发生,包括在命令中间(如创建 IP 连接)。

这是一个问题,因为我还没有想到解决这个问题的方法。我的应用程序需要发送一个命令(例如连接到服务器,AT+CIPSTART="UDP","example.com",5000)此命令将响应“OK”,然后当命令完成时“CONNECT OK”。但是,我需要能够对许多其他可能的响应做出反应,而我还没有找到一种方法来做到这一点。我需要用我的代码做什么;等待调制解调器的响应,检查响应,根据该响应执行操作?

我的代码有限(作为一个 8 位微控制器!)并且希望将重复保持在最低限度。如何编写一个响应函数,从 GSM 模块(请求或现在)获取响应,然后让我的程序的其余部分知道发生了什么?

理想情况下,我想对这些响应做点什么。就像保持内部状态(当我听到时GPS Ready,我知道我可以为 GPS 等供电。

也许我应该考虑一些事情,或者也许有一个开源项目已经解决了这个问题?

这是我到目前为止所拥有的:

/* Command responses */
enum {
    // Common
    OK = 0,
    ERROR,
    TIMEOUT,
    OTHER,
    // CGREG
    NOT_REGISTERED,
    // CGATT
    NOT_ATTACHED,
    // Network Status
    NO_NETWORK,
    // GPRS status
    NO_ADDRESS,
    // HTTP ACTION
    NETWORK_ERROR,
    // IP Stack State
    IP_INITIAL,
    IP_STATUS,
    IP_CONFIG,
    UDP_CLOSING,
    UDP_CLOSED,
    UDP_CONNECTING
} gsmResponse;

int gsm_sendCommand(const char * cmd) {
    unsigned long timeout = timer_getCurrentTime() + 5000;

    uart_clearb(GSM_UART); // Clear the input buffer
    uart_puts(GSM_UART, cmd); // Send the command to the module
    while (strstr(bf2, "\r") == NULL) { // Keep waiting for a response from the module
        if (timeout < timer_getCurrentTime()) { // Check we haven't timed out yet
            printf("Command timed out: %s\r\n", cmd);
            return TIMEOUT;
        }
    }
    timer_delay(100); // Let the rest of the response be received.

    return OK;
}

int gsm_simpleCommand(const char * cmd) {
    if (gsm_sendCommand(cmd) == TIMEOUT)
        return TIMEOUT;

    // Getting an ERROR response is quick, so if there is a response, this will be there
    if (strstr(bf2, "ERROR") != NULL)
        return ERROR;

    // Sometimes the OK (meaning the command ran) can take a while
    // As long as there wasn't an error, we can wait for the OK
    while (strstr(bf2, "OK") == NULL);
    return OK;
}

简单命令是专门寻找OKERROR响应的任何 AT 命令。类似的东西AT。但是,我也将它用于更高级的命令,例如AT+CPIN?因为这意味着我将捕获整个响应,并且可以进一步搜索+CPIN: READY. 然而,这些都不是对主动回应的回应。实际上,gsm_sendCommand()当收到主动响应时,该函数会提前返回。

管理这种复杂的、偶尔不请自来的状态消息的好方法是什么?请注意,此应用程序是用 C 语言编写的,并且在 8 位微控制器上运行!

4

1 回答 1

3

必须在同一数据流中同时处理未经请求的消息以及对请求的响应是很困难的,因为您需要对传入流进行多路分解并将结果分派给适当的处理程序。它有点像中断处理程序,因为您必须放弃您正在做的事情并处理您不一定期望的其他信息。

一些模块有一个辅助串行端口,也可用于消息。如果这是可能的,您可能只会在一个串行端口上出现未经请求的消息,而主端口用于您的 AT 命令。这可能是不可能的,并且一些 GSM 模块将不支持辅助端口上的完整命令集。

也许更好的方法是禁用未经请求的消息。大多数命令要请求的所有状态。例如,在等待注册时,无需等待主动注册消息出现,只需轮询模块以了解当前注册状态。这使您始终处于控制之中,您只需处理刚刚发送的命令的响应。如果您正在等待多个事件,您可以在循环中轮询每个项目。这通常会使代码更简单,因为您一次只需要处理一个响应。缺点是您的响应时间受投票率的限制。

如果您打算继续使用未经请求的消息方法,我建议为未经请求的消息实施一个小队列。在等待对命令的响应时,如果响应与命令不匹配,只需将响应推送到队列中。然后,当您收到对 AT 命令的响应或超时时,您可以在之后处理未经请求的消息队列。

于 2013-02-03T11:56:16.403 回答