移远EC20 4G模块长短信(级联)收发实战:AT命令详解与中文编码避坑指南

📅 2026/7/15 17:42:08 👁️ 阅读次数 📝 编程学习
移远EC20 4G模块长短信(级联)收发实战:AT命令详解与中文编码避坑指南

1. 移远EC20模块与长短信收发基础

在嵌入式物联网项目中,短信通信是最可靠的远程通信方式之一。相比网络通信依赖基站信号和IP连接,短信只需要最基本的蜂窝网络覆盖即可工作。移远EC20作为一款工业级4G通信模块,支持通过AT命令实现短信收发功能,特别适合用于远程监控、设备报警等场景。

我第一次在项目中使用EC20发送长短信时,发现当内容超过70个汉字时,手机接收到的全是乱码。经过排查才发现,普通短信有长度限制:GSM编码下每条短信最多153个字符,而UCS2中文编码下只有67个字符容量。这就引出了级联短信(Concatenated SMS)的概念——当内容超长时,模块会自动将短信拆分成多条发送,接收端再重新组装显示。

级联短信的实现依赖三个关键技术点:

  1. UDH头信息:每条分片短信都携带序号和总条数
  2. 唯一标识符:同一组短信使用相同的Message ID
  3. 编码一致性:必须统一采用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命令序列:

  1. 设置短信存储位置(避免SIM卡存储空间不足):
AT+CPMS="ME","ME","ME"
  1. 启用文本模式(PDU模式不支持级联显示):
AT+CMGF=1
  1. 配置UCS2编码(中文必需):
AT+CSCS="UCS2"
  1. 设置短信参数(关键参数组合):
AT+CSMP=17,167,0,8

其中最后一个参数"8"表示使用UCS2编码,这是支持中文的关键。我曾误设为"0"导致发送的中文全部变成问号。

  1. 检查短信中心号码(通常自动获取):
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字):

春江潮水连海平,海上明月共潮生。 滟滟随波千万里,何处春江无月明。

实际操作步骤:

  1. 将手机号转为Unicode:
# Python转换示例 number = "+8615380943310" unicode_num = ''.join([f"{ord(c):04X}" for c in number]) # 结果:002B0038003600310035003300380030003900340033003300310030
  1. 发送第一段(前67字符):
AT+QCMGS="002B0038003600310035003300380030003900340033003300310030",2,1,123 > 66258F665E8698FB6EE54E009670CE67087155895F20FF0C6D77E54E0A67087151776E10665EFF0C6D0B6D0B968F7A7B975E26FF0C4F55E0424F55166258F666CA16709FF1F Ctrl+Z
  1. 发送第二段(剩余17字符):
AT+QCMGS="002B0038003600310035003300380030003900340033003300310030",2,2,123 > 4F55565E84265BFF1F Ctrl+Z

注意:输入内容后需要按Ctrl+Z发送,不是回车。我在首次测试时因为按回车导致命令一直处于等待输入状态。

3.3 电信卡兼容性问题

根据社区反馈,电信卡用户可能会遇到ERROR:350错误。这是因为:

  1. 电信已逐步关闭CDMA网络
  2. 需要EC20 R08及以上版本支持VoLTE
  3. 部分省份需要特殊APN配置

解决方案:

  1. 确认模块版本:
ATI

查看是否包含"R08"标识

  1. 检查网络注册状态:
AT+CEREG?

返回",1"或",5"表示已注册

  1. 必要时配置电信专用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 级联短信重组

当收到分片短信时,观察两个特征:

  1. 短信内容开头有6字节UDH头(如0500030A0102)
  2. 多条短信的Message ID相同

处理流程:

  1. 提取UDH中的总段数和当前序号
  2. 按序号缓存各段内容
  3. 收齐所有段后去除UDH并拼接
  4. UCS2解码得到完整内容

5. 常见问题排查

5.1 ERROR:350错误分析

这个错误在电信卡场景最常见,可能原因包括:

  1. 模块不支持VoLTE(需R08版本)
  2. 当地电信网络已关闭CDMA
  3. APN配置错误

解决步骤:

  1. 确认模块版本支持VoLTE
  2. 检查网络注册状态:
AT+CEREG?
  1. 尝试手动设置APN:
AT+QCFG="apn","ctnet"

5.2 中文乱码问题

如果收到全是"???"或乱码,检查:

  1. 编码是否设为UCS2:
AT+CSCS?
  1. CSMP参数是否正确:
AT+CSMP?

确认第四个参数是8

  1. 手机是否支持UCS2显示(老年机可能有问题)

5.3 短信发送失败

返回+CMS ERROR时:

  • 代码304:内存已满,需删除旧短信
AT+CMGD=1,4
  • 代码305:短信中心号错误,重新设置
AT+CSCA="+8613800100500"
  • 代码330:SIM卡未插好,检查硬件连接

在实际项目中,我建议每次发送前都检查短信中心号,因为有些地区的自动获取可能不可靠。另外定期清理短信存储空间也很重要,特别是需要长期稳定运行的设备。