如何在 C 中创建 AT 命令解析器以获取来自 USART1 的传入字符串?

Posted

技术标签:

【中文标题】如何在 C 中创建 AT 命令解析器以获取来自 USART1 的传入字符串?【英文标题】:How to create AT Commands Parser in C to get the incoming string from USART1? 【发布时间】:2014-09-14 04:31:31 【问题描述】:

我想从 STM32VLDiscovery (STM32F100X4) 的 USART1 中获取字符串,并根据从 USART1 接收到的字符串编写一个 AT 命令解析器。

以下是我提出的概念,但我不确定它是否正确。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dosomethinga.h"

void dosomethingB();
void GET_AT_COMMAND(char*);
void takecommand(char *, char *);
int quit;


int main()
   char buff[15];
    char command = '\0';
    quit = 0;

    while(!quit)
    
        printf("Enter your command: ");
        scanf("%s", &buff);

        if (buff[0] == 'A' && buff[1] == 'T' && buff[2] == '+')
        
            GET_AT_COMMAND(buff);
        

    


void dosomethingB()

    printf("dosomethingB called \n");


void GET_AT_COMMAND(char *text)

    int command;
    char temp[10] = "";

    /*if(text[3] == 'A')
          command = 1;

    else if(text[3] == 'B')
        command = 2;

    else if(text[3] == 'Z')
        command = 3;
    */

    takecommand(text,temp);

    if (strcmp(temp, "CALLA") == 0)
        command = 1;

    if (strcmp(temp, "CALLB") == 0)
        command = 2;

    if (strcmp(temp, "Z") == 0)
        command = 3;

    switch(command)
    
        case 1:
            dosomethingA();
            break;

        case 2:
            printf("herehere.... \n");
            dosomethingB();
            break;

        case 3:
            printf("Exiting program.... \n");
            quit = 1;
            break;


        default:
            printf("Nothing to do here \n");
     


void takecommand(char *mycmd, char *hold)

    int i;
    for(i = 0; i < 10 ; i++)
    
         hold[i] = mycmd[i+3];
    

谁能解释我应该执行的步骤?谢谢。

【问题讨论】:

我对 AT 命令一无所知,但我敢打赌,您可以通过将 case 语句的 case 块移动到命名函数并调用它们来减少一些代码行在if-else 块中。 if(strcmp(temp, "CALLA") == 0) dosomenthingA(); else if(...) dosomethingB(); .... 也许更适合代码审查?你有一个错误:scanf("%s", &amp;buff) buff 是一个数组,可以直接使用,你应该关心输入长度:scanf("%.14s", buff)takecommand 包含一个 magic 10 ;如果您必须更改命令的大小,则必须在许多地方进行修复。 strncpy 或 memcpy 已经完成了。 (仅初见分析...) 【参考方案1】:

基本上,您应该等待输入中的注意“AT”并忽略它之前的任何内容。 例如,输入“XYZATZ\r”和“AaatZ\r”都应作为“ATZ”命令处理。 在“A”和“T”(以及所有其他命令字符)之间也可以有短暂的停顿,因为人类可能会键入这些命令。

默认情况下,所有命令都以“\r”字符结尾。

从 ITU-T 文档中了解更多关于 AT 命令的信息。例如来自V.250 标准。

可能有许多替代方法来实现它。最佳选择取决于您的需求。如果你要实现移动终端的所有AT命令,那么你应该花更多的时间在解析器上。如果您想为几个命令制作一些测试应用程序,那么您的实现可以像您提供的那样简单。

【讨论】:

请注意,A + T 字符都必须是大写或小写(例如ATZATzatZatz 都是有效的,但例如AtZ不是)。【参考方案2】:

我开发了这个AT命令解析器,可以参考一下。

当你从 UART1 获取数据时,只需调用这个方法at_wait_msg() 来解析 AT 消息

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

static const char *AT_HEADER = "AT";
static const char *AT_DEVICE_PROFILE = "DR";
static const char *AT_SET_DEVICE = "SD";

static const char AT_EOF = '\r';

typedef enum 
    DeviceProfile,
    SetDevice,
    Error
 AT_Msg_Type;

typedef struct 
    char header[3];
    char command[3];
    char data[128];
 AT_Msg_Data;

static void at_wait_msg(char text);
static void at_wait_msg_complete(char *text);
static void at_parse_msg(AT_Msg_Data *data);
static AT_Msg_Type at_check_format(AT_Msg_Data *data);

static char _rx_data[512];
static uint16_t _rx_index = 0;

int main()

    //example data getting from UART1
    char text[] = "ATDR\rATSD123456abchelloworld\r1123ATssa\r";

    for (int i = 0; i < strlen(text) + 1; i++) 
        //to simulate getting data from UART1 byte per byte
        at_wait_msg(text[i]);
    

    return 0;


static void at_wait_msg(char text)

    _rx_data[_rx_index++] = text;

    if (text == AT_EOF) 
        at_wait_msg_complete(_rx_data);

        _rx_index = 0;      
    


static void at_wait_msg_complete(char *text)

    AT_Msg_Data data;

    int result = sscanf_s(_rx_data, "%2s%2s%s\r",
        data.header, sizeof(data.header),
        data.command, sizeof(data.command),
        data.data, sizeof(data.data));

    if (result >= 2) 
        at_parse_msg(&data);
    


static void at_parse_msg(AT_Msg_Data *data)

    AT_Msg_Type type = at_check_format(data);

    switch (type) 
    case DeviceProfile:
        printf("device profile\r\n");
        break;
    case SetDevice:
        printf("settings %s\r\n", data->data);
        break;
    case Error:
    default:
        printf("Error\r\n");
        break;
    


static AT_Msg_Type at_check_format(AT_Msg_Data *data)

    if (strcmp(data->header, AT_HEADER) != 0) 
        return Error;
    

    if (strcmp(data->command, AT_DEVICE_PROFILE) == 0) 
        return DeviceProfile;
    

    if (strcmp(data->command, AT_SET_DEVICE) == 0) 
        return SetDevice;
    

    return Error;

【讨论】:

以上是关于如何在 C 中创建 AT 命令解析器以获取来自 USART1 的传入字符串?的主要内容,如果未能解决你的问题,请参考以下文章

仅获取今天在 laravel 中创建的记录

如何在C#中创建JSON字符串

如何在Windows系统中创建并使用Git仓库

为 CSV 文件制作解析器以获取大量数据

如何在数据来自 API 的颤动中创建下拉列表?

java中创建一个String 问题