简介:面向5G模组开发与调试人员的广和通FG150 & FM150 Series AT命令手册,聚焦5G NR、LTE、WCDMA、TD-SCDMA与GSM等多制式模组的指令查询和功能配置,适合物联网终端、工业自动化及智能交通场景下的驱动开发、联调测试与故障排查参考。包内为1个PDF文档,约1.79MB,正文共241页,版本V3.6.3,适用FG150-AE、FM150-NA、FM150-AE等型号;内容按网络设置、模组状态、数据传输和系统命令分类,收录AT+CGMI、AT+CGMM、AT+CGMR、AT+CSQ、AT+CGATT等常用指令示例,并保留版本变更记录与参数说明,目录层级清晰,便于按功能检索。已有589人学习下载。读者可借此系统掌握模组厂商信息查询、固件版本读取、信号强度判断和网络附着状态检查等基础操作,也能沿目录定位APN配置、低功耗模式、小区锁定等进阶命令的参数与返回码,为实际项目中的指令调试、联调记录、问题定位及团队技术培训提供可直接查阅的原始依据。
1. 一块插上没反应的 FM150:AT 指令环境要先装对什么
板子焊好、USB 线插上、串口终端一开,屏幕上跳出来的是一串问号,切到十六进制看全是 0x00。这是很多人第一次接 FM150 模组的开局。FM150 AT 指令手册 241 页,V3.6.3,2020-02-20 定版,适用 FG150-AE、FM150-NA、FM150-AE 三款型号,命令从 +CGMI 这种身份查询一路排到 +GTCELLLOCK 这种小区锁定。手册本身不讲主机侧装什么、串口怎么配、哪条命令在你的固件上会回 ERROR。装不对最直接的表现是:端口能打开,发什么都不回;或者回一堆 OK,但 +CGATT? 永远是 0。这套环境适合手上有模组和载板、准备做 5G 数据链路联调的开发者,也适合接手别人半成品工程、要把 AT 通道重新捋一遍的人。
2. 版本与环境对齐:V3.6.3 手册该配哪套工具链
装 AT 环境最容易翻车的地方不在命令本身,在于手册、固件、主机工具三方版本没有对齐。手册封面写 V3.6.3,不代表你手里那颗模组跑的就是 V3.6.3 对应的固件;主机侧串口工具默认参数不对,也照样能打开端口但一个字符都收不到。这一章先把三样东西摆到桌面上对齐,再动手装。
2.1 型号先对:手册适用范围只有这三款
手册开头的 Applicability 表只有三行,FG150-AE Series、FM150-NA Series、FM150-AE Series。这三个型号共享同一套命令集文档,但射频指标、支持的频段、部分私有命令的默认取值并不一致。拿 FM150-NA 的模组去套 AE 版本的参数默认值,最常见的后果是某些 +GT 开头的私有命令回 ERROR 或者行为对不上。
判断自己手上是哪一款,别只看包装标签,两个办法最稳:
# 方法一:看模组屏蔽罩丝印,型号通常直接印在上面 # 方法二:上电后读模组自报的型号,比标签可信 printf 'AT+CGMM\r' > /dev/ttyUSB2 printf 'AT+CGMI\r' > /dev/ttyUSB2+CGMM返回 Model ID,+CGMI返回 Manufacturer ID,手册 3.1.1 到 3.1.4 明确列了这两组命令的长短两种写法(+CGMI/+GMI、+CGMM/+GMM),返回内容一致,短写法老固件兼容性更好。参数上没有什么可调的,注意发送结尾用\r,有些固件对\r\n也能识别,但统一用\r最不容易出问题。
型号确认完之后再确认固件版本,用AT+CGMR读 Revision。这一步的目的是:手册 V3.6.3 的变更记录里,很多命令是分批次加进去的,如果你的固件版本比手册老,手册里写着的一些命令在设备上根本不存在。这不是手册错,是版本没对齐。
2.2 主机侧软件清单:四样东西,别多装
AT 调试不需要 IDE,也不需要厂商上位机,装多了反而互相抢串口。我一般固定这四样:
| 组件 | 用途 | 版本建议 | 备注 |
|---|---|---|---|
| USB 串口驱动 | 让系统认到模组的 CDC-ACM 口 | 随系统内核或厂商提供 | Linux 内核 5.x 以上基本自带 |
| picocom 或 minicom | 交互式发命令、看回显 | picocom 3.1+ / minicom 2.7+ | 二选一,别同时开同一个口 |
| Python 3 + pyserial | 脚本化批量验证 | Python 3.8+ / pyserial 3.5+ | 最后一章的自检脚本要用 |
| 手册电子版 | 查命令语法和返回码 | V3.6.3 | 变更记录那一节要重点看 |
装 picocom 和 pyserial 的命令在 Debian/Ubuntu 系上就两条:
sudo apt update sudo apt install -y picocom python3-pip pip3 install pyserialpicocom轻量,退出快捷键是Ctrl+A再Ctrl+X,比 minicom 少一层菜单。pyserial是为后面写自检脚本准备的,人工敲十几条命令容易漏,脚本跑一遍最省事。如果你的机器是离线环境,这两个包提前下好 deb 或 whl,别到现场才发现装不上。
2.3 串口参数:115200 8N1,流控必须关
模组 AT 口的默认参数基本是 115200、8 数据位、无校验、1 停止位、无硬件流控。这里最容易踩的坑是流控:有些串口工具默认打开 RTS/CTS,而载板上 RTS/CTS 根本没引出来或者没接,结果是端口能打开、能发数据、但收不到任何返回,看起来像模组死机。
用 stty 手动设一遍,比在工具里点选更可控:
# 关闭流控、设成 115200 8N1、关闭回显转换 stty -F /dev/ttyUSB2 115200 cs8 -cstopb -parenb -crtscts raw -echo # 确认设置生效 stty -F /dev/ttyUSB2 -a | grep -E 'speed|cs8|crtscts'-crtscts是关硬件流控的关键项,raw关掉终端的行缓冲和特殊字符处理,避免把\r吃掉。-echo关的是主机侧回显,模组自己的回显由ATE命令控制,两者别搞混。改完 stty 之后如果还是不通,先换一根确认能传数据的 USB 线,劣质线只通电不传数据的情况不少见。
2.4 端口枚举:一个模组为什么冒出好几个 ttyUSB
USB 复合设备上电后通常会枚举出多个串口节点,/dev/ttyUSB0到/dev/ttyUSB3都可能出现,分别对应 AT 命令口、诊断日志口、数据口、GPS/NMEA 口。插拔顺序不同,编号会变,写死在脚本里迟早出事。
查一下每个口对应什么:
# 看插入时的内核日志,能看出每个口注册的顺序和用途 dmesg | grep -i -E 'ttyUSB|cdc_acm' | tail -20 # 用 udevadm 看端口的物理路径,插不同 USB 口路径会变 udevadm info -q path -n /dev/ttyUSB2稳妥做法是写一条 udev 规则把 AT 口固定成/dev/ttyFM150,脚本和工具都指向这个名字:
# /etc/udev/rules.d/99-fm150.rules # 依据 USB 设备的 vid/pid 与接口号绑定,换 USB 口也不会变名 SUBSYSTEM=="tty", ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0104", ATTRS{bInterfaceNumber}=="02", SYMLINK+="ttyFM150", MODE="0666"idVendor/idProduct用lsusb查你实际设备的取值,bInterfaceNumber对应 AT 口所在接口号,不同固件枚举顺序会有差异,先用dmesg确认。SYMLINK+="ttyFM150"建软链,MODE="0666"省掉每次 sudo 的麻烦。规则写完sudo udevadm control --reload && sudo udevadm trigger,重新插拔一次生效。
3. 打通第一条 AT 通道:串口工具安装与最小回环验证
端口和参数都对齐之后,这一步的目标很明确:让AT两个字回车之后返回OK。听起来简单,实际上这一步卡住的人最多,因为它同时涉及权限、端口选择、流控、回显四件事,任何一件不对都表现为「没反应」。
3.1 Linux 侧装 picocom 与串口权限
普通用户默认不在 dialout 组里,直接开串口会 Permission denied。加组这一步做完必须重新登录才生效,很多人加完组发现还是不行,就是因为终端会话没重开。
# 把当前用户加入 dialout 组,获得串口读写权限 sudo usermod -aG dialout $USER # 重新登录后确认组已生效 groups | grep dialout # 用 picocom 打开 AT 口,参数一次写全 picocom -b 115200 -d 8 -p n -s 1 --flow n /dev/ttyFM150-b 115200波特率,-d 8数据位,-p n无校验,-s 1一位停止位,--flow n显式关流控。这套参数和上一章的 stty 是等价的两条路径,picocom 会在打开时自己设一遍,所以更推荐直接用 picocom 而不是裸 stty。
进去之后敲AT回车。正常返回:
AT OK注意这里AT是模组回显出来的(默认ATE1开着),OK是结果码。如果你的终端里看不到自己敲的字符,说明回显被关了或者终端本地回显没开;如果连OK都没有,往下看第 3.3 节和第五章。
3.2 Windows 侧端口确认与串口工具参数
Windows 上没有 picocom,用设备管理器看 COM 号,再用任意串口助手。参数页三项必须对:波特率 115200、数据位 8、停止位 1、校验 None、流控 None。流控这一项很多助手默认是「硬件」,不改就收不到数据。
发命令时注意两点:一是结尾要勾选「发送新行」或者手动加 CR,二是十六进制和文本模式别搞混。有的助手在十六进制模式下会自动补\r\n,而模组对\r\n\r\n这种多余空行有时会返回ERROR,看起来像命令语法错。
确认 COM 号别靠猜,插拔一次看设备管理器里哪个口消失又出现。如果设备管理器里出现的是带黄色感叹号的未知设备,先装驱动,别急着怀疑模组。
3.3 回显与结果码:ATE、ATQ、ATV 三个开关
手册 4.1 节的 V、Q、E 三条命令,决定你屏幕上看到的东西。这三条命令看起来是格式问题,实际排错时非常关键——回显关掉之后,脚本解析返回会简单很多。
AT // 基础连通性测试,回 OK 说明通道通了 ATE0 // 关闭命令回显,之后敲命令不再重复显示 ATE1 // 重新打开回显,交互调试时用 ATQ0 // 打开结果码(默认),命令执行完回 OK/ERROR ATQ1 // 关闭结果码,只回数据不回 OK,脚本模式慎用 ATV1 // 结果码用文本形式 OK/ERROR(默认) ATV0 // 结果码用数字形式 0/4,老上位机兼容用ATE0是脚本化调试第一个该发的命令,关了回显之后每条命令的返回就是「数据 + 结果码」,正则匹配起来干净。ATQ1要谨慎,关了结果码之后你无法区分「命令成功但没数据」和「命令失败」,排错阶段不建议开。ATV0只在对端程序写死了数字结果码时用,日常调试保持ATV1。
这三条命令都是立即生效但不跨重启的(具体是否持久化取决于固件),重启模组后回到默认值。如果你的脚本依赖ATE0,每次连接后都要重发一次,别指望它记住。
3.4 用 +CLAC 建能力基线,别信记忆
手册 3.1.14 里有一条+CLAC,列出当前固件支持的全部 AT 命令。这条命令的价值在于:它返回的是你这颗模组真实支持的命令列表,不是手册上写的列表。两者对不上的时候,以+CLAC为准。
# 把支持的命令列表完整抓下来存成基线文件 printf 'AT+CLAC\r' > /dev/ttyFM150 sleep 3 cat /dev/ttyFM150 > fm150_cmdlist_baseline.txt # 查某条私有命令在不在支持列表里 grep -i 'GTCELLLOCK' fm150_cmdlist_baseline.txt grep -i 'GTAUTODHCP' fm150_cmdlist_baseline.txt+CLAC的返回是一大段多行文本,直接cat串口会截断,所以先重定向到文件再处理。sleep 3是给模组吐完整个列表留时间,列表长的固件可能要更久,可以按需加到 5 秒。
这一步的意义是建立基线:以后遇到「手册里明明有这条命令,发下去却回 ERROR」,先grep一下基线文件。如果基线里没有,说明这条命令不在你的固件里,不是语法问题;如果基线里有但发下去还是 ERROR,那才是参数或状态问题。这个习惯能省掉大量翻手册的时间。
顺便把版本信息也一起存进基线,后面换模组、换固件的时候有对照:
# 一次抓齐身份信息,作为这台设备的档案 { printf 'AT+CGMI\r'; sleep 0.5; printf 'AT+CGMM\r'; sleep 0.5; \ printf 'AT+CGMR\r'; sleep 0.5; printf 'AT+CGSN\r'; sleep 0.5; } > /dev/ttyFM150 sleep 2 cat /dev/ttyFM150 > fm150_identity.txt每条命令之间留 0.5 秒间隔,是为了不让模组把两条命令的返回混在一起。+CGSN返回的是产品序列号(IMEI),和+CFSN的工厂序列号不是一回事,做资产登记时别填错字段。
4. 把模组注册上网络:SIM、CFUN、APN 与数据拨号
AT 通道通了只是第一步,从「能对话」到「能上网」中间还有 SIM 自检、射频开关、PDP 上下文、拨号四道关。这一章按真实联调顺序走一遍,每道关都给可执行的命令和判断标准。
4.1 SIM 链路自检:先把卡认出来
模组认不到卡,后面所有网络命令都是白费。手册 3.1.13 有+GTUSIM,专门用来检查 USIM 卡状态,配合+CCID读卡号、+CPIN?查 PIN 状态。
AT+GTUSIM? // 查 USIM 卡检测状态,确认卡在位 AT+CCID // 读 ICCID,返回一串 19~20 位数字 AT+CPIN? // 查 PIN 码状态,正常返回 +CPIN: READY AT+CIMI // 读 IMSI,15 位数字,能读出来说明卡被正确识别+CCID和+CIMI这两条是判断卡是否真被读到的硬指标:前者是卡本身,后者是运营商签约信息。两条都能返回正常数值,说明卡座、电平、协议这一整条链路没问题。如果+CPIN?返回+CPIN: SIM PIN,说明卡设了 PIN 码,需要先AT+CPIN="1234"解锁;返回+CPIN: NOT INSERTED就是物理层没接触好。
热插拔相关的两条命令在手册 4.1.7 和 4.1.8:+MSMPD控制 SIM 卡热插拔检测的使能,+SIMSWAPCFG设置热插拔检测的有效电平。载板设计上 SIM 检测脚是高有效还是低有效,必须和+SIMSWAPCFG配的一致,配反了的表现是卡明明插着却报未插入。这块参数别凭感觉,查载板原理图。
双卡场景用手册 4.1.16 的+GTDUALSIM切换。变更记录里明确写了这条命令的「Persistent to yes」,也就是设置会掉电保存,切换完重启仍然有效。这个特性在调试时容易造成困惑——你以为重启会回到默认卡槽,实际上没有。
4.2 射频与功能态:CFUN 和飞行模式
SIM 认到之后开射频。手册 4.1.4 的+CFUN是总开关,+CFUN=1全功能,+CFUN=0最小功能(射频关),+CFUN=4关射频但保持 SIM 供电。联调时我习惯先用+CFUN=4确认 SIM 和串口都正常,再切+CFUN=1开射频,这样能把「卡的问题」和「射频的问题」分开。
AT+CFUN? // 查当前功能态,正常联网时应该是 +CFUN: 1 AT+CFUN=4 // 关射频,保留 SIM 供电,用于隔离排查 AT+CFUN=1 // 全功能,开射频 AT+GTFMODE? // 查硬件飞行模式状态 AT+GTFMODE=1 // 打开硬件飞行模式,射频关闭 AT+CPWROFF // 软关机,关机前建议先执行+GTFMODE(手册 4.1.9)是硬件飞行模式,和+CFUN的软件功能态是两套机制,可能同时存在。射频打不开的时候两条都要查,只看+CFUN会漏。+CPWROFF(手册 4.1.10)是软关机命令,直接断电有概率丢配置,尤其是刚写完持久化参数的时候,先+CPWROFF再断电是稳妥做法。
低功耗相关的还有+SLPMODE(4.1.11)、+GTWAKE(4.1.12)、+GTLPMMODE(4.1.13)、+GTPMTIME(4.1.14)、+WRIM(4.1.15)。做数据透传联调时如果发现「隔一段时间没数据就断」,大概率是进了睡眠,先把+SLPMODE关掉排除掉这个变量,再回头调功耗。
4.3 APN 与 PDP 上下文:+CGDCONT 是根
APN 配不对,+CGATT可能是 1(附着成功)但数据通不了。标准路径是+CGDCONT定义 PDP 上下文,鉴权参数用+CGAUTH或$QCPDPP,厂商私有的+GTMPDN用来增改 PDP 定义。
AT+CGDCONT=1,"IP","cmnet" // 定义 cid=1,PDP 类型 IP,APN 填运营商给的 AT+CGDCONT? // 回读全部上下文,确认 cid 和 APN 没写串 AT+CGAUTH=1,1,"user","pass" // cid=1 使用 PAP 鉴权,填用户名密码 AT$QCPDPP=1,1,"user","pass" // 私有写法,部分固件用这条设鉴权+CGDCONT第一个参数是 cid,第二个是 PDP 类型(IP、IPV6、IPV4V6),第三个是 APN 字符串。cid 不要和已有上下文冲突,先AT+CGDCONT?看一眼占用情况再写。PDP 类型选错的表现是能附着但拿不到地址,IPV4V6在只支持单栈的网络下也会出问题,联调阶段先用IP最稳。
+CGAUTH和$QCPDPP是两条不同路径,前者是标准命令,后者是私有命令。变更记录里$QCPDPP在 V3.6.2 加过、又在 V3.6.3 的某次修订里被删掉、后来$qcrmcall和$qcpdpp又出现在新增列表里。这种反复说明什么?说明不同固件分支上这两条命令的支持情况不一致。所以第 3.4 节用+CLAC建基线这一步在这里就派上用场了:先确认命令在不在,再决定用哪条。
4.4 拨号与数据面:私有命令的版本差异最大
拨号这块是版本差异最集中的地方。手册变更记录里能清楚看到几条命令的反复:
| 命令 | 变更记录里的动作 | 影响 |
|---|---|---|
| +GTAUTODHCP | V3.6.3 早期删除,后又新增 | 自动获取 IP 的行为在不同固件上不一致 |
| +GTAUTOCONNECT | V3.6.3 新增 | 老固件上不存在,发了回 ERROR |
| +GTRNDIS | V3.6.3 修改 | 参数顺序或取值有调整 |
| $QCRMCALL | V3.6.2 新增,cid 描述后改 | 拨号参数含义随版本变 |
| +GTMPDN | V3.6.3 新增 | 私有 PDP 管理,老固件没有 |
这就是为什么我一直强调先看变更记录再看正文。手册正文写的是最新状态,你的固件可能是中间某个版本,两头对不上就会怀疑人生。
常见做法是先走标准路径拨号,不行再上私有命令:
AT+CGATT? // 确认已附着,返回 +CGATT: 1 AT$QCRMCALL=1,1 // 私有拨号,起 cid=1 的数据通道 AT+GTRNDIS=1,1 // 开启 RNDIS 网卡模式,参数以固件为准 AT+GTAUTOCONNECT=1 // 开启自动拨号,重启后自动连 AT+GTAUTODHCP=1 // 自动获取 IP,注意版本差异$QCRMCALL的两个参数大致是「动作」和「cid」,具体取值各固件分支有差异,先用AT$QCRMCALL=?查一次支持的参数范围再发。+GTRNDIS是让模组以网卡形态出现,配合主机的 RNDIS 驱动用;不做网卡模式、走 PPP 的话这条不用发。
+GTAUTOCONNECT和+GTAUTODHCP这一对是给「设备上电就要自动联网」的场景用的,配好之后不用主机发拨号命令。但正因为是自动的,出问题时反而难查——你不知道它什么时候拨的、拨成功没有。调试阶段建议先手动拨通,确认整条链路没问题,最后再开自动,别一上来就开。
4.5 状态轮询:用哪几条命令判断「到底通没通」
联调时最常问的一句话是「现在通了吗」。判断标准不能只看一条命令,我一般按这个顺序看:
AT+CSQ // 信号质量,返回 +CSQ: 20,99 之类,rssi 99 表示无信号 AT+CGATT? // 附着状态,+CGATT: 1 表示已附着 AT+GTSTATIS? // 流量与连接统计,V3.6.3 新增 AT+GTCELLSTATUS? // 服务小区状态,V3.6.3 新增 AT+GTSRVSTATUS? // 服务状态,V3.6.3 新增 AT+GTEPSMOBINFO? // EPS 移动性信息,V3.6.3 新增 AT+GTCAINFO? // 载波聚合信息,V3.6.3 新增+CSQ返回两个值,第一个是信号强度(0~31,99 表示未知或无信号),第二个是误码率。信号强度 10 以下基本别指望稳定传输,先解决天线和位置问题,别在软件上折腾。
后面五条+GT开头的状态命令都是 V3.6.3 才加的,老固件上没有。这正好又是一次版本校验:如果AT+GTSTATIS?回 ERROR 而AT+CLAC里也没有,说明你的固件版本低于 V3.6.3 的某个修订点,状态查询只能退回+CSQ和+CGATT?这两条基础命令。
5. 避坑与排查:五条血泪记录
这一章的五条都是联调现场真实会遇到的,按「现象 → 原因 → 解决」写。遇到问题先对照这里的顺序排查,比从头翻 241 页快得多。
5.1 现象:串口打开正常,敲 AT 一个字符都不回
原因通常有三个层次。最外层是流控:工具默认开了 RTS/CTS,硬件上没接,模组认为主机没准备好,不吐数据。中间层是端口选错:打开的是诊断口或数据口而不是 AT 口,那些口不响应 AT 命令。最内层是模组处于睡眠状态,+SLPMODE开着且没有唤醒信号。
解决顺序:先用dmesg确认插拔时枚举出的端口列表,逐个试AT,找到真正响应 AT 的那个;再用stty -F /dev/ttyXXX -crtscts或工具里关流控;最后查+SLPMODE和+GTWAKE,如果配了睡眠唤醒,需要拉 RI 或 DTR 唤醒再发命令。逐层排除比乱试参数快。
5.2 现象:能回 OK,但 +CGATT? 长期是 0
+CGATT: 0表示未附着,但能回 OK 说明串口和命令解析都没问题,问题在注册链路上。常见原因按概率排:SIM 没被真正识别(+CPIN?不是 READY)、天线没接或接触不良(+CSQ是 99)、射频被关(+CFUN是 0 或 4、+GTFMODE是 1)、APN 写错导致 PDP 激活失败、所在位置没有对应频段覆盖。
排查用二分法:先AT+CPIN?和AT+CCID确认卡,再AT+CSQ确认信号,再AT+CFUN?和AT+GTFMODE?确认射频开着,最后AT+CGDCONT?核对 APN。这四步下来基本能定位到具体哪一环。注意+CFUN=4是关射频但 SIM 供电,这个状态下+CGATT?一定是 0,别把调试时自己设的状态当成故障。
5.3 现象:手册里写着的命令发下去回 ERROR
先别改参数,先确认这条命令在不在你的固件里。用手册 3.1.14 的+CLAC抓一份列表grep一下。如果不在,就是固件版本低于手册版本,这条路走不通,换等效命令或者升级固件。
如果在列表里还是 ERROR,看三种情况:一是命令有前置状态要求,比如没附着就发拨号命令;二是参数格式对不上,AT+XXX=?查一下支持的参数范围;三是这条命令在当前 SIM 或网络下不支持,比如某些运营商网络下私有命令的行为会不同。
还有一种隐蔽情况:命令本身没错,但被上一条命令的残留状态干扰。比如刚发过ATQ1关了结果码,后面所有命令都不回 OK,看着像失败其实成功了。遇到「批量都是 ERROR」先查AT&V或ATQ?看全局设置有没有被改过。
5.4 现象:高频发命令时丢字符、日志串行
现象是返回里偶尔少几个字符,或者两条命令的返回粘在一起。原因基本是两条命令之间间隔太短,模组的命令解析器还没处理完上一条,下一条就进来了。
解决是给命令之间加固定间隔,脚本里每条之间至少 100ms,状态查询类命令给到 300ms 以上。另外确认单条命令的结尾只有一个\r,\r\n\r\n会被当成空命令处理,模组回一个ERROR,混在正常返回里很难发现。
硬件层面也要看:USB 线太长、没有屏蔽、靠近开关电源,都会造成偶发丢字节。换根短线试一次,能排除掉不少玄学问题。
5.5 现象:参数配好当时生效,断电重启就还原
AT 命令的参数持久化行为并不统一。手册变更记录里专门标注了某些命令「Persistent to yes」(比如+GTDUALSIM),说明它掉电保存;没标注的默认不保存,重启回默认值。
解决办法是:查手册里该命令的参数说明有没有持久化标记,没有标记的就在每次上电的初始化流程里重新下发一遍。别指望发一次就永久生效。
另一个坑是直接断电。部分参数写入是异步的,命令回了 OK 只代表收到,不代表写进存储。稳妥做法是改完参数等 1~2 秒,再发AT+CPWROFF软关机,等模组真正关断后再断电。这个习惯能避免很多「明明配了却丢了」的问题。
6. 装完怎么验证:一份能跑通的 12 步自检脚本
人工敲命令验证的问题是容易漏步、容易看错返回值。我习惯写一个 pyserial 脚本,把关键命令串起来跑一遍,每条都给期望值,跑完输出一份通过/失败清单。脚本本身不复杂,价值在于每次换模组、换固件、换载板都能五分钟内给出结论。
#!/usr/bin/env python3 # FM150 AT 指令自检脚本,按联调顺序逐条验证 import serial, time, re, sys PORT = "/dev/ttyFM150" # udev 固定后的软链,换机器不用改 BAUD = 115200 # (命令, 期望出现的正则, 说明) CHECKS = [ ("AT", r"^OK", "基础连通"), ("ATE0", r"^OK", "关闭回显"), ("AT+CGMI", r"\w+", "厂商ID"), ("AT+CGMM", r"FM150|FG150", "型号匹配"), ("AT+CGMR", r"\d+\.\d+", "固件版本"), ("AT+CGSN", r"\d{15}", "IMEI 15位"), ("AT+CCID", r"\d{18,20}", "ICCID"), ("AT+CPIN?", r"\+CPIN:\s*READY", "SIM 就绪"), ("AT+CSQ", r"\+CSQ:\s*(?!99)\d+", "信号非99"), ("AT+CFUN?", r"\+CFUN:\s*1", "射频全功能"), ("AT+CGATT?", r"\+CGATT:\s*1", "已附着"), ("AT+CGDCONT?", r"\+CGDCONT:", "PDP 上下文存在"), ] def send(ser, cmd, wait=0.5): ser.reset_input_buffer() ser.write((cmd + "\r").encode()) # 结尾只发 \r,不要 \r\n time.sleep(wait) # 给模组处理时间,状态类命令可加长 return ser.read(ser.in_waiting or 1).decode(errors="ignore") def main(): ser = serial.Serial(PORT, BAUD, timeout=2, rtscts=False, dsrdtr=False) # 显式关流控 failed = [] for cmd, pattern, desc in CHECKS: resp = send(ser, cmd) ok = re.search(pattern, resp, re.M) is not None print(f"[{'PASS' if ok else 'FAIL'}] {desc:<12} {cmd:<16} -> {resp.strip()[:60]}") if not ok: failed.append((cmd, desc, resp.strip())) ser.close() print(f"\n通过 {len(CHECKS)-len(failed)}/{len(CHECKS)}") sys.exit(1 if failed else 0) if __name__ == "__main__": main()脚本逻辑有几处值得说明。rtscts=False和dsrdtr=False是在串口层显式关流控,比依赖工具默认值可靠;ser.write((cmd + "\r").encode())只发单个\r,避免多余空行被当成错误命令;ser.reset_input_buffer()在每条命令前清一次接收缓冲,防止上一条的残留数据污染判断。
CHECKS表里的正则都是宽松匹配,因为不同固件的返回格式在细节上有差异,比如+CSQ后面可能有空格也可能没有。(?!99)这个负向断言专门用来排除「有信号字段但值为 99(无信号)」的假通过,这是最容易被误判的一条。
执行顺序是有讲究的:AT和ATE0打底,然后身份信息、SIM、信号、射频、附着、PDP 逐层往上。任何一层 FAIL,后面的结果都不可信,先修前面那层再看后面。
12 条全过之后,还有两条建议手工确认一次,脚本不太好判:
| 确认项 | 命令 | 判断标准 |
|---|---|---|
| 数据面是否真的通 | AT$QCRMCALL=1,1后主机侧ping | 能拿到地址且能通外网 |
| 持久化是否生效 | 配完参数后AT+CPWROFF再上电 | 关键参数仍是配置值 |
我把这套脚本放在工程目录里,每次换载板、升级固件、改 APN 都先跑一遍,跑通了再动业务代码。从那以后我每次上电联调都强制走一遍这 12 条,再没出现过「以为通了其实没通、查了两小时发现是 SIM 没插好」这种低级返工。希望帮到你。
本文还有配套的精品资源,点击获取