移远EC20 4G模块长短信(级联)收发实战:AT命令详解与中文编码避坑指南
1. 移远EC20模块与长短信收发基础
在嵌入式物联网项目中,短信通信是最可靠的远程通信方式之一。相比网络通信依赖基站信号和IP连接,短信只需要最基本的蜂窝网络覆盖即可工作。移远EC20作为一款工业级4G通信模块,支持通过AT命令实现短信收发功能,特别适合用于远程监控、设备报警等场景。
我第一次在项目中使用EC20发送长短信时,发现当内容超过70个汉字时,手机接收到的全是乱码。经过排查才发现,普通短信有长度限制:GSM编码下每条短信最多153个字符,而UCS2中文编码下只有67个字符容量。这就引出了级联短信(Concatenated SMS)的概念——当内容超长时,模块会自动将短信拆分成多条发送,接收端再重新组装显示。
级联短信的实现依赖三个关键技术点:
- UDH头信息:每条分片短信都携带序号和总条数
- 唯一标识符:同一组短信使用相同的Message ID
- 编码一致性:必须统一采用UCS2编码格式
在EC20模块上,级联短信功能已经内置实现,开发者只需要通过正确的AT命令序列配置参数即可。不过中文环境下的使用有几个关键陷阱需要注意,这也是我踩过坑之后要重点分享的内容。
2. 环境准备与基础配置
2.1 硬件连接与初始化
使用EC20发送短信前,需要确保硬件正确连接。以嵌入式Linux开发板为例,通常通过USB接口连接EC20模块,系统会自动生成多个/dev/ttyUSB设备节点。短信功能一般使用ttyUSB2端口,波特率默认为115200。
建议先用minicom或microcom工具手动测试AT命令:
microcom -p /dev/ttyUSB2 -s 115200输入AT后应该收到"OK"响应,这表明模块已就绪。如果无响应,请检查:
- 天线是否安装(信号强度影响AT命令响应)
- SIM卡是否插好(建议使用支持4G的普通卡,非物联网卡)
- 模块供电是否充足(EC20峰值电流可达2A)
2.2 恢复出厂设置
开始配置前,强烈建议先执行恢复出厂设置,避免历史配置干扰:
AT&F这个命令会将所有参数重置为默认值,返回"OK"表示成功。我曾在项目中遇到短信发送失败的问题,最后发现是之前测试时修改了编码参数没有还原,导致后续所有操作都异常。
2.3 关键参数配置
发送中文长短信需要一组特定的参数组合,以下是必须配置的AT命令序列:
- 设置短信存储位置(避免SIM卡存储空间不足):
AT+CPMS="ME","ME","ME"- 启用文本模式(PDU模式不支持级联显示):
AT+CMGF=1- 配置UCS2编码(中文必需):
AT+CSCS="UCS2"- 设置短信参数(关键参数组合):
AT+CSMP=17,167,0,8其中最后一个参数"8"表示使用UCS2编码,这是支持中文的关键。我曾误设为"0"导致发送的中文全部变成问号。
- 检查短信中心号码(通常自动获取):
AT+CSCA?如果返回空,需要手动设置当地运营商短信中心号,例如北京移动:
AT+CSCA="+8613800100500"3. 长短信发送实战
3.1 短信分段原理
当短信内容超过单条限制时,EC20会自动将其分割成多条发送。以中文短信为例:
- 单条限制:67个汉字/字符
- 超出部分:按67字符分段,每段添加UDH头
- 接收端:根据UDH重组显示为一条完整信息
分段控制通过AT+QCMGS命令的参数实现:
AT+QCMGS="<号码>",<总段数>,<当前段序号>,<消息ID>其中:
- 号码:需转换为Unicode格式(如"00310038003600310035003300380030003900340033003300310030"对应"+8615380943310")
- 消息ID:0-255的随机数,同一组短信保持相同
3.2 发送完整示例
假设要向"+8615380943310"发送长短信《春江花月夜》前四句(84字):
春江潮水连海平,海上明月共潮生。 滟滟随波千万里,何处春江无月明。实际操作步骤:
- 将手机号转为Unicode:
# Python转换示例 number = "+8615380943310" unicode_num = ''.join([f"{ord(c):04X}" for c in number]) # 结果:002B0038003600310035003300380030003900340033003300310030- 发送第一段(前67字符):
AT+QCMGS="002B0038003600310035003300380030003900340033003300310030",2,1,123 > 66258F665E8698FB6EE54E009670CE67087155895F20FF0C6D77E54E0A67087151776E10665EFF0C6D0B6D0B968F7A7B975E26FF0C4F55E0424F55166258F666CA16709FF1F Ctrl+Z- 发送第二段(剩余17字符):
AT+QCMGS="002B0038003600310035003300380030003900340033003300310030",2,2,123 > 4F55565E84265BFF1F Ctrl+Z注意:输入内容后需要按Ctrl+Z发送,不是回车。我在首次测试时因为按回车导致命令一直处于等待输入状态。
3.3 电信卡兼容性问题
根据社区反馈,电信卡用户可能会遇到ERROR:350错误。这是因为:
- 电信已逐步关闭CDMA网络
- 需要EC20 R08及以上版本支持VoLTE
- 部分省份需要特殊APN配置
解决方案:
- 确认模块版本:
ATI查看是否包含"R08"标识
- 检查网络注册状态:
AT+CEREG?返回",1"或",5"表示已注册
- 必要时配置电信专用APN:
AT+QCFG="ims",1 AT+QCFG="apn","ctnet"4. 短信接收与解析
4.1 接收通知设置
当有新短信到达时,模块会通过URC(Unsolicited Result Code)通知。需要先配置通知方式:
AT+CNMI=2,1,0,0,0参数说明:
- 第一个"2":新短信立即通知,忙时缓存
- 第二个"1":将短信存储到ME内存并通知
测试时我曾设为"0"导致收不到任何通知,排查半天才发现是这个参数的问题。
4.2 短信读取与解码
收到通知后(如"+CMTI: "ME",0"),可以读取短信:
AT+CMGR=0返回示例:
+CMGR: "REC READ","002B0038003600310035003300380030003900340033003300310030",,"23/08/15,14:30:25+32" 4F60597D其中"4F60597D"是Unicode编码的"你好",可以通过Python解码:
text = bytes.fromhex("4F60597D").decode('utf-16be') # 输出:你好4.3 级联短信重组
当收到分片短信时,观察两个特征:
- 短信内容开头有6字节UDH头(如0500030A0102)
- 多条短信的Message ID相同
处理流程:
- 提取UDH中的总段数和当前序号
- 按序号缓存各段内容
- 收齐所有段后去除UDH并拼接
- UCS2解码得到完整内容
5. 常见问题排查
5.1 ERROR:350错误分析
这个错误在电信卡场景最常见,可能原因包括:
- 模块不支持VoLTE(需R08版本)
- 当地电信网络已关闭CDMA
- APN配置错误
解决步骤:
- 确认模块版本支持VoLTE
- 检查网络注册状态:
AT+CEREG?- 尝试手动设置APN:
AT+QCFG="apn","ctnet"5.2 中文乱码问题
如果收到全是"???"或乱码,检查:
- 编码是否设为UCS2:
AT+CSCS?- CSMP参数是否正确:
AT+CSMP?确认第四个参数是8
- 手机是否支持UCS2显示(老年机可能有问题)
5.3 短信发送失败
返回+CMS ERROR时:
- 代码304:内存已满,需删除旧短信
AT+CMGD=1,4- 代码305:短信中心号错误,重新设置
AT+CSCA="+8613800100500"- 代码330:SIM卡未插好,检查硬件连接
在实际项目中,我建议每次发送前都检查短信中心号,因为有些地区的自动获取可能不可靠。另外定期清理短信存储空间也很重要,特别是需要长期稳定运行的设备。
