从最早的GSM模块,到后来的WiFi、蓝牙、LoRa、NB-IoT,几乎所有外接通信模块,都绕不开AT指令。很多新手刚接触的时候觉得AT指令很简单,不就是发字符串收返回嘛,但真正用起来坑一点都不少。今天就系统地聊一聊AT指令,从它的来龙去脉、指令结构,到优缺点和实际调试经验。也是因为最近参加了瑞萨的“无线连接”WIFI和BLE模块测评,也用得上。
一、AT指令到底是什么?从哪来的?
AT指令,全称Attention Commands,直译就是"注意指令"。它不是某家公司随便定义的一套协议,而是有年头的标准了。
最早AT指令是贺氏(Hayes)公司在1981年为Smartmodem 300调制解调器设计的控制指令集,因为所有指令都以"AT"开头(Attention的缩写,用来唤醒调制解调器),所以得名AT指令。当年用电话线拨号上网的年代,所有Modem都兼容这套指令,相当于行业事实标准。
后来蜂窝通信起来了,GSM模块继承并扩展了这套指令集,也就是我们常说的GSM 07.05、07.07标准,定义了短信、通话、网络注册等一整套AT指令。再往后,WiFi模块、蓝牙模块、NB-IoT、4G Cat.1模块,几乎所有串口控制的通信模组,全都沿用了AT指令的框架,只是各家在标准基础上做了自己的扩展。
可以说,AT指令就是嵌入式外接通信模块的"通用语言",你学会了一套,换不同厂家的模块,上手成本会低很多。
AT指令的核心定位它本质上是一种主机-从机架构的串口文本控制协议:
- 主机:我们的MCU(STM32、GD32、ESP这些)
- 从机:通信模块(WiFi/蓝牙/4G等)
- 物理层:基本都是UART串口,少数用SPI或USB虚拟串口
- 交互方式:主机发一行文本指令,模块解析后返回文本结果
下面这张图是典型的AT指令系统架构:
二、AT指令的标准结构,一次讲明白
很多人觉得AT指令就是随便发字符串,其实它有非常规范的结构,理解了结构,看任何模块的AT手册都能快速上手。
1. 基础格式
一条标准的AT指令,结构非常固定:
拆解一下:
- AT前缀:所有指令必须以AT开头,不区分大小写(at、At、aT都可以),作用是让模块识别到指令起始
- 指令关键字:比如CWJAP(连接WiFi)、CFUN(功能模式)、NMGS(发短信)
- 等号与参数:设置类指令用=跟参数,多个参数用逗号分隔
- 结束符:必须以回车符\r(ASCII 0x0D)结尾,这是很多新手踩的第一个坑——只发字符串不发回车,模块根本不响应
2. 四种指令类型
同一条指令,通常有四种使用形式,这是AT指令最精髓的设计:
这个设计非常经典,一条指令名,四种用法,覆盖了查询、设置、测试、执行四种场景。
3. 返回结果格式
模块返回的内容同样有规范,一般分为三部分:
- 回显(Echo):默认开启,模块会把收到的指令原封不动发回来,方便调试
- 响应内容:查询指令返回具体数据,设置指令可能返回中间状态
- 最终状态码:OK 表示成功,ERROR 表示失败,有的模块还会返回错误码
典型的成功交互时序:
举个最常见的例子,查询WiFi模块是否连接成功:
- 主机发送:AT+CWJAP?<CR>
- 模块返回:
- +CWJAP:"MyWiFi","11:22:33:44:55:66",6,-55
- OK
失败的情况:
- 主机发送:AT+CWJAP="不存在的WiFi","12345678"<CR>
- 模块返回:
- +CWJAP:1
- ERROR
三、AT指令到底用来干嘛?典型应用场景盘点
别看AT指令简单,能做的事情非常多,几乎所有模块的控制都靠它。我梳理了最常用的几大类:
1. 基础控制类- 模块复位:AT+RST
- 恢复出厂:AT+RESTORE
- 功能模式:AT+CFUN(飞行模式、全功能、最小功耗等)
- 固件版本查询:AT+GMR
- 串口参数配置:波特率、校验位、停止位
2. 网络连接类
这是用得最多的,不同模块指令不同,但逻辑一致:
- WiFi模块:扫描热点、连接AP、设置静态IP、DHCP配置
- 4G/NB模块:SIM卡检测、网络注册、运营商查询、PDP激活
- 蓝牙模块:扫描设备、配对、连接、断开、设置广播名
3. 数据传输类- TCP/UDP连接建立、数据收发
- MQTT连接、订阅、发布
- HTTP/HTTPS请求
- 短信收发、彩信(蜂窝模块)
4. 功能配置类- 低功耗模式配置、休眠唤醒参数
- GPIO控制、ADC读取
- 固件升级(OTA)
- 证书烧录、加密参数配置
四、AT指令的优缺点,客观聊聊
用了这么多年AT指令,它能活到今天肯定有不可替代的优势,但缺点也同样明显。客观总结一下:
优点- 简单易懂,调试方便纯文本协议,人能直接看懂,拿个串口助手就能调试,不用抓包工具,出问题肉眼就能排查。这是它最大的优势,开发门槛极低。
- 通用性极强从30年前的Modem到今天的WiFi 6模块,都在用AT指令框架。学会一款,换其他模块上手极快,很多指令名甚至都是一样的。
- 实现成本低对模块厂商来说,解析文本指令比实现复杂二进制协议简单太多;对主机端来说,串口发字符串更是基础操作,双方开发成本都低。
- 兼容性好不同厂家的模块,核心指令基本兼容,比如AT、AT+GMR、AT+RST这些通用指令,几乎所有模块都支持。
- 可扩展性强厂商可以随意加自定义指令,只要在AT+后面加自己的关键字就行,不影响标准指令的使用。
缺点- 效率低,浪费带宽纯文本传输,大量冗余字符。比如发个1字节的数据,要包一层AT指令头和返回,实际有效载荷占比很低。高速大数据量传输场景很吃亏。
- 解析麻烦,边界难处理文本协议解析起来其实比二进制费脑子,要处理换行、回车、不定长返回、主动上报(URC)混在响应里的情况。新手写的AT解析程序,经常出现数据错位、丢包、解析失败。
- 没有统一标准,各家乱扩展基础指令有标准,但高级功能全是厂商自定义。同样是MQTT连接,乐鑫、移远、合宙的指令格式完全不一样,没有通用性可言。
- 不适合高可靠场景没有校验机制(默认串口也不加校验),传输出错了很难发现;没有序号和重传机制,指令发出去有没有执行全靠返回的OK/ERROR判断,复杂场景容易时序错乱。
- 主动上报(URC)处理麻烦模块会主动上报一些事件,比如WiFi断开、收到短信、TCP连接断开。这些上报随时可能插在正常指令的返回中间,解析程序如果没处理好,很容易把上报当成指令返回,导致逻辑错乱。
五、实际开发中的AT指令交互模式
做产品开发,AT指令不是简单的发一条等一条,通常有两种成熟的交互模式:
模式一:同步查询式(最简单,新手推荐)主机发一条指令,阻塞等待返回OK或ERROR,处理完再发下一条。
- 优点:逻辑简单,不容易乱序
- 缺点:阻塞CPU,等待期间干不了别的,响应慢
模式二:状态机+队列(量产产品常用)用环形队列缓存待发送的指令,状态机逐个发送,非阻塞运行,同时单独处理主动上报(URC)。
- 优点:不阻塞主循环,实时性好,能处理复杂的多指令时序
- 缺点:代码复杂度高,状态机写不好容易出bug
这里给大家一个经验:简单功能、指令不多的场景,直接同步阻塞就行,简单可靠;指令多、有实时性要求的,一定要上状态机+队列,别硬写阻塞延时。
六、踩过的那些坑,都是经验
这些年调过的AT模块没有二十种也有十几种,踩过的坑数不胜数,分享几个最常见的,大家可以避避坑:
坑1:回显开关没处理好很多模块默认开启命令回显,你发什么它先原封不动返回一遍。新手写解析程序经常把回显当成返回数据,怎么解析都不对。
- 解决:要么初始化时用ATE0关掉回显,要么解析的时候跳过第一行回显。
坑2:回车换行不统一标准AT指令只要求\r结尾,但很多模块返回的时候是\r\n换行,有的甚至只有\r。还有人写代码顺手发成\r\n,大部分模块能识别,但个别严格的模块就不响应。
- 解决:发送严格只用\r结尾,接收时把\r和\n都当成分隔符,兼容处理。
坑3:主动上报插在响应中间比如你刚发了查询指令,正好模块触发了WiFi断开的URC,返回就变成了:
很多程序只判断有没有OK,没管中间插了URC,就会误以为查询成功,拿到错误数据。
- 解决:解析器要能区分"指令响应"和"主动上报",URC单独回调处理,不要和指令返回混在一起。
坑4:指令发太快,模块忙不过来有的新手连续发指令,中间一点延时都不加,模块还在处理上一条,下一条就来了,直接丢包。
- 解决:每条指令之间留至少10~20ms间隔,或者严格等上一条返回OK再发下一条。
坑5:错误只看ERROR,不看错误码很多指令失败会返回具体错误码,比如+CME ERROR: 10,不同错误码对应不同原因,对排查问题帮助极大。别一看到ERROR就复位,先看看错误码是什么。
七、常见模块AT指令风格对比做了这么多年,不同厂家的AT指令风格差异还挺大的,简单对比一下:
八、最后说几句
AT指令这东西,说简单也简单,串口发字符串谁都会;说复杂也复杂,要写一个稳定可靠、能处理各种异常情况的AT解析框架,没几个项目的积累真写不好。
它不是什么高大上的技术,但却是嵌入式工程师的基本功。做物联网、做外接通信模块,几乎天天都要打交道。把AT指令的原理、结构、常见坑摸透了,调任何新模块都能事半功倍。
大家平时调AT指令都遇到过什么奇葩坑?欢迎在评论区聊聊,一起避坑。
补充说明:帖子里提到的几张示意图,分别是系统架构图、交互时序图,方便大家直观理解。实际调试的时候,建议备一个USB转串口模块,直接用串口助手手动敲AT指令测试,先把模块流程调通了再写代码,效率会高很多。
后续我也会对瑞萨 DA14531 Bluetooth LE模块 和 DA16200超低功耗Wi-Fi模块 进行AT指令的实际调试。
|