at 命令最初是 Hayes调制解调器(Modem)的命令集,因其简洁的 "AT"(Attention)前缀而得名,它已经成为一种非常通用的、用于与嵌入式设备(如MCU)进行串口通信的协议,尤其是在物联网模块、GPS模块、蓝牙模块等外设中。

(图片来源网络,侵删)
AT命令的核心思想
at 命令的核心是一种基于文本的、同步的、命令-响应的通信模式。
- 文本格式:命令和响应都是可读的ASCII字符串,便于调试和人工输入。
- 命令-响应:MCU(作为从机)等待主机(如电脑、手机)发送一条命令,执行后返回一条或多条响应。
- 同步:一条命令执行完毕并收到响应后,下一条命令才能被发送。
AT命令的基本语法
一个标准的AT命令通常遵循以下格式:
AT<Command>[=<Parameter>][<CR>]
AT或at:命令前缀,用于唤醒MCU的命令解析器,不区分大小写。<Command>:命令本身,通常是一个或两个字母,如AT+CMD。[=<Parameter>]:可选的参数,可以是数值、字符串等。[<CR>]:命令结束符,通常是回车符(\r, 十进制13)或换行符(\n, 十进制10),或者两者组合(\r\n)。这是最关键的部分,必须严格遵守模块的规范。
示例:
AT\r\n:最简单的测试命令,检查设备是否在线。AT+RESET\r\n:重启设备。AT+CWJAP="MyWiFi","12345678"\r\n:连接到指定的Wi-Fi网络。AT+CIPSEND=0,13\r\n:准备通过连接0发送13个字节的数据。
响应格式:

(图片来源网络,侵删)
- 成功响应:通常以
OK- 错误响应:通常以
ERROR- 信息响应:返回具体的数据,如
AT+GMR会返回固件版本信息。- 中间响应:在多行响应中,可能会有
+<Command>: ...这样的行,最后以OK或ERROR结束。 - 错误响应:通常以
在MCU上实现AT命令的两种主要方式
根据MCU和外设(如Wi-Fi模块)的连接方式,主要有两种实现架构。
MCU作为AT指令的“转发器” (Passthrough Mode)
这是最常见、最简单的方式,尤其适用于MCU本身处理复杂网络协议能力较弱的情况(使用一个不带Wi-Fi的MCU+一个ESP8266/ESP32模块)。
工作流程:
- 用户/主机 通过串口(如USB转串口)向 MCU 发送AT命令。
- MCU 的固件不做任何解析,直接将收到的AT命令原封不动地通过另一个硬件串口(如UART1)转发给 外设模块(如ESP8266)。
- 外设模块 执行命令,并将响应数据通过UART1发送回 MCU。
- MCU 同样不做解析,直接将响应数据原封不动地转发回给 用户/主机。
MCU固件的核心任务:

