简介:这份资源是 Fibocom 广和通 FG150 与 FM150 系列 5G 模组的官方 AT 命令手册,面向使用该系列模组进行物联网终端、工业自动化设备开发的嵌入式工程师与驱动调试人员,用于解决在模组初始化、入网注册、数据链路与系统参数配置过程中查不到准确命令的问题。压缩包内共 1 个 PDF 文件,约 1.79MB,为 V3.6.3 版英文指令文档,正文两百四十余页,按网络设置、模组状态、数据传输、系统配置等类别组织,并附版本变更记录与适用型号说明,如 FG150-AE、FM150-NA、FM150-AE。手册逐条给出命令语法、参数取值范围、返回码与交互示例,涵盖 CGMI、CGMM、CGMR、CSQ、CGATT 等常用查询指令,以及 APN、PDP、信号与连接状态等配置项,便于读者对照实际串口日志定位问题、核对固件行为。目前已有 589 人学习下载,适合需要查阅权威命令定义、排查入网与数据链路故障的开发者常备参考。
1. 从一台拨不上号的样机说起:FM150 手册到底解决什么问题
某网关样机在实验室跑了两周没出岔子,装到现场后AT+CGATT?始终回 0,串口敲什么都回 OK,运营商侧看不到任何附着记录。开发板厂商给的示例代码只有AT+CGDCONT和AT$QCRMCALL两行,剩下的全是空白。广和通 FM150 这类 5G 模组的真实脾气,藏在 241 页的 AT 指令手册里——V3.6.3 版,2020-02-20 发布,覆盖 FG150-AE、FM150-NA、FM150-AE 三个型号,从模组信息、控制状态、呼叫、短信一路列到数据拨号、双卡、小区锁定。这份资源适合正在做 5G 模组二次开发的人:无论你是在 Linux 网关上跑 RMNET,还是用单片机串口发 AT,它就是那颗模组的说明书,也是现场排查时唯一能对质的东西。
2. 先建索引再读正文:+C、+G、+GT、$qc 四条命名血脉怎么分
拿到一份 241 页的 PDF,从头读到尾是最亏的做法。指令手册不是教材,它是字典,正确用法是先建索引、再按需翻。这份手册的结构其实很规整:第 2 章讲协议与命令结构,第 3 到第 7 章按功能分块(模组信息、控制与状态、呼叫、时间、短信),后面的章节才是数据业务和厂商扩展。真正让人卡住的不是找不到章节,而是不知道某个指令该去哪一章找——解决这个问题,看指令前缀就够了。
2.1 前缀即出身:四条血脉决定了可移植性
手册里出现的指令可以按前缀分成四类,每一类的来源、稳定性和换平台后的可用性完全不同。搞清这一点,你在别的模组上积累的经验才知道哪些能带走。
| 前缀 | 来源 | 典型指令 | 换模组后还能用吗 |
|---|---|---|---|
+C | 3GPP TS 27.007 / 27.005 | +CGMI、+CGMM、+CGDCONT、+CPMS、+CMGF | 基本能用,语义一致 |
+G | 旧式别名,与+C一一对应 | +GMI、+GMM、+GMR、+GSN | 能用,只为兼容老代码存在 |
+GT | 厂商自定义扩展 | +GTAUTOCONNECT、+GTCELLLOCK、+GTLPMMODE | 不能,绑死固件版本 |
$qc | 平台私有 | $QCRMCALL | 不能,换平台即失效 |
+C那一族是 3GPP 定的,+CGMI查厂商、+CGMM查型号、+CGMR查固件版本、+CGSN查 IMEI,这套在任何一家模组上都是同样的行为,代码可以直接搬。+G那一族是历史遗留,+GMI和+CGMI干的是同一件事,手册里两套并列列出,老项目里见到AT+GMR不要以为是野路子。
+GT才是这份手册真正的信息量所在——网络、休眠、双卡、小区、数据统计几乎全在这一族里。+GTUSIM查 USIM 卡、+GTFMODE控硬件飞行模式、+GTWAKE开主机唤醒、+GTLPMMODE配休眠唤醒模式、+GTDUALSIM切双卡、+GTCELLLOCK锁小区、+GTCAINFO读载波聚合信息、+GTWWAN查广域网状态、+GTSTATIS做数据统计、+GTMPDN配模组自有 PDP、+GTAUTOCONNECT开机自动拨号、+GTROAMCFG配漫游策略。这些指令换个固件版本就可能改语法,代码里必须带版本判断。
提示:厂商扩展不全是
+GT开头。+WRIM(RI 信号宽度)、+MSTART(启动消息通知)、+MHUP(模组侧挂断)、+SLPMODE(休眠使能)、+SIMSWAPCFG(SIM 热插拔电平)、+MSMPD(热插拔使能)、+MTSM(温度测量)都算扩展指令。只搜+GT会漏掉一批跟低功耗、热插拔强相关的条目。
$qc那一族只有寥寥几条,但每一条都在关键路径上。$QCRMCALL是触发 RMNET 网卡的那一下,$QCPDPP原本用来配 PDP 鉴权——注意,后者在 2020-01-14 的变更记录里被删掉了,新代码里再写就是 ERROR。这种“曾经存在、现在消失”的指令,只有翻变更记录才知道。
2.2 Change History 比正文更值得先读
这份手册的第 4 到第 6 页是 Change History,很多人直接跳过,实际上它是整份文档里信息密度最高的部分,因为每一条都在告诉你“哪个指令的行为变了”。
翻一遍能捞出几个关键节点。V3.6.1 是 2019-11-19 的初版,V3.6.2 在 2019-11-22 一次性加了+GTDUALSIM、+GTOTA、+GTWWAN、+GTCELLLOCK四条,说明那个时间点模组补了一批网络侧功能。2019-12-09 和 2019-12-27 两次修改+GTCELLLOCK的参数范围,意味着早期固件上锁频的参数写法跟现在不一样,抄老代码会失败。2020-01-16 新增+GTCAINFO,2020-04-18 又改了一次,中间只隔三个月。
最值得记的是+GTAUTODHCP。2020-01-13 加进来,2020-02-20 的 V3.6.3 第一条记录就是 “Delete +GTAUTODHCP”,活了一个多月。所以你在网上看到的“打开自动 DHCP 就发AT+GTAUTODHCP=1”这类写法,在当前固件上大概率回 ERROR,得改成主机侧自己跑 dhcp 客户端。
还有一个反直觉的点:文档头写的版本是 V3.6.3、日期 2020-02-20,但变更记录的最后一行已经排到 2020-05-16 的+GTINTFMODE。这说明这份 PDF 是滚动更新的,头部日期只是编制时间,不能用来判断内容覆盖到哪。要以变更记录最后一行的时间为准,判断你手上这份是不是最新的。
2.3 用 +CLAC 把纸面目录变成机器清单
手册写的是“这个系列支持什么”,固件决定的是“你这颗片子实际有什么”。两者经常对不上:新固件加了功能但手册没更新,或者手册列了但你的型号没实现。AT+CLAC就是用来做这个差集的——它返回当前固件实际支持的全部指令列表。
import serial, time, re def at(ser, cmd, wait=0.5): ser.reset_input_buffer() ser.write((cmd + "\r\n").encode()) time.sleep(wait) return ser.read_all().decode(errors="ignore") ser = serial.Serial("/dev/ttyUSB2", 115200, timeout=1) at(ser, "AT") # 先握手,确认串口是通的 at(ser, "ATE0") # 关回显,否则每条命令都被回显一遍,污染结果 raw = at(ser, "AT+CLAC", wait=2.0) # 指令可能有上百条,等待时间必须放宽 # 抓 +XXX 和 $qcXXX 两类 token,过滤掉 OK / ERROR 这类短词 cmds = sorted({m for m in re.findall(r"\+?[A-Z$][A-Z0-9$+]*", raw) if len(m) > 2}) with open("clac.txt", "w") as f: f.write("\n".join(cmds)) print(f"captured {len(cmds)} commands")这段代码做了三件事:握手、关回显、抓清单。wait=2.0是关键参数,指令数量多的时候模组吐数据会超过一秒,等太短只能拿到半截,后面做差集就会误判“手册里有但固件没有”。ttyUSB2是常见 AT 口编号,但模组枚举出几个口取决于+GTUSBMODE的配置,接错口的表现是发什么都回 ERROR 或者干脆没回音,这一点在第 5 章会展开。
拿到clac.txt之后,把它跟手册目录里抽出的指令名做一次集合差,你会得到两张表:固件有但手册没写的(通常是新功能,去查最新版手册)、手册写了但固件没有的(要么型号不支持,要么需要升级固件)。这两张表比通读一遍手册有用得多。
3. 上电第一公里:从 AT 握手到 +CEREG 驻网判定的完整自检序列
模组上电之后到能跑业务之前,有一段固定流程:串口通、卡识别、射频开、网络注册、数据附着。每一步都有对应的指令可以查,把这套序列固化成开机自检脚本,能挡掉现场八成的“连不上”。
3.1 串口先握手:E、Q、V 三条开关
连上串口第一件事不是发业务指令,是把通信参数理顺。Linux 下先确认模组枚举出几个口:
# 看每个 ttyUSB 对应的接口名,找出 AT 口 for d in /sys/class/tty/ttyUSB*/device; do echo "$d -> $(cat $d/interface 2>/dev/null)" done # 连上去手敲,115200 8N1,软硬流控都关 picocom -b 115200 --flow n /dev/ttyUSB2115200 是默认波特率,8N1,无流控。有些板子会把波特率改成 921600 提吞吐,改之前确认你的 USB 转串口芯片跟得上,否则会出现“发出去的指令被吞掉一半”的玄学现象。
进去之后依次处理三条开关。ATE0关回显——回显开着的时候,你发AT+CSQ,串口会先吐一遍AT+CSQ再吐结果,脚本按行解析就会错位。ATQ0打开结果码,ATQ1关掉,正常业务当然要开着。ATV1用文本结果码(OK/ERROR/+CME ERROR: ...),ATV0是数字码,脚本里用数字码能少一次字符串匹配,但排障时人眼看文本码舒服得多,我的习惯是开发阶段用ATV1,量产脚本再考虑切ATV0。
再加一条AT+CMEE=2。这是 27.007 里的标准指令,作用是让错误从干巴巴的ERROR变成带原因码的+CME ERROR: 3(3 表示不允许操作)或+CME ERROR: 10(SIM 未插入)。现场排查时,ERROR和+CME ERROR: 10的排查路径差着十万八千里,这一条指令能省很多时间。
3.2 身份与卡状态:五个必查量
串口通了之后,先把模组和卡的身份信息抓全,一是确认固件版本跟你手上的手册对得上,二是留档方便对比。
| 指令 | 返回内容 | 用途 |
|---|---|---|
AT+CGMI | 厂商标识 | 确认模组来源 |
AT+CGMM | 型号 | 区分 FG150 / FM150 及各地区版本 |
AT+CGMR | 固件版本 | 与手册版本比对,决定哪些指令可用 |
AT+CGSN | IMEI | 设备唯一标识,报障必带 |
AT+CFSN | 出厂序列号 | 产线追溯用,跟 IMEI 不是一回事 |
AT+CCID | ICCID | 读卡,判断卡是否被识别 |
AT+CIMI | IMSI | 判断卡是否被运营商侧激活 |
AT+CPIN? | READY/SIM PIN等 | 卡状态机最直接的一眼 |
AT+CNUM查本机号码,很多物联网卡根本没写这个字段,回ERROR是正常的,不要当成故障。AT+GTUSIM是厂商侧的卡检测,语法不确定的时候先发AT+GTUSIM=?让模组自己吐语法骨架,比翻 PDF 快。
AT+CCID读不出来是最常见的翻车点之一,现象是AT+CPIN?回READY但AT+CCID空或者 ERROR。这时候要看两件事:卡座是不是没插到位,以及+SIMSWAPCFG配的热插拔电平跟硬件对不对——后者是第 5 章的重点。
3.3 驻网判定:+CSQ 和 +CEREG 要一起看
信号强度和注册状态是两码事,很多人只看AT+CSQ回了个 20 就以为网络没问题,结果数据死活起不来。
AT+CSQ返回两个值:rssi,ber。rssi 取值 0 到 31,越大越好,99 表示未知或不可测;ber 是误码率,同样 99 表示未知。这个值是无线侧的粗略强度,跟能不能注册上没必然关系。
注册状态要看AT+CEREG?。第二个参数的含义是:1 表示本地网络已注册,2 表示正在搜网,3 表示注册被拒绝,5 表示漫游注册。5G 模组上有个高频误判:AT+CREG?(2G/3G 注册)长期回 0,因为模组实际走的是 LTE 或 NR 通道,这时候要看AT+CEREG?才对。我见过有人盯着+CREG查了一下午。
再补三条:AT+COPS?看当前运营商,AT+CGATT?看分组域附着(回 1 才算附着成功),AT+CGPADDR=1看 PDP 上下文有没有分到 IP。附着成功但没 IP,说明 PDP 没激活,问题在拨号那一层,不在注册那一层。
3.4 把自检写成脚本
手工敲一遍能通,不代表批量设备能通。把上面这些固化成脚本,产线和现场都用同一份:
import serial, time, json PROBE = [ "AT", "AT+CGMI", "AT+CGMM", "AT+CGMR", "AT+CGSN", "AT+CFSN", "AT+CCID", "AT+CIMI", "AT+CPIN?", "AT+GTUSIM?", "AT+CSQ", "AT+CEREG?", "AT+COPS?", "AT+CGATT?", "AT+CGPADDR=1", ] def run(ser, cmd, wait=0.4): ser.reset_input_buffer() ser.write((cmd + "\r").encode()) time.sleep(wait) return ser.read_all().decode(errors="ignore").strip() ser = serial.Serial("/dev/ttyUSB2", 115200, timeout=0.5) ser.write(b"ATE0\r") # 必须先关回显 time.sleep(0.3) ser.reset_input_buffer() report = {c: run(ser, c) for c in PROBE} print(json.dumps(report, indent=2, ensure_ascii=False))wait=0.4对大部分指令够用,但AT+CCID要走卡这边,有些卡慢,建议单独给它0.8。AT+GTUSIM?如果回 ERROR,改成AT+GTUSIM=?拿语法,再按语法补参数——这是处理所有不确定厂商指令的通用套路,先问语法再问值,别凭记忆写。
跑完这份报告,你会得到一台设备的完整快照:固件版本、IMEI、卡号、信号、注册、附着、IP。现场出问题时,拿故障机的快照跟正常机对比,差异项基本就是问题所在。
4. 数据通道三选一:PPP、内置协议栈与 $QCRMCALL 的拨号差异
模组能注册上网络,跟主机能收发 IP 包,中间还隔着一层数据通道。这份手册覆盖了三条路径,选错了会在项目后期付出很大代价。
4.1 三条路径的选型对比
| 路径 | 触发方式 | 主机侧要求 | 适合场景 | 断线恢复 |
|---|---|---|---|---|
| PPP 拨号 | ATD*99# | 需要 pppd + chat 脚本 | 老平台、MCU、无网卡驱动的系统 | 主机侧 watchdog 重拨 |
| 内置协议栈 | +GTMPDN++GTAUTOCONNECT | 无,模组自己跑 TCP/UDP | 轻量终端、无操作系统、只管上报 | 模组侧自动重连 |
| RMNET / QMI | $QCRMCALL=1,1 | Linux 内核 rmnet 驱动 + dhcp 客户端 | 网关、CPE、要跑完整 IP 栈 | qmi 守护进程 + 重拨脚本 |
PPP 是最老也最通用的那条,ATD*99#拨出去,主机侧跑 pppd 起来一个 ppp0。优点是任何能跑 pppd 的系统都支持,缺点也明显:串口速率成为上限,断线要靠主机发现,重拨逻辑得自己写。手册第 5 章的+CBST(选承载业务类型)和+FCLASS(业务类别选择)就是给这条路配的。
内置协议栈走的是另一条思路:模组自己把 TCP/IP 跑起来,主机只发 AT 指令让它建 socket、发数据。+GTMPDN用来配模组自有的 PDP 上下文,+GTAUTOCONNECT控制开机自动拨号。这条路省掉了主机侧所有网络栈,代价是灵活性——你想跑个自定义协议或者做多路复用,基本没戏。
RMNET 是 Linux 网关上最常见的选择。$QCRMCALL触发拨号,模组返回一个网卡名,主机侧对这个网卡跑 DHCP 拿地址。它把数据路径从串口挪到了 USB 的 rmnet 通道,吞吐能上去,代价是需要内核支持。
4.2 PDP 上下文与鉴权:cid 别乱选
不管走哪条路,PDP 上下文都是绕不开的。AT+CGDCONT定义上下文,第一个参数是 cid:
# 定义 cid=1 的 IPv4 上下文,APN 按运营商给的填 AT+CGDCONT=1,"IP","apn.example" # 查当前所有上下文,确认写进去了 AT+CGDCONT? # 配鉴权:cid, 鉴权类型, 用户名, 密码 # 鉴权类型:0=NONE,1=PAP,2=CHAP,3=PAP 或 CHAP AT+CGAUTH=1,1,"user","pass" # 拨号后查分到的 IP AT+CGPADDR=1cid这个参数容易被想当然。默认大家都用 1,但运营商专网经常要求用 2 或 3,甚至不同 APN 对应不同 cid。写错 cid 的表现是AT+CGDCONT?看着有配置,但AT+CGPADDR=1拿不到地址——因为业务实际走的是另一个上下文。现场拿到专网卡,第一件事是问清楚 cid 和 APN,别自己猜。
+CGAUTH的鉴权类型也要对上。运营商给 PAP 你配 CHAP,表现是拨号超时或者直接被拒,日志里看不出明确原因,只有个NO CARRIER。稳妥做法是先配 3(PAP 或 CHAP 都试),通了之后再收紧到具体那种。
4.3 自动拨号:+GTAUTOCONNECT 与已删除的 +GTAUTODHCP
内置协议栈路径上,开机自动拨号靠+GTAUTOCONNECT。这条指令在 2020-01-13 加进来,跟它一起加的还有+GTAUTODHCP,两条原本是配套的:一条负责拨号,一条负责拨完自动跑 DHCP。
问题在于+GTAUTODHCP在 V3.6.3 里被删了。所以现在正确的组合是:+GTAUTOCONNECT打开自动拨号,DHCP 那一步交回主机侧做。老项目里如果还留着AT+GTAUTODHCP=1,升级固件后必然回 ERROR,而且这个 ERROR 很隐蔽——它不影响拨号,只是 DHCP 那步没了,表现为“能拨上但拿不到 IP”。
针对+GTMPDN这类新指令,我的习惯是先问语法再写代码:
# 先让模组自己吐语法骨架,参数顺序以它为准 AT+GTMPDN=? # 再看当前值 AT+GTMPDN? # 按骨架写配置,写完再查一遍确认落盘 AT+GTMPDN=<按骨架填> AT+GTMPDN?这么做是因为手册里同一个指令在不同固件版本上参数顺序变过——+GTCELLLOCK就改过两次参数范围。凭记忆写参数,回 ERROR 的时候你分不清是语法错还是值非法,排查成本翻倍。
4.4 通道起来之后:用 +GTWWAN 和 +GTSTATIS 验证
拨号成功不等于链路可用。+GTWWAN查广域网状态,能看出当前是哪个制式、信号如何、IP 有没有;+GTSTATIS是 2020-03-16 新增的数据统计指令,用来核对收发字节数。
RMNET 路径的完整验证流程大致是这样:
# 1. 模组侧触发拨号,cid=1 AT$QCRMCALL=1,1 # 期望返回:$QCRMCALL: 1, rmnet_data0 # 第一个参数是 cid,第二个一般是 1,返回里的网卡名要记下来 # 2. 主机侧把网卡拉起来 ip link set rmnet_data0 up # 3. 拿地址 udhcpc -i rmnet_data0 -q -n -t 5 # 4. 确认地址和默认路由 ip -4 addr show rmnet_data0 ip route | grep rmnet_data0udhcpc的-t 5是重试次数,-n表示拿不到地址就退出而不是一直等。这两参数在脚本里必须给,否则拨号失败时脚本会挂死在那。如果udhcpc拿到地址但 ping 不通外网,先查默认路由有没有指到这张网卡,再查AT+CGATT?是不是 1——附着掉了的话,网卡在但包出不去。
5. 五个现场翻车记录:ERROR、睡不醒、热插拔失灵的排查路径
这一章全是踩过的坑。每条按“现象、原因、解决”写,顺序基本就是我自己的排查顺序。
5.1 所有 AT 都回 ERROR:接错 USB 复合口
现象:串口能打开,发什么都回 ERROR,偶尔连AT都回 ERROR。
原因:5G 模组枚举出来的是一个 USB 复合设备,同时提供 AT、DIAG、NMEA、MODEM 好几个口。你连上去的那个不一定是 AT 口。+GTUSBMODE就是控制这套枚举表的,改过配置之后口序会变,之前记的ttyUSB2可能变成ttyUSB3。
解决:先按接口名找,别按编号找。/sys/class/tty/ttyUSB*/device/interface里会写着每个口的用途,找那个标着 AT 的。找不到就一个一个试,AT 口对AT一定有OK回应,其他口要么没反应,要么吐的是二进制诊断数据。
5.2 老脚本升级固件后报 ERROR:+GTAUTODHCP 已被删除
现象:同一份脚本,旧批次模组跑得好好的,新批次全部在 DHCP 那一步失败,日志里一条 ERROR。
原因:+GTAUTODHCP在 V3.6.3 里被删掉了。旧固件上有这条指令,新固件没有,脚本发过去就是 ERROR。更麻烦的是这个 ERROR 不影响前面的拨号,只影响拨号之后的拿地址,所以现象是“拨上了但没网”。
解决:删掉AT+GTAUTODHCP那行,把 DHCP 挪到主机侧。如果是嵌入式系统没法跑 DHCP 客户端,就在模组侧配静态 IP,或者改走内置协议栈路径。升级固件之前养成习惯,拿新固件的AT+CLAC结果跟脚本里用到的指令做一次交集,缺哪条一眼就能看出来。
5.3 睡下去叫不醒:+GTLPMMODE 和 +WRIM 没配对
现象:低功耗配置生效后,主机发数据完全没反应,必须断电重启。串口上偶尔能看到模组已经醒了但没有输出。
原因:休眠唤醒是有握手的。+GTLPMMODE配休眠和唤醒模式,+WRIM配 RI 信号的脉宽。这两条不匹配的时候,模组认为已经通过 RI 通知了主机,主机那边因为脉宽太窄没采到,双方就卡在那互相等。+GTWAKE是另一条相关指令,控制的是主机唤醒模组这个方向。
解决:先把+WRIM的脉宽调宽,给主机留够采样窗口,再回去调+GTLPMMODE。主机侧串口读要设成非阻塞,别指望读到固定字节数才返回。调通之前用示波器抓一下 RI 引脚,确认脉宽真的出来了——软件层面看到的现象很容易骗人。
注意:低功耗这块改一个参数要重新验一遍全流程,因为休眠和唤醒的时序是耦合的。改完
+WRIM只测唤醒不测休眠,问题会留到现场才爆。
5.4 SIM 热插拔检测失效:+SIMSWAPCFG 电平配反
现象:卡拔掉之后模组没反应,AT+CPIN?一直回READY,或者反过来,卡插着却报无卡。
原因:+MSMPD是热插拔使能开关,+SIMSWAPCFG配的是检测引脚的有效电平。有效电平配反了,模组的判断就整个反过来——插着的时候认为拔了,拔了认为插着。这两个参数是跟硬件电路绑的,同一份固件烧到不同板子上,配置可能完全相反。
解决:查原理图上 SIM 检测引脚是上拉还是下拉,据此定+SIMSWAPCFG的电平。改完之后插拔各试三次,看AT+CPIN?和AT+CCID是不是跟着变。只试一次很容易碰巧通过——拔卡瞬间的抖动可能被当成一次有效中断。
5.5 短信中文全是问号:+CMGF 和 +CSCS 没对齐
现象:英文短信正常,中文发出去对方收到的是一串问号或者乱码。
原因:短信有两种模式,+CMGF=0是 PDU 模式,+CMGF=1是文本模式。文本模式下字符集由+CSCS决定,发中文必须切到"UCS2"。切了之后号码和内容都要按 UCS2 编码成十六进制串,长度翻倍,很多人只改了字符集没改编码方式。
解决:AT+CSCS="UCS2"之后,手机号和正文都做 UCS2 编码再发,+CSMP里的数据编码字段也要跟着配。这套流程在 PDU 模式下反而更直观,因为整个 PDU 串都是你自己拼的,编码对不对一眼能看出来。我的习惯是中文短信统一走 PDU 模式,少一层隐式转换。
6. 信号取证进阶:用 +GTCELLLOCK 与 +GTCAINFO 锁定现场问题
现场问题最难的地方不是修,是复现。设备在客户那信号时好时坏,拿回实验室一切正常,这时候需要的是取证而不是猜测。这份手册里有几条指令是专门干这个的。
+GTCELLLOCK是锁频锁小区,用来把模组钉在某个频段或某个小区上。它的参数范围在 2019-12-09 和 2019-12-27 被改过两次,所以不同固件上的写法不一样,用之前必须AT+GTCELLLOCK=?拿骨架。典型用法是怀疑某频段干扰时,把模组锁到另一个频段对比吞吐,问题是不是跟频段相关一目了然。
+GTCAINFO读载波聚合信息,2020-01-16 新增、2020-04-18 又改过。5G 和 LTE 的速率很大程度靠载波聚合撑着,聚合没起来的时候速率掉一半,但+CSQ上的信号强度看着还挺好。这条指令能告诉你当前聚合了几个载波、各载波的状态。
+GTCELLSTATUS和+GTSRVSTATUS(都是 2020-02-17 一起加的)分别看小区状态和服务状态,+GTEPSMOBINFO看 EPS 移动性信息。这几条组合起来,能拼出一张接近网优工具的现场快照。
| 指令 | 主要字段 | 用来判断什么 |
|---|---|---|
+GTCELLLOCK | 频段、频点、小区 ID | 锁定条件是否生效 |
+GTCAINFO | 载波数量、各载波状态 | 聚合有没有起来 |
+GTCELLSTATUS | 小区级参数 | 当前驻留小区是否稳定 |
+GTSRVSTATUS | 服务状态 | 业务是否可用 |
+GTEPSMOBINFO | 移动性参数 | 是否在频繁重选 |
光看单次快照没用,要做时间序列采样。三十秒一次,落 CSV,跑满二十四小时,然后把+GTCAINFO里的载波数量和+GTSTATIS里的收发字节数对齐看,速率掉下去的时刻聚合是不是也掉了,一眼就能对上。
import serial, time, csv, datetime CMDS = ["AT+CSQ", "AT+CEREG?", "AT+GTCAINFO?", "AT+GTCELLSTATUS?"] ser = serial.Serial("/dev/ttyUSB2", 115200, timeout=1) ser.write(b"ATE0\r"); time.sleep(0.3) with open("cell_trace.csv", "w", newline="") as f: w = csv.writer(f) w.writerow(["ts"] + CMDS) while True: row = [datetime.datetime.now().isoformat(timespec="seconds")] for c in CMDS: ser.reset_input_buffer() ser.write((c + "\r").encode()) time.sleep(0.5) # 采集指令多,单条等待要留够 row.append(ser.read_all().decode(errors="ignore").strip()) w.writerow(row) f.flush() # 长时间跑必须 flush,否则崩了丢数据 time.sleep(30)flush()这行别省。采样脚本一跑一整天,进程被 kill 或者设备重启,缓冲区里那几个小时的数据就没了,而恰恰是出
本文还有配套的精品资源,点击获取