如何在 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", &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 字符都必须是大写或小写(例如ATZ
、ATz
、atZ
或atz
都是有效的,但例如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 的传入字符串?的主要内容,如果未能解决你的问题,请参考以下文章