
一直做单片机项目的朋友应该都有这种感觉设备一旦离开实验室网络问题就变得特别现实。我之前接了一个远程设备监控的活儿现场没有 WiFi只有 4G 信号于是开始认真评估怎么做联网。查了一圈最后落到了这块 SIM7600G-H CAT4 4G (LTE) Shield for Arduino 上它把 SIMCom 的 SIM7600G-H 模组、SIM 卡座、天线座、电源管理、串口电平转换都集成到了一块标准 Arduino 扩展板上插上 UNO 或者 Mega 就能用。整个项目的核心就变成了“通过串口发 AT 指令”对单片机开发者来说几乎是零门槛。这篇文章就把我从选型、硬件接线、AT 指令调通到写一个带数据上报和指令下发的完整流程整理出来特别是供电和网络注册这些坑希望能帮你少走弯路。1. 为什么选 SIM7600G-H CAT4 4G Shield 作为 Arduino 联网方案1.1 SIM7600G-H 是一颗什么样的 4G 模组SIM7600G-H 是 SIMCom 旗下的 LTE Cat 4 模组支持 LTE-FDD、LTE-TDD、HSPA、GSM/GPRS/EDGE 这些网络制式频段覆盖非常广比较常见的 LTE-FDD 频段 B1/B2/B3/B4/B5/B7/B8/B12/B13/B18/B19/B20/B25/B26/B28以及 LTE-TDD 的 B38/B39/B40/B41 都在支持范围里同时还内置 GNSS可以输出 GPS/北斗/GLONASS 定位结果。理论上行速率 50Mbps下行 150Mbps对 Arduino 这种串口带宽根本跑不满但好处是响应快、覆盖好后期如果要升级成传输图片或者做远程固件下发也不会被网络带宽卡住。很多朋友会问为什么不用 NB-IoT 或者 Cat.1这个我后面单独说。单就这块 Shield 而言它已经把模组本身最难搞的射频部分也就是天线阻抗匹配、叠层走线、ESD 防护这些全处理好了用户只需要把 SIM 卡插好、天线接上、串口连上剩下的全是逻辑问题。我自己之前也试过自己画 4G 模组的最小系统PCB 打样回来光搜网就花了两天最后发现是天线馈线附近的地没处理好。所以如果目标是快速做产品原型或者项目验证直接用这种 Shield 是最划算的。1.2 CAT4、CAT1、NB-IoT 到底怎么选关于通信制式的选择我做了个表格方便直接对比参数NB-IoTLTE Cat.1LTE Cat.4典型下行速率几十 kbps约 10Mbps150Mbps典型上行速率几十 kbps约 5Mbps50Mbps语音通话不支持支持 VoLTE支持 VoLTE模块成本较低中等偏高网络延迟较高适中低适合场景水电表、停车、传感器低速上报共享设备、POS、追踪器视频传输、高频率数据采集、远程桌面我的判断标准很简单如果产品只上报几个字节一天一次NB-IoT 真的够用如果要频繁上报、延迟要低还要兼顾未来固件升级包下载Cat.1 是性价比之选而像我现在这个项目不光要上报传感器数据还要偶尔下传几十 K 的配置文件更重要的是需要全国范围稳定漫游Cat.4 显然更稳。再加上 SIM7600G-H 在国内主流运营商网络下都有完整频段支持所以选它基本是“一次到位”的方案。1.3 用 Shield 而不是自己搭模组电路自己做 4G 电路最大的问题是射频和电源。LTE 的射频走线有严格的阻抗要求天线位置、馈线长度、地平面切割都会影响灵敏度别说是新手就算有点 RF 经验的工程师也不敢保证一版搞定。另外 4G 模组发射时瞬态电流很容易冲到 2A板子上的 DC-DC 电路、大电容、电源布局如果不合理就会导致模组反复重启。Shield 的形态把这些问题全部屏蔽掉了你只需要关心“供电电源能不能提供足够电流”和“串口电平是否匹配”这两点我会在下一节详细讲。2. 到手后的硬件准备与首次上电2.1 板卡接口、跳帽和串口通道选择拿到 Shield 以后先别急着插 Arduino先看清楚板子上的主要插座和跳帽。通常会有 DC 电源输入口、USB 接口用于直接连接电脑调试、4G 天线 SMA 座、GNSS 天线 SMA 座、SIM 卡座、UART 排针、PWRKEY 按键/排针以及控制串口通道选择的跳帽。不同厂商的 Shield跳帽定义会有区别。我用的这块是默认通过排针连接 Arduino UNO 的数字口 D2/D3 作为软串口如果你用 Mega可以拨到硬件串口 Serial1。上电之前一定要确认跳帽位置否则会出现“串口没反应”的假故障。我的习惯是先看原理图或者丝印把跳帽对应通道记下来再上电避免反复插拔。2.2 供电最容易翻车的环节这句我要说得非常绝对不要指望 Arduino UNO 的 5V 引脚能直接带动 4G Shield。Arduino UNO 的 5V 来自 USB 或者板载稳压器在 USB 供电时满打满算也就 500mA而 SIM7600G-H 在注册网络、发送数据时峰值电流能到 1.5A 甚至 2A电压一跌模组就会反复重启或者表现为 CSQ 信号极差、AT 无响应。后者的迷惑性很大很多人以为是天线问题其实是供电问题。正确的做法是用 5V/2A 以上的适配器从 Shield 的 DC 电源口单独供电。如果现场只有 12V 电源也可以从 Arduino 的 DC 口进让 Arduino 的板载电路先降到 5V再由 Shield 二次处理但注意 Arduino 的稳压芯片持续供 2A 会很烫不建议长期跑。我实测最省心的方案是实验室那套 5V/3A 直流电源或者找一个质量好点的 5V/2A USB 适配器直接怼到 Shield 的电源口Arduino 再单独供电或由 Shield 的电源输出供给。另外在首次通电前一定要先把 4G 天线接上。空载不接天线不仅是信号差的问题长期空载还可能损坏射频前端。GNSS 天线如果暂时不用可以不接但 4G 主天线必须接。2.3 SIM 卡安装与第一次开机SIM 卡建议用 4G 物联网卡或者运营商正常开通了数据业务的手机卡。插卡时把缺口对准卡座的斜角方向用力推到底听到清脆“咔嗒”声才算到位。常见的问题是 SIM 卡没完全插入导致 ATCPIN? 一直返回 ERROR 或者提示 SIM not inserted。开机有两种方式一种是直接按板上的 PWRKEY 键按住 100ms 到 500ms另一种是用 Arduino 的 GPIO 控制 PWRKEY 引脚拉低几百毫秒再释放。我用 Arduino 控制时写了一个软开机函数上电后先启动串口再拉低 PWRKEY 引脚启动模组。开机后观察指示灯一般 NETLIGHT 慢闪表示正在搜网快闪表示已经注册到网络不同厂商的 Shield 指示逻辑可能略有差异最好翻一下对应的手册。2.4 Arduino IDE 环境准备与扩展板适配SIM7600G-H Shield 不需要额外的 Arduino 库它就是一个串口设备所以环境准备的核心是 Arduino IDE 本身。我用的是 1.8.19稳定性比 2.x 在部分老电脑上好很多如果你遇到 IDE 打不开的问题可以先切回 1.8.x。开发板选择 Arduino UNO 或者 Mega然后在项目里加载 SoftwareSerial 库即可。如果后续想把主控换成 ESP32要注意 ESP32 的 UART 电平是 3.3V而一些 Shield 的 UART 可能按 5V 电平设计了需要确认是否支持 3.3V 输入或者加电平转换。用 ESP32 时可以直接用 Serial2 硬件串口连接 Shield具体代码我会在第 4 节后面提一下。3. 用 AT 指令打通 4G 数据链路3.1 串口连接与基本通信首次调试 4G Shield 时我强烈建议先用 USB 线把 Shield 直接连电脑用串口助手发 AT 指令这样排查问题最快。等指令流程全部跑通了再换回 Arduino 控制。如果你直接用 Arduino 发指令建议先用最简单的透传程序#include SoftwareSerial.h SoftwareSerial sim(8, 7); // RX, TX void setup() { Serial.begin(115200); sim.begin(115200); delay(1000); sim.println(AT); } void loop() { if (sim.available()) Serial.write(sim.read()); if (Serial.available()) sim.write(Serial.read()); }这里有个细节SoftwareSerial 的 RX 引脚要接 Shield 的 TXTX 引脚接 Shield 的 RX交叉连接不要接反。如果你的 Arduino 是 Mega建议用硬件串口 Serial1因为 SoftwareSerial 在 115200 波特率下容易丢字节除非把波特率降到 9600 或 57600。第一次通信如果出现乱码优先检查波特率是否和 Shield 默认一致一般默认 115200。3.2 检查 SIM 卡、信号和网络注册状态模组开机并连接串口后按顺序执行这几条指令AT ATE0 ATCPIN? ATCSQ ATCREG?逐条解释一下实际意义AT握手返回 OK 就说明串口链路通了。ATE0关闭回显否则后面指令看得心累。ATCPIN?检查 SIM 卡状态返回 CPIN: READY 表示卡已准备好如果返回 ERROR大概率是卡没插好或卡没开卡。ATCSQ查询信号强度返回两个数字比如 CSQ: 18,99第一个数字范围 0-31越大信号越好一般大于 12 就能正常联网第二个 99 表示误码率未知不用管。如果长期返回 0 或者 99先检查天线和电源。ATCREG?网络注册状态返回 CREG: 0,1 表示注册到归属网络0,5 表示漫游0,3 表示网络拒绝。我测试时遇到过一次比较奇怪的情况CSQ 有 20但 CREG 一直返回 0,2正在注册中排查半天发现是 SIM 卡的 APN 没有配置虽然注册和 APN 不完全是一回事但物联卡的套餐状态也会影响注册结果。后来换了正确的 APN 并激活 PDP 上下文后CREG 马上变 1。3.3 配置 APN 并激活 PDP 上下文4G 拨号最核心的一步是在模组上定义 PDP 上下文。不同运营商、不同物联网卡的 APN 都不一样常见的有 cmnet、cmiot、ctnb 等具体要问卡商。配置指令如下ATCGDCONT1,IP,你的APN ATCGACT1,1 ATCGATT?ATCGDCONT1,IP,APN定义编号为 1 的 PDP 上下文协议类型 IPv4APN 按实际替换。ATCGACT1,1激活这个上下文如果返回 OK说明拨号成功。ATCGATT?查询是否附着到 GPRS/LTE 网络返回 CGATT: 1 就是已经附着。这一步如果返回 ERROR先执行 ATCGDCONT? 查看当前上下文确认是否本来就有残留配置有的话先 ATCGDCONT1 删除再重建。另外不要小看 APN 这个问题我之前用一张测试卡卡商给的文档里写的是自定义 APN结果我一路默认 cmnet怎么都激活不了换了自定义 APN 之后秒成功。3.4 用 HTTP 指令完成一次真实的数据上报网络打通以后最直接的应用就是 HTTP 上报。SIM7600 系列通常有传统 HTTPAT 指令和简化版 HTTPCLIENT 指令。传统流程比较繁琐但兼容性好ATHTTPTERM ATHTTPINIT ATHTTPPARACID,1 ATHTTPPARAURL,http://your-server.com/api/upload ATHTTPPARACONTENT,application/json ATHTTPDATA64,10000ATHTTPDATA 后面两个参数分别是要发送的 JSON 数据长度字节和等待数据的超时时间毫秒。执行后模组会返回一个提示符此时把 JSON 数据一次性发过去比如{device:sim7600,temp:25.6}发送完成后模组返回 OK接着执行ATHTTPACTION1HTTPACTION 的参数 1 代表 POST 请求0 是 GET2 是 HEAD。这条指令会阻塞直到服务器响应返回的格式类似HTTPACTION: 1,200,24其中 200 就是 HTTP 状态码24 是响应体长度。最后用 ATHTTPREAD 读取服务器返回内容。如果你手里的固件版本比较新可以使用更简洁的 ATHTTPCLIENT 指令一条命令就能完成 GET 请求。POST 也可以但要注意 JSON 里的引号需要转义。我建议优先用传统 ATHTTPINIT 流程因为网上能找到的参考多问题排查也容易HTTPCLIENT 虽然短但不同固件对参数的解析差异比较大。3.5 用 Arduino 实现一个 60 秒心跳上报把上面的 AT 指令封装成 Arduino 函数就可以做一个最小的心跳程序。核心思路是初始化串口 - 启动模组 - 等待 CPIN READY - 配置 APN - 激活 PDP - 每 60 秒执行一次 HTTP POST。我写了一个精简版供参考#include SoftwareSerial.h SoftwareSerial sim(8, 7); const char apn[] cmiot; const char url[] http://your-server.com/api/heartbeat; void sendAT(const char* cmd, unsigned long wait 2000) { sim.print(cmd); sim.print(\r\n); unsigned long t millis(); while (millis() - t wait) { while (sim.available()) Serial.write(sim.read()); } } void setup() { Serial.begin(115200); sim.begin(115200); pinMode(9, OUTPUT); digitalWrite(9, HIGH); delay(1000); digitalWrite(9, LOW); // PWRKEY 拉低启动模组 delay(500); digitalWrite(9, HIGH); delay(5000); // 等模组启动 sendAT(AT); sendAT(ATE0); sendAT(ATCPIN?); sendAT(ATCSQ); sendAT(ATCGDCONT1,\IP\,\cmiot\); // 改成你的 APN sendAT(ATCGACT1,1); } void loop() { sendAT(ATHTTPTERM); sendAT(ATHTTPINIT); sendAT(ATHTTPPARA\CID\,1); sendAT(ATHTTPPARA\URL\,\http://your-server.com/api/heartbeat\); sim.println(ATHTTPACTION0); delay(8000); sendAT(ATHTTPREAD); delay(60000); }这个代码只做演示实际项目需要解析 AT 指令的返回值不能像这样只发送不校验。我写代码时习惯把每个 AT 步骤封装成“发送-等待-断言返回值”的函数比如expectOK()这样可以快速定位故障在哪一步。4. 实战案例温湿度远程监控与指令下发4.1 项目需求与硬件连接这批项目要做的是室外设备箱里的温湿度实时监测设备没有网线只能走 4G云端平台需要每 5 分钟看到一次数据同时支持远程下发一个“重启设备”的指令。最终的硬件清单是Arduino UNO 一块SIM7600G-H CAT4 4G (LTE) Shield for Arduino 一块DHT22 温湿度传感器一个数据脚接 D45V/3A 电源适配器一个继电器模块一个控制被监控设备供电控制脚接 D6连接时注意 DHT22 的 VCC 接 5VGND 接 GNDDATA 接 D4并在 DATA 与 VCC 之间接一个 10k 上拉电阻。继电器模块的 VCC 接 Arduino 5VGND 接 GNDIN 接 D6。整块板子的电源由 5V/3A 适配器从 Shield 电源口进入Shield 再给 Arduino 供电这样从上电顺序上就保证了 4G 模组优先拿到足够的电流。4.2 数据上报协议设计上报数据我用了 JSON简单明了服务器端和调试时都容易看。格式如下{device_id:box001,type:env,temp:26.3,humi:58.2}服务器处理完上报请求后返回一个 JSON告诉设备有没有待执行的指令{cmd:reboot,param:0}设备解析到 cmd 字段是 reboot就拉高继电器引脚断开设备电源 5 秒再重新闭合。这个“服务器下行指令”的设计其实包含在上报的响应里避免了 Arduino 端做 TCP 长连接资源占用小逻辑也简单。对延迟要求不高的控制类场景这种“轮询响应”的模式非常实用。4.3 Arduino 端核心代码与关键注释核心代码分成三个部分DHT22 采集、SIM7600G-H 初始化、上报与指令执行。我先说初始化部分因为这部分对稳定性影响最大。我封装了一个waitForReady函数循环发 AT 直到模组返回 OK超时 10 秒就报错这样可以避免上电时序不稳定导致的偶发失败。上报部分我做了数据长度动态计算因为 ATHTTPDATA 需要知道 JSON 长度。注意不要直接用 Arduino 的 String 类拼接超长字符串UNO 内存只有 2KB稍微复杂点的 JSON 就爆了。建议用 snprintf 拼到 char 数组里再算 strlen 传给 HTTPDATA。下面是节选代码#include SoftwareSerial.h #include DHT.h SoftwareSerial sim(8, 7); DHT dht(4, DHT22); char apn[] cmiot; char server[] http://your-server.com/api/upload; void sendCommand(const char* cmd, const char* expect, unsigned long timeout) { sim.print(cmd); sim.print(\r\n); unsigned long t millis(); char buf[64] {0}; int idx 0; while (millis() - t timeout) { while (sim.available()) { char c sim.read(); buf[idx] c; if (idx 63) idx 63; } } if (strstr(buf, expect) NULL) { Serial.print(FAIL: ); Serial.println(cmd); } } void setupModule() { pinMode(9, OUTPUT); digitalWrite(9, HIGH); delay(800); digitalWrite(9, LOW); delay(600); digitalWrite(9, HIGH); delay(6000); sendCommand(AT, OK, 3000); sendCommand(ATE0, OK, 2000); sendCommand(ATCPIN?, READY, 5000); sendCommand(ATCSQ, OK, 2000); sendCommand(ATCGDCONT1,\IP\,\cmiot\, OK, 3000); sendCommand(ATCGACT1,1, OK, 8000); sendCommand(ATCGATT?, 1, 3000); }完整代码不在这里全贴但结构就是“采集 - 拼 JSON - HTTP POST - 读响应 - 解析 cmd - 执行动作”。我建议你在 PC 串口助手上先把 AT 指令流程跑一遍再烧进 Arduino会发现调试效率高很多。4.4 从云端下发指令的实现细节因为我选择了“轮询响应”方案服务器端只需要在收到 POST 请求返回时携带指令。Arduino 端解析响应时我用了一个简单的字符串查找比如找到cmd:reboot就执行重启逻辑。这种解析方式不严谨但项目够用。如果你有多个指令建议用 JSON 解析库比如 ArduinoJson但注意 UNO 内存有限选 5.x 版本并且配置好缓存大小。指令执行我做了两层保护第一层判断响应的 HTTP 状态码是不是 200否则不做任何动作第二层只在连续两次上报都返回同一个非空指令时才执行避免网络瞬时干扰造成误动作。4.5 如果换成 ESP32 该怎么做项目做到后面客户提了一个需求能不能在设备端缓存 24 小时的历史数据方便断网时本地存储。Arduino UNO 的 Flash 和 RAM 都不够我就把主控换成了 ESP32。硬件连接上ESP32 的 UART2 接 ShieldGPIO16 作为 RX 接 Shield 的 TXGPIO17 作为 TX 接 Shield 的 RX如果是 3.3V 的 Shield 没问题否则中间加电平转换。核心代码里只需要把 SoftwareSerial 换成 Serial2初始化方式如下Serial2.begin(115200, SERIAL_8N1, 16, 17);其他的 AT 指令流程完全复用。ESP32 的好处是可以用多个任务一个任务跑网络上报一个任务跑传感器轮询还能用 SPIFFS 存储断网数据整体架构会舒服得多。5. 常见问题与排查技巧实录5.1 模块不启动指示灯不亮遇到这种情况先不要怀疑模块坏了我统计下来 90% 是电源问题。检查顺序如下供电电源是否真的插在 Shield 的 DC 口而不是 Arduino 的 USB 口。电源是否达到 5V/2A很多廉价 USB 适配器标称 2A实际带载就掉压。PWRKEY 是否按够时间如果用手动按键至少按 1 秒再松开如果用 Arduino 控制拉低时间不要小于 500ms。如果所有电源都没问题把 Shield 单独接 USB 到电脑看有没有新增串口设备。如果 USB 枚举都失败可能是板子硬件问题。5.2 串口有输出但 AT 无响应或乱码AT 完全无响应最常见的是 TX/RX 接反。Shield 的 UART 排针丝印一般是 “TXD” 和 “RXD”Arduino 的 TX 接 Shield 的 RXDArduino 的 RX 接 Shield 的 TXD。很多人习惯按引脚名“同名相连”结果弄反了。乱码的情况主要分两种一种是波特率不对SIM7600G-H 默认 115200但也有厂商改成了 9600另一种是电平不匹配部分 Shield 的串口是 3.3V 逻辑Arduino UNO 的 5V 逻辑直接接进去可能造成识别异常这时候最好加一个双向电平转换模块。5.3 信号差、CSQ 低、搜不到网先说结论搜不到网优先怀疑天线信号差优先怀疑电源。具体排查步骤确认 4G 天线已接好并且尽量远离金属外壳和 Arduino 板上的排针排母。确认 SIM 卡已开通 4G 数据业务物联网卡还要确认套餐没有停机。用 ATCOPS? 查看当前运营商如果返回运营商名称说明已经注册如果返回空可以试 ATCOPS0 让它自动选网。在室内调试时信号经常只有一格可以把天线放在窗边或者换成吸盘天线延长馈线到室外。我之前踩过一个很隐蔽的坑Shield 上同时有 LTE 主天线和分集天线两个座我误把 GNSS 天线当主天线插上结果 CSQ 只有 5换成配套的 LTE 天线后马上到了 18。5.4 HTTP 请求超时或一直返回错误HTTP 请求失败时先按顺序检查基础状态ATCGATT? 是否返回 1如果没有说明还没附着到 LTE 网络先解决上网问题。ATCGACT? 是否返回 1PDP 上下文没激活的话 HTTP 肯定起不来。如果确认网络已激活可以用 ATHTTPPARAURL,http://8.8.8.8 这种纯 IP 的地址做测试排除 DNS 解析问题。域名测试 OK但 HTTP 超时检查服务器是否允许公网访问80/8080 端口是否通。还要强调一点ATHTTPDATA 发送数据时长度参数必须准确如果你告诉模组要发 64 字节实际只发了 60 字节它就会一直等着直到超时。我建议在代码里用 snprintf 后立刻计算 length不要手动换算。5.5 GNSS 定位一直无数据如果这个项目需要定位一定要分清 GNSS 天线和 4G 天线不能混用。GNSS 天线有源供电通常需要模组的 GNSS 天线馈电引脚供电Shield 上一般已经处理好。冷启动状态下在室内基本定不了位需要靠近窗户或者室外空旷处等待时间 1-3 分钟。常见的 AT 指令是ATCGNSPWR1 ATCGNSSINF其中 CGNSSINF 返回的是 NMEA 语句或者解析后的坐标格式取决于固件版本。如果一直不返回先确认天线是否接对再用 ATCGNSSPWR0 关闭电源重启后重新打开。5.6 常见问题速查表我把上面这些经验整理成一张表方便现场照着查现象可能原因解决方法模块无指示灯供电不足/未上电换 5V/2A 电源单独供电AT 无响应TX/RX 接反/跳帽错交叉连接核对跳帽串口乱码波特率/电平不匹配统一 115200加电平转换CSQ 低天线未接/供电跌落接好天线加强供电CPIN 报 ERRORSIM 卡未插好重插卡并检查触点数据业务无法激活APN 配错联系卡商核对 APNHTTP 超时PDP 未激活/DNS 故障先查 CGATT/CGACT再用 IP 测试GNSS 无数据天线接错/环境遮挡换 GNSS 天线窗边冷启动关于这套方案我自己在项目里最深的体会是4G 模块不是“单片机外设”那种简单的芯片它有自己的电源时序、网络状态机和协议栈所以调试时不要怕慢一步一步用串口助手把 AT 指令流程跑透再移到 Arduino 上看起来绕路实际是最快的路径。如果你也想用 SIM7600G-H CAT4 4G (LTE) Shield for Arduino 做联网项目我的建议是前期别急着写代码先把手上的卡、天线、电源这三样基础条件确认到位后面所有问题都会简单很多。