(图片来源网络,侵删)
- 初始化两个串口(UART0用于与PC通信,UART1用于与模块通信)。
- 在一个主循环中,不断检查UART0是否有数据,有则将其写入UART1的发送缓冲区。
- 不断检查UART1是否有数据,有则将其写入UART0的发送缓冲区。
- (可选)实现简单的流控,避免缓冲区溢出。
优点:
- 实现简单:MCU固件逻辑非常简单,几乎是“透明”的。
- 开发快速:不需要在MCU上实现复杂的AT协议栈,只需处理串口数据流。
- 利用成熟模块:直接使用模块厂商已经调试好的固件,稳定可靠。
缺点:
- 占用MCU资源:即使逻辑简单,串口中断和数据处理也会占用一部分CPU时间和RAM。
- 无法深度优化:MCU无法根据模块的响应做出智能决策,所有逻辑都在主机端完成。
适用场景:
- 任何需要将现有设备(如电脑、树莓派)通过串口与AT模块连接的场景。
- MCU只是作为一个“桥梁”,不关心AT命令的具体内容。
MCU作为AT指令的“解析器” (Parser Mode)
在这种架构下,MCU本身就是核心,它直接控制一个网络接口(如以太网、Wi-Fi)或者本身就是AT协议的执行者。
工作流程:
- 用户/主机 通过串口向 MCU 发送AT命令。
- MCU 的固件接收到数据后,解析出命令、参数等。
- MCU 根据解析出的命令,执行相应的内部操作(调用TCP/IP栈函数、控制GPIO、读写Flash等)。
- MCU 生成相应的响应数据(如
OK,ERROR, 或查询结果),并通过串口发送回 用户/主机。
MCU固件的核心任务:
- 串口接收中断:配置串口接收中断,当收到一个字节时,将其存入一个环形缓冲区。
- 命令解析器:在一个主循环中,检查环形缓冲区中是否有完整的命令(即是否收到了结束符
\r\n)。 - 状态机:如果发现完整命令,则启动一个状态机来解析命令字符串。
- 检查是否以
AT或at开头。 - 提取命令码(如
+CWJAP)。 - 提取参数(如
"MyWiFi"和"12345678")。
- 检查是否以
- 命令分发器:根据解析出的命令码,调用对应的处理函数(一个巨大的
if-else if或switch-case结构)。 - 响应生成器:命令处理函数执行完毕后,根据结果生成响应字符串(如
OK\r\n或ERROR\r\n)。 - 串口发送:将生成的响应字符串通过串口发送出去。
优点:
- 高度集成:所有功能都在MCU内部,无需额外模块,成本更低,PCB更简单。
- 性能更高:MCU可以直接响应,无需等待外部模块,响应延迟更低。
- 资源占用更少:不需要两个独立的串口及其相关资源。
- 灵活性强:可以自由定义和扩展AT命令集,使其完全服务于自己的应用。
缺点:
- 开发复杂:需要自己实现一个健壮的命令解析器和命令处理器。
- 调试困难:调试一个状态机和字符串解析器比转发数据要复杂得多。
- 工作量大:需要为每个支持的命令编写单独的处理函数。
适用场景:
- 自定义的网关设备。
- 需要远程控制和监控的嵌入式设备。
- MCU本身功能强大,足以处理所有任务(如使用STM32 + LwIP)。
MCU端实现AT解析器的关键步骤(代码示例)
以下是一个伪代码/简化代码示例,展示如何在MCU上实现一个简单的AT解析器。
#include <string.h>
#include <stdio.h> // 用于 sprintf
// 定义环形缓冲区
#define RX_BUFFER_SIZE 128
char rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t rx_head = 0;
volatile uint16_t rx_tail = 0;
// 串口接收中断服务函数
void USARTx_IRQHandler(void) {
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
char data = USART_ReceiveData(USART1);
rx_buffer[rx_head] = data;
rx_head = (rx_head + 1) % RX_BUFFER_SIZE;
// 防止溢出
if (rx_head == rx_tail) {
rx_tail = (rx_tail + 1) % RX_BUFFER_SIZE;
}
}
}
// 检查并处理命令
void process_at_commands() {
char *line_ptr;
char command[16];
char param1[32];
char param2[32];
// 查找完整的行 (以 \r\n
line_ptr = strstr(rx_buffer + rx_tail, "\r\n");
if (line_ptr != NULL) {
// 标记此行为已处理
uint16_t line_length = (line_ptr - (rx_buffer + rx_tail)) + 2; // +2 for \r\n
rx_tail = (rx_tail + line_length) % RX_BUFFER_SIZE;
// 去掉 \r\n,方便解析
*line_ptr = '\0';
// 解析命令
if (sscanf(rx_buffer + rx_tail, "AT%15[^=]=%31[^,],%31s", command, param1, param2) == 3) {
// 处理带两个参数的命令,如 AT+CWJAP="ssid","pass"
if (strcmp(command, "+CWJAP") == 0) {
printf("Attempting to connect to WiFi: SSID=%s, PASS=%s\r\n", param1, param2);
// 在这里调用实际的Wi-Fi连接函数
// ...
printf("OK\r\n");
}
} else if (sscanf(rx_buffer + rx_tail, "AT%15s", command) == 1) {
// 处理无参数的命令,如 AT 或 AT+GMR
if (strcmp(command, "AT") == 0) {
printf("OK\r\n");
} else if (strcmp(command, "+GMR") == 0) {
printf("Firmware Version: 1.0.0\r\n");
printf("OK\r\n");
}
} else {
// 命令格式错误
printf("ERROR\r\n");
}
}
}
int main(void) {
// ... 硬件初始化 (时钟, GPIO, 串口) ...
USART_Init(...);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_EnableIRQ(USART1_IRQn);
while (1) {
process_at_commands();
// ... 其他任务 ...
}
}
| 特性 | 转发器 | 解析器 |
|---|---|---|
| 架构 | MCU <--(串口)--> AT模块 | MCU <--(串口)--> Host |
| MCU角色 | 透明网桥,数据中转 | 协议执行器,命令处理器 |
| 开发难度 | 低 | 高 |
| 灵活性 | 低,受限于模块AT指令集 | 高,可自定义AT指令 |
| 成本/复杂度 | 较高(需外接模块) | 低(单芯片方案) |
| 性能 | 较低(有通信延迟) | 高(直接响应) |
| 适用场景 | 快速原型、利用现有模块 | 定制产品、集成度高、成本敏感型 |
对于初学者或快速项目,方式一(转发器) 是最佳选择,对于追求高性能、低成本和高度定制化的产品,则需要投入精力实现方式二(解析器)。
