简介:面向STM32F4系列开发者的EC20模块TCP透传模式通信工程示例,解决微控制器通过AT指令建立套接字连接并透明收发数据的常见需求。资源适合有一定嵌入式基础、正在调试无线通信模块的开发者,也适合作为物联网终端联网功能的学习参考。压缩包共174个文件、约4.06MB,以C语言源码、头文件、Keil工程文件、编译产物和批处理脚本为主要类型,目录结构完整,便于直接查看、编译或二次修改。已有1347人学习下载。工程除通信逻辑外,还包含定时器、复位时钟、模数转换、闪存、控制器局域网等标准外设库驱动源码;通过源码可以梳理串口初始化、网络附着、上下文激活、建立连接、数据收发、错误监测与关闭连接等关键流程,能够帮助读者深入理解EC20与STM32F4的协作方式,并为后续扩展功能提供可运行的工程基础。 最近在帮朋友调一块基于EC20的物联网主板,需求很直白:设备通过串口发数据,远端服务器能实时收到,服务器下发指令设备也能秒回。一开始想省事,用AT指令一条条去怼,结果发现稍微复杂一点的交互就非常别扭——数据帧要转义、响应要解析、多包还要拼接。后来老老实实把EC20切到TCP透传模式,才发现这事本该这么干:模块把串口收到的所有字节原封不动丢到TCP链路里,服务器下发的内容也直接从串口吐出来,MCU眼里这就是一根“网线”。这篇文章就把我在实际项目中配置EC20 TCP透传模式的全过程、AT指令细节、接线注意事项,以及几个特别容易踩的坑全部理一遍,给正准备用4G模组做数据透传的工程师一点参考。
1. 透传模式到底解决了什么问题
1.1 从AT指令模式到透传模式的思维切换
很多第一次用EC20的朋友,习惯性做法是:上电初始化,等模块注册网络,然后用AT+QIOPEN建立TCP连接,接着在业务代码里用AT+QISEND一条条发数据,用AT+QIRD或+QIURC主动通知去收数据。这套逻辑没错,AT指令模式适合“控制为主、数据为辅”的场景,比如发短信、查信号、改APN之类的操作。
但一旦业务变成“持续双向收发数据”——比如传感器每隔几秒上报一次、平台随时可能下发控制指令——AT指令模式的缺点就全暴露了:数据封装成AT命令帧有额外的头尾开销;模块收到TCP数据时是通过URC通知的,MCU要时刻处理主动上报的串口字符流,跟自己的业务逻辑穿插在一起;发送长数据时还要考虑AT+QISEND的返回值,失败要重发,代码写起来非常啰嗦。
透传模式的设计思路完全不同:EC20在TCP连接建立之后,从AT命令模式切换到一个“完全透明”的数据通道。MCU串口发出的每一个字节,模块不做任何解析,直接通过TCP发给服务器;反过来,服务器下发的TCP数据,模块也原样从串口吐出来。对MCU来说,这就是一个串口转以太网的桥,你不需要关心TCP/IP怎么封装,只需要处理自己的业务协议。
1.2 什么项目适合选透传,什么项目不适合
我个人的判断标准很简单:看看你的数据流是“请求-响应”还是“持续双向”。
如果每次交互都是MCU先发一条查询,然后等待一个明确的应答,AT指令模式问题不大。像Modbus TCP网关那种应用,用AT指令模式反而更好做协议帧的边界控制。这类场景用透传模式,应答和主动上报混在一起,反而需要自己加帧头和帧尾去区分。
但如果你的业务是:设备端定时上报状态、平台随时下发参数、或者跟MQTT broker打交道——透传模式是绝对正确的选择。MQTT的报文本身就有自己的包头格式,TCP层只是搬运工,透传模式下MCU只需要按MQTT报文格式封装好,丢给串口就行。我用EC20接阿里云MQTT时就是这么干的,爽快得多。
另外还要注意,EC20的透传模式只支持TCP client,也就是模块主动去连接远端服务器。如果业务需要外部设备主动连进来,那要另想办法,比如做反向连接,或者干脆换方案。
2. 硬件接线与基础准备
2.1 EC20核心引脚和模块选型
移远EC20是一款LTE Cat 4模组,支持最大下行150Mbps、上行50Mbps,覆盖FDD-LTE/TDD-LTE/WCDMA/GSM频段。市面上大部分是LGA封装的EC20CE,硬件设计时至少要引出这些引脚:
| 功能 | 引脚/接口 | 说明 |
|---|---|---|
| 串口 | MAIN_TXD / MAIN_RXD | 主串口,AT指令和数据都走这里 |
| USB口 | USB_BOOT / USB_DM / USB_DP | 可以用于调试和固件升级,量产不必接 |
| 开关机 | PWRKEY | 拉低一定时间触发开机 |
| 复位 | RESET_N | 低电平复位 |
| SIM卡 | SIM_VCC / SIM_DATA / SIM_CLK / SIM_RST | 标准SIM卡座接口 |
| 状态指示 | NET_STATUS / STATUS | 网络状态和运行状态 |
| 电源 | VBAT_BB / VBAT_RF | 模组主供电,3.4V~4.3V,推荐4V左右 |
调试阶段最简单的方式是买一块EC20开发板,板子自带USB转串口、SIM卡座、天线座,直接USB供电就能用。自己画板子就注意一个事:模块的峰值电流能到2A以上,电源LDO或DC-DC必须能扛得住瞬时大电流,否则模块会反复重启。
2.2 串口连接和电平匹配
EC20的IO电平默认是1.8V,但很多MCU是3.3V或5V电平。开发板一般已经做好了电平转换,直接接USB转TTL小板就行。如果是自己画的板子,串口一定要加电平转换芯片,常见选择是TXS0108EPWR或者分立的MOS管电平转换电路。这里最容易出的问题就是:模块的TXD电平到MCU的RXD没问题,但是MCU的TXD发出去的电平3.3V或5V直接怼到模块的RXD,轻则数据乱码,重则烧IO口。
串口波特率默认是115200,初始化时我习惯先用115200调通,再在量产固件里改成9600,降低长线干扰概率。要注意的是,EC20的AT指令串口波特率是可以配置的,配置命令是AT+IPR=115200。一旦设置过非默认波特率,以后每次上电都按新波特率工作,忘记这一点很容易以为模块坏了。
2.3 SIM卡与天线的基础要求
透传模式对SIM卡的要求只有一个:能正常附着网络并拿到IP地址。但有几个坑要提前说:
- SIM卡别用剪卡,边缘毛刺容易导致接触不良,最好用正规卡托;
- 天线要接好再上电,不接天线虽然也能注册网络,但信号会很差,TCP连接建立后极不稳定;
- SIM卡欠费停机会导致附着失败,检查注册状态时先确认余额。
3. TCP连接建立的AT指令配置全流程
3.1 开机、注册网络、查询信号,一个都不能少
模块上电之后,我先做一个标准三步检查,确认模块和网络都处于健康状态。
第一步,验证串口通信正常。发送AT,返回OK。如果不返回,优先检查波特率、串口接线、模块是否已正常开机。
第二步,等模块注册网络。发AT+CREG?,返回+CREG: 0,1,中间的第二位为1表示已注册home网络,为5表示漫游,为0表示还没注册。
第三步,确认SIM卡和APN。发AT+CGATT?,返回+CGATT: 1说明已附着GPRS/LTE网络。如果返回0,检查AT+APN?或通过AT+QICSGP配置APN。
注意:国内运营商的APN一般不需要手动设置,SIM卡里自带,但部分物联网卡需要手动指定,尤其是有些卡用的是公共APN(如
cmiot),不设置会导致连不上网。
3.2 配置TCP协议栈上下文
使用EC20内置TCP/IP协议栈前,必须先把PDP上下文配好。这里我用的是移远推荐的配置方式:
AT+QICSGP=1,1,"cmnet","","",1参数含义依次是:contextId为1、协议类型为IPv4、APN为cmnet、用户名密码为空、认证方式为PAP(1)。如果用的是物联网卡或企业卡,APN按运营商给的填。
用AT+QICFG可以查看和配置TCP/UDP相关的参数,比如连接超时时间、TCP数据接收模式等。默认的就行,不太需要动。
3.3 连接服务器:AT+QIOPEN的正确打开方式
建立TCP连接的命令是AT+QIOPEN=<contextID>,<connectID>,<service_type>,<IP>,<port>[,<local_port>[,<access_mode>]]。
我实际用的命令长这样:
AT+QIOPEN=1,0,"TCP","111.222.111.222",8080,0,0参数说明:
contextID:1,对应前面配置的PDP上下文;connectID:0,这是socket的编号;"TCP":服务类型;- IP和端口根据实际服务器填;
access_mode:0表示直接模式(即AT指令模式),1表示透传模式。
这里有个细节:很多人以为先要AT+QISWTMD=1切到透传模式,再连接服务器。实际操作上应该先建立连接,再切换模式。我就是先把access_mode设为0建连,确认链路通畅后再切透传。
命令发送后,模块会返回:
CONNECT OK然后紧接着返回一条URC:
+QIOPEN: 0,0两个字段分别是connectID和错误码,0表示成功。
如果返回+QIOPEN: 0, 207这种非0错误码,参考移远手册,201是参数错误,203是网络异常,206是连接超时,207是路由错误。看到207先检查是不是SIM卡没有附着网络,或者APN配置不对。
3.4 进入透传模式:AT+QISWTMD和AT+QICFG的配合
要启动透传,执行AT+QISWTMD=1,模块返回OK之后,后面再发数据就直接进TCP链路了。
等下,这里有个容易晕的点:AT+QISWTMD=1只是设定了透传模式,但要让模块真正开始透传,还需要再发一个CONNECT一样的“握手”吗?不是的,实测是这样:执行AT+QISWTMD=1返回OK以后,模块会立刻进入透传状态,此时MCU发往串口的所有数据都被当作业务数据发送。如果你不希望设置完就立刻进透传,还有一种两段式用法——AT+QIMODE?查询当前模式,在代码里主动控制切换时机。
我实际项目里的初始化伪代码是这样:
// 1. 基础AT握手 send_cmd("AT\r\n", "+CREG", 1, 100); // 2. 等待网络注册 send_cmd("AT+CREG?\r\n", "+CREG: 0,1", 30, 1000); // 3. 配置PDP上下文 send_cmd("AT+QICSGP=1,1,\"cmnet\",\"\",\"\",1\r\n", "OK", 1, 300); // 4. 建立TCP连接 send_cmd("AT+QIOPEN=1,0,\"TCP\",\"SERVER_IP\",PORT,0,0\r\n", "+QIOPEN: 0,0", 60, 500); // 5. 进入透传 send_cmd("AT+QISWTMD=1\r\n", "OK", 1, 200); // 6. 进入透传后,串口直接透传业务数据这套流程我测了很稳,不过AT+QIOPEN建立连接时,模块返回CONNECT OK和+QIOPEN: 0,0的顺序在不同固件版本下可能颠倒,解析时要兼容两种情况。
4. 透传模式下的数据收发机制与退出恢复
4.1 串口数据如何完整到达服务器
进入透传模式后,EC20会做这些事:串口收到的字节持续写入内部socket缓冲区,然后通过TCP发送出去。这里有几个重要的行为特征,写业务代码前必须搞清楚。
第一,TCP本身有流控机制,EC20的发送缓冲区有限。如果MCU一次性往串口灌的数据超过模块的缓冲能力,模块会处理不过来。
实际上EC20内部有一个发送缓冲区,不同固件版本大小不一,但都不算大。数据超过MTU,模块会分包发送,但TCP保证接收端的顺序,所以在服务器端你只需要按TCP流去读,不用关心分包。
第二,MCU串口发送的节奏不能太激进。我在STM32上的实测做法是:发送完一包(比如512字节)之后,等模块串口返回ready指示,或者简单粗暴加一个几十到几百毫秒的延迟。这个延迟是必要的,否则核心缓冲区被打满,数据会丢。
第三,EC20在透传模式下,模块串口在空闲时会自动进入低功耗状态,MCU发过来的第一个字节会用来唤醒主机,这段唤醒时间会导致首包延迟。对时间敏感的业务,要提前发一个无用字节或开启模块的“always on”模式,这个通过AT+QICFG="dte_reset"等命令控制,但具体命令看固件版本。
4.2 透传模式下的收数据与主动上报
服务器下发的TCP数据,模块会实时从串口输出。我接协议分析仪看过,数据到达串口基本没有缓存延迟,能做到秒级实时。这里需要注意:如果服务器同时下发多包数据,串口打印的数据是连续拼接的,MCU侧要靠自己的业务协议去分包,模块不会帮你加任何帧分隔符。
举例来说,如果服务器下发两条指令,一条是LED_ON,一条是READ_TEMP,模块串口输出的就是:
LED_ONREAD_TEMP没有换行,没有间隔。所以业务协议里必须有明确的帧头长度或者超时切包机制。我项目里用的方式是:固定头部两个字节为帧长,MCU端按帧长收完一帧,如果超过50ms没收到下一个字节判定当前帧结束。这种做法在透传模式下非常实用。
4.3 退出透传模式的三板斧
业务中总会遇到需要临时退出透传、发AT指令查状态的情况。EC20的退出机制是一个特殊的退出序列:发送三个加号+++,前面不需要延迟,后面也一定紧跟着一个延迟。
具体做法是:串口发送+++,然后保持静默1秒以上。模块识别到这是退出序列,会从透传返回AT命令模式,并在串口输出OK。
再次进入透传则发送ATO,模块返回CONNECT,就重新进入透传状态。
这里有个非常坑的点:+++必须在一段时间内连续输入,中间不能夹着其它数据,而且输入+++的前后需要一个“guard time”。移远官方文档写的是:发送+++前至少保持静默300ms,发送完+++后再保持静默大于300ms,模块才会把它当成退出指令,而不是业务数据。我一开始没注意这个静默窗口,结果按业务数据发给服务器了,服务器端还莫名其妙收到了三个加号。
安全一点的写法是:
// 退出透传 usart_delay(500); // 或更长 send_str("+++"); usart_delay(1000); // 留足guard time // 串口会返回 OK send_str("ATO\r\n"); // 重新进入透传 // 串口会返回 CONNECT4.4 透传模式下一些被忽略的细节
透传模式下不要发AT指令,否则这些字符串会被当作业务数据发给服务器。排查问题时如果想发AT指令,一定要按照上面的方式先退出透传。
如果TCP链路断了,透传模式会返回一个错误提示:模块串口会输出+QIURC: "closed",同时自动退出透传回到AT命令模式。业务代码里要能识别这个URC,及时重新建连。我项目里的自动重连逻辑就是靠解析这个URC触发的。
5. 常见故障排查:从连接超时到数据乱码的根因分析
5.1 连接建不上或者经常掉线
先说现象:AT+QIOPEN发出去之后,迟迟不见CONNECT OK,等了几十秒才返回+QIOPEN: 0, 206或者干脆超时无响应。
优先排查顺序:
- 用
AT+CREG?确认网络注册状态,不是1或5就先解决网络问题; - 用
AT+CSQ查信号强度,返回值在10以下通常信号很差,连TCP会稳不住; - 确认服务器的IP和端口在公网可达,尤其是端口,云服务器安全组和本地防火墙都要放行,不然外部连接直接被拒;
- 如果服务器在外网而模块在局域网,不要用局域网内网穿透软件做TCP中转,容易经常断开。
我之前踩过一个坑:服务器端程序监听的是127.0.0.1,外面自然连不上,日志显示only one usage of each socket address——端口被占或绑定失败,这个问题不是EC20端而是服务器端。
5.2 数据发送成功但服务器收不到
连接建立了,模块也没报错,但服务器就是收不到数据。这种问题先自查串口电平。我遇到过几次“数据发出去但乱码或完全没有”的情况,后来用示波器一量,发现MCU的TXD电平是3.3V,模块的RXD电平是1.8V,导致模块方根本识别不了逻辑1。
另外检查一下串口参数:EC20默认是8N1(8数据位、无校验、1停止位),如果MCU侧配了偶校验或2位停止位,模块发出去的数据必然对不上。
如果串口参数和电平都没问题,就用串口助手直连模块,手动发数据验证,看看是不是MCU侧代码的问题还是模块本身的问题。
5.3 透传过程中数据传输异常或偶发丢数据
排除掉信号和环境干扰后,最常见的原因是MCU侧发送没做流控。EC20支持硬件流控CTS/RTS,如果MCU的串口支持RTS/CTS,最好接上。实测中,如果不用流控,模块发送缓冲区满后,MCU还在发,那多出来的数据就直接丢了。
如果MCU串口没有流控引脚,就在应用层做软件流控:发送每包数据之间加等待,或者按“发一批、等ack、再发下一批”的方式处理。
还有一点,透传模式下EC20收到的数据如果带\r\n之类的控制字符,模块是不会做任何处理的,原样发送。如果发现服务器收到“奇怪字符”,看一下是不是MCU代码里自己加进去的调试信息。
5.4 服务器下发数据没有及时到达串口
一般到达时间非常快,体感上没有延迟。但如果服务器连续下发大量数据,EC20的接收缓冲区也只有几十KB,超出后TCP窗口会收缩,服务器端发送会变慢甚至阻塞。对高并发下发场景,建议MCU侧尽快读取串口数据,别让缓冲区堆积。
6. 从调试到量产:透传方案落地的几个额外经验
调试完透传模式,真正进入产品阶段还有一些细节需要注意。第一是模块的供电设计,前面说了EC20瞬间电流能到2A,示波器实测4G发射瞬间供电电压跌落超过400mV的话,模块就会掉线重启。我量产板用的电源是MIC28304这类DC-DC,输出电容加了一颗470uF和几颗10uF/22uF陶瓷电容做瞬态响应,实测非常稳。
第二是SIM卡座选型。推盖式卡座容易在振动环境下接触不良,产品如果长期运动或户外部署,优先用自弹式或翻盖带锁卡座,卡槽周围预留ESD防护器件。
第三是固件版本。EC20的固件版本非常多,不同版本对AT指令的兼容性有细微差别。量产前统一固件版本,不要一个出货批次有多个固件。
最后,透传模式适合大部分场景,但如果你要做的产品是走Modbus TCP网关那种需要解析协议、统计流量、做心跳保活的设备,AT指令模式下控制力更强,反而更好实现这些功能。选哪种模式,取决于你要交付的产品形态。我自己更偏爱透传模式的简洁,但前提是业务协议已经在MCU侧做得足够健壮。
本文还有配套的精品资源,点击获取