4、AT指令集详解:基础AT指令、3GPP标准指令、TCP/IP协议栈指令、MQTT/HTTP扩展指令、自定义指令开发

AT指令,说白了就是咱们工程师和模组对话的「通用语言」。不管你用哪个厂家的模组,只要它支持AT,你就能用一串简单的字符串让它干活——连网、发数据、读状态。

我刚开始做蜂窝项目时,总觉得AT指令太简单,不就是发个字符串嘛。直到有一次,一个设备在产线上死活连不上服务器,查了三天才发现是AT指令的换行符没对齐。嗯,从那以后我再也不敢小看这些「小字符」了。

核心认知:AT指令集是模组与主控MCU之间的「通信协议」。你发一条指令,模组回一条响应。就这么简单,但细节决定成败。

AT指令集知识体系 AT指令集 基础AT指令 3GPP标准指令 TCP/IP协议栈 MQTT/HTTP扩展 自定义指令开发 AT / AT+CPIN AT+CSQ AT+CREG AT+CGATT AT+QIOPEN AT+QISEND AT+QMTCONN AT+QHTTPURL AT+<自定义> AT+<私有协议> 💡 实战建议 基础AT → 3GPP标准 → TCP/IP → MQTT/HTTP → 自定义 按这个顺序学习,从「能通信」到「会通信」再到「精通通信」

4.1 基础AT指令——模组的「开机自检」

基础AT指令是所有模组都支持的「最小指令集」。说白了,就是用来确认模组活着没、SIM卡插了没、信号好不好。

我个人习惯,拿到一个新模组,第一件事就是发一条 AT。如果它回 OK,说明串口通了,模组在跑。如果没反应——先检查波特率,再检查电平匹配。我曾经被一个3.3V和1.8V的电平不匹配坑过,串口线焊对了,但电平不对,模组就是不搭理你。

指令 功能 典型响应 说明
AT 测试连接 OK 模组活着,串口正常
AT+CPIN? 查询SIM卡状态 +CPIN: READY SIM卡已就绪
AT+CSQ 查询信号强度 +CSQ: 20,99 20对应约-75dBm,还行
AT+CGMI 查询模组厂商 Quectel 确认模组型号
AT+CGMR 查询固件版本 Revision: BG96MAR02A08M2G 用于版本管理

我的小技巧:在产线测试时,我会写一个「三连测」脚本:先发 AT 确认模组活着,再发 AT+CPIN? 确认SIM卡,最后发 AT+CSQ 看信号。三个都过,基本可以放行。这个流程我用了好几年,省了不少返工。

4.2 3GPP标准指令——和基站「握手」

3GPP标准指令是蜂窝通信的「国际通用语」。不管你是用2G、4G还是NB-IoT,这些指令的格式和含义都是统一的。你想想看,如果每个厂家的模组都用不同的指令去注册网络,那工程师不得疯掉?

我遇到过最典型的问题:设备在实验室跑得好好的,一到现场就连不上网。查了半天,发现是 AT+CREG? 返回的是 0,2——模组正在搜索网络,但一直搜不到。后来发现是天线没拧紧。嗯,这种低级错误,谁还没犯过呢?

指令 功能 典型响应 避坑点
AT+CREG? 查询网络注册状态 +CREG: 0,1 1表示已注册,2表示搜索中
AT+CGATT? 查询GPRS附着状态 +CGATT: 1 1表示已附着,0表示未附着
AT+CGPADDR 查询IP地址 +CGPADDR:1,10.168.1.100 拿到IP才能走TCP/IP
AT+COPS? 查询当前运营商 +COPS: 0,0,"CHINA MOBILE" 确认是否连对了运营商

⚠️ 重要提醒:很多新手会忽略 AT+CGATT? 的返回值。模组注册了网络(CREG=1),不代表它已经附着到GPRS(CGATT=1)。这两个状态必须都OK,才能进行数据传输。我曾经见过一个项目,CREG一直为1,但CGATT始终为0,结果设备「在线但发不了数据」——这种问题最难排查。

4.3 TCP/IP协议栈指令——让数据「跑起来」

基础指令和3GPP指令搞定了,模组已经连上网络了。但怎么把数据发出去?这就需要TCP/IP协议栈指令了。说白了,就是让模组帮你完成Socket连接、数据收发这些脏活累活。

我个人习惯用移远模组的 AT+QIOPEN 系列指令。不同厂家的指令格式略有差异,但逻辑是一样的:先建连接,再发数据,最后关连接。

// TCP客户端连接示例(移远模组)
AT+QIOPEN="TCP","192.168.1.100",8080
// 响应:CONNECT OK

// 发送数据
AT+QISEND=0
> Hello, this is my IoT device!
// 响应:SEND OK

// 接收数据(URC上报)
+QIURC: "recv",0,5
// 表示从连接0收到5字节数据

// 关闭连接
AT+QICLOSE=0
// 响应:CLOSE OK

避坑指南:我曾经在发送数据时,忘了在数据末尾加换行符。模组一直等,超时后才返回 SEND FAIL。后来我养成了习惯:发完数据后,一定用 0x1A(Ctrl+Z)结束。嗯,这个坑踩过一次就够了。

4.4 MQTT/HTTP扩展指令——上云「快车道」

TCP/IP是底层,MQTT和HTTP是上层协议。现在做物联网,大部分场景都是直接上MQTT或HTTP。模组厂商也聪明,直接把协议栈集成到固件里,你发几条AT指令就能完成连接、订阅、发布。

我最近做的一个智慧农业项目,就是用MQTT AT指令直接连阿里云。整个过程不到20行AT指令,比用MCU自己跑MQTT库省了至少一半的代码量。

// MQTT连接示例(移远模组)
AT+QMTCFG="aliauth",0,"productKey","deviceName","deviceSecret"
// 配置阿里云三元组

AT+QMTOPEN=0,"iot-as-mqtt.cn-shanghai.aliyuncs.com",1883
// 打开MQTT连接
// 响应:+QMTOPEN: 0,0

AT+QMTCONN=0,"clientId"
// 建立MQTT连接
// 响应:+QMTCONN: 0,0,0

AT+QMTSUB=0,1,"/topic/test",0
// 订阅主题
// 响应:+QMTSUB: 0,1,0,0

AT+QMTPUB=0,0,0,0,"/topic/test","Hello MQTT"
// 发布消息
// 响应:+QMTPUB: 0,0,0
协议 典型指令前缀 适用场景 注意事项
MQTT AT+QMTOPEN / AT+QMTCONN 实时数据上报、远程控制 注意QoS等级,QoS1会重发
HTTP AT+QHTTPURL / AT+QHTTPGET 非实时数据、OTA升级 注意URL长度限制
CoAP AT+QCOAPOPEN NB-IoT低功耗场景 UDP协议,不保证可靠

⚠️ 注意:MQTT的保活心跳(Keep Alive)是个容易忽略的点。如果心跳间隔太长,服务器会断开连接;太短又浪费功耗。我一般设60秒,配合模组的PSM省电模式,效果不错。另外,记得在断线后自动重连——我见过太多设备因为网络抖动掉线后「失联」的案例。

4.5 自定义指令开发——让模组「听懂你的话」

标准AT指令能覆盖大部分场景,但总有一些特殊需求——比如读取某个私有传感器的数据、执行特定的加密算法、或者对接某个非标协议。这时候,就需要自定义指令了。

我做过一个项目,客户要求模组直接读取一个I2C温湿度传感器。标准AT指令肯定不支持。怎么办?让模组厂商帮忙开发自定义指令。说白了,就是让模组的固件里多一段代码,注册一个新的AT指令处理函数。

// 伪代码:自定义AT指令处理流程
// 1. 注册指令
AT_REGISTER("AT+TEMP", temp_handler);

// 2. 实现处理函数
int temp_handler(char *params, char *response) {
    int temp = read_i2c_temperature();  // 读取I2C传感器
    sprintf(response, "+TEMP: %d", temp);
    return AT_OK;
}

// 3. 使用效果
// 发:AT+TEMP
// 收:+TEMP: 25

我的经验:自定义指令开发,一般有两种方式:一是找模组厂商定制固件(适合大批量),二是在MCU端做指令转发(适合小批量)。我个人更推荐第二种——把自定义指令的逻辑放在MCU上,模组只做透传。这样模组固件不用动,升级也方便。我曾经用这种方式,在MCU上实现了 AT+GPS 指令,模组收到后通过串口转发给GPS模块,再把结果返回。灵活得很。

4.6 指令调试与排错——实战中的「救命稻草」

指令写好了,但设备就是不按预期工作。怎么办?别慌,我总结了一套「AT指令排错三板斧」:

  1. 看响应码:模组返回 ERROR 时,后面通常跟着 +CME ERROR: 或 +CMS ERROR: 错误码。查一下模组手册,基本能定位问题。
  2. 开回显:发 ATE1 打开回显,看看你发的指令模组到底收到了什么。我曾经发现MCU发的指令多了个空格,模组直接不认。
  3. 抓日志:用串口工具把模组的所有输出都抓下来。很多时候,问题就藏在那些你忽略的URC上报里。

最后说一句:AT指令不难,难的是细心。每个换行符、每个逗号、每个引号,都可能成为你调试一整天的问题根源。但只要你掌握了这五类指令——基础、3GPP、TCP/IP、MQTT/HTTP、自定义——你就能驾驭市面上90%的蜂窝模组。