批量AT指令发送接收返回和处理
在嵌入式开发中,与通信模块(如蓝牙、ESP8266、4G模块、NB-IoT模块等)交互通常采用AT指令集。为了提高代码的可维护性和复用性,我们需要构建一个既能处理单条指令,又能方便地进行批量指令发送的框架。本方案采用“结构体数组定义+通用发送函数+中断接收(也可以用轮询)”的模式,实现高效、稳定的AT指令交互。为了实现批量处理和统一管理,我们首先定义AT指令的存储结构和接收缓冲区(串口中断的接收缓
·
在嵌入式开发中,与通信模块(如蓝牙、ESP8266、4G模块、NB-IoT模块等)交互通常采用AT指令集。为了提高代码的可维护性和复用性,我们需要构建一个既能处理单条指令,又能方便地进行批量指令发送的框架。本方案采用“结构体数组定义+通用发送函数+中断接收(也可以用轮询)”的模式,实现高效、稳定的AT指令交互。
为了实现批量处理和统一管理,我们首先定义AT指令的存储结构和接收缓冲区(串口中断的接收缓冲区)。使用结构体可以将指令字符串、期望的响应关键字以及超时时间封装在一起,便于索引。
- 指令信息结构体:用于存储AT指令表。包含指令本身(如
AT\r\n)、预期的成功响应(如OK)以及建议的等待时间。 - 接收缓冲区结构体:用于在中断中暂存串口接收到的数据。采用双缓冲机制,
Receive_Buffer用于中断实时接收,AT_Buffer用于主程序处理,防止数据竞争。 - 指令枚举:定义指令的索引,方便在代码中通过名称调用,避免硬编码数字。
/*指令结构体*/
typedef struct
{
const char *cmd; //AT指令
const char *response; //AT指令的响应
int delay_ms; //AT指令的等待时间
} at_cmd_info;
/*指令集*/
const at_cmd_info AT_CMD[]={
"AT\r\n", "OK\r\n", 1000,
"AT+RESET\r\n", "OK\r\n", 1000,
"AT+MAX\r\n", "OK\r\n", 1000
};
/*指令枚举*/
typedef enum __enumAT_CMD
{
AT_CMD_AT=0,
AT_CMD_RESET,
AT_CMD_MAX
} enumAT_CMD;
/* 接收返回的数据(DMA+中断/轮询/中断),并比对是否是自己想要的返回值*/
typedef struct
{
char buffer[100]; //接收缓冲区
int length; //接收数据长度
int rev_flag; //接收完成标志
} reve_info;
reve_info Receive_Buffer; //全局变量,接收数据的缓冲区,示例,明白这是串口中断接收缓冲区就可以
reve_info AT_Buffer; //全局变量,如果需要进一步对返回的指令进行分析,将串口缓冲区的数据复制到AT_Buffer
通用发送与接收函数
这是整个框架的核心。该函数负责清空旧数据、发送新指令、并在超时范围内轮询检查接收缓冲区。一旦在缓冲区中发现预期的响应字符串,即判定为成功,并将数据拷贝至处理缓冲区。
关键设计点:
- 防干扰:函数入口处必须使用
memset清空接收缓冲区,防止上一条指令的残留数据导致误判。 - 安全性:数据拷贝时使用
strncpy而非strcpy,并手动添加\0,防止缓冲区溢出。 - 时间片:循环中使用
HAL_Delay(1),既保证了超时计时的准确性,又让出了CPU时间片给中断服务程序去搬运数据。
处理策略:/* 发送AT指令并接收返回数据 */ int AT_Send_Reve_Delay(uint8_t *cmd ,uint8_t *regsponse, uint32_t delay_ms) { memset(Receive_Buffer.buffer, 0, sizeof(Receive_Buffer.buffer)); Receive_Buffer.length = 0; /*发送函数:串口,AT指令,指令长度,超时时间(和AT指令的等待时间不同),根据发送函数不同,可以删除串口和超时时间,只保留发送指令和指令长度 */ HAL_UART_Transmit(&huart2, cmd, strlen((const char*)cmd), 100); int timeout = delay_ms; //根据实际情况调整超时时间的单位 while (timeout--) { if (strstr(Receive_Buffer.buffer, regsponse) != NULL) { //将接收到的数据复制到AT_Buffer中,如果你需要对数据进行进一步处理,可以在这里复制接收缓冲区数据,如果不用进一步处理,可以删除此段代码,直接返回1 strncpy(AT_Buffer.buffer, Receive_Buffer.buffer,sizeof(AT_Buffer.buffer)-1); AT_Buffer.buffer[sizeof(AT_Buffer.buffer) - 1] = '\0'; return 1; //接收到正确的响应,退出循环 } HAL_Delay(1); //根据实际情况调整延迟时间的单位1ms } return 0; //超时,未接收到正确的响应 }
单条处理:适用于需要严格顺序或根据上一条结果决定下一条指令的场景。
批量循环:适用于初始化配置,通过for循环遍历AT_CMD数组。int main (void) { int ret=AT_Send_Reve_Delay(AT_CMD[AT_CMD_AT].cmd, AT_CMD[AT_CMD_AT].response, AT_CMD[AT_CMD_AT].delay_ms); if (ret)//命令成功 { printf("Received response: %s\n", AT_Buffer.buffer); }else //命令失败 { printf("Command failed\n"); } while(1) { } }
更多推荐
所有评论(0)