说在前面。。这是我根据RT官方的源码进行的魔改,中间参考了网上的材料以及移远技术给出的建议
先上图:
1. 关机流程
- 执行AT命令【AT+QPOWD】
- 延时10s,以确保执行了该命令
- 拉低电源引脚【PWRKEY】
- 延时10s,以确保完全关机
2. 开机-初始化流程
2.1 开机操作
- 拉高电源引脚【PWRKEY】
- 延时12s,期间不要进行任何交互
- 模组开机后,会主动发送【RDY】,表示已经准备好
- 每隔500ms发送一次【AT】,超时时间3000ms
- 收到模组应答的【OK】,继续开机流程,进行模组配置
- 直到超时未收到【OK】,退出开机流程,执行关机流程
请注意,经和移远技术人员交流,模组开机后会有程序初始化时间,建议模组开机12s内不要发送任何数据
if (power_on())
{
LOG_D("start init %s device.", device->name);
rt_thread_mdelay(12000); // 开机12s内不要不要不要不要发数据
……
……
移远4G模组内部存在一个“拉黑”的逻辑:
频繁注网失败(短时间内多次连接某个运营商的网络),模组会自动将该运营商拉黑(即一段时间内不再尝试连接该运营商的任何网络),尤其是开启了机卡绑定的物联网卡,因此软件上需要规避短时间频繁请求注网,通过阶梯增加等待开机时间来实现。
以连续重连为例(一直重连且从未成功在线):
第一次重连:等待1分钟
第二次重连:等待5分钟
第三次重连:等待10分钟
……
……
第N次重连:等待1小时
由于在判断需要重连时,已经将4G模组关机了,因此这里的延时通过重写开机实现即可。
struct hhd_at
{
struct netdev *netdev; // 网络设备
struct at_device *atdev; // AT设备
struct at_client *atclt; // AT client
uint8_t cnt; // 连续重连计数
uint32_t delay_ms; // 延时时间
uint32_t last_tick; // 上次tick
}; // 实现重连延时的结构体
static struct hhd_at s_hhd_at = {
.netdev = RT_NULL, .atdev = RT_NULL, .atclt = RT_NULL,
.cnt = 0, .delay_ms = 0, .last_tick = 0
};
#define MAX_DELAY_COUNT 7
#define ADD_DELAY_COUNT \
do{ s_hhd_at.cnt++;\
if (s_hhd_at.cnt >= MAX_DELAY_COUNT)\
{\
s_hhd_at.cnt = MAX_DELAY_COUNT - 1;\
}\
}while(0)
// 1min 5min 10min 15min 30min 40min 1h
const uint32_t at_delay_time[MAX_DELAY_COUNT] = {60000, 300000, 600000, 900000, 1800000, 2400000, 3600000};
/* 开机 */
uint8_t power_on(void)
{
uint32_t now_tick = rt_tick_get();
while ((now_tick >= 60000) && (now_tick - s_hhd_at.last_tick < at_delay_time[s_hhd_at.cnt]))
{
uint32_t need = at_delay_time[s_hhd_at.cnt] - (now_tick - s_hhd_at.last_tick);
LOG_E("The waiting time for operating the 4G module has not ended! cnt[%d], delay[%d], waited[%d], need[%d]", s_hhd_at.cnt, at_delay_time[s_hhd_at.cnt], now_tick - s_hhd_at.last_tick, need);
SCREEN_LOG("重连冷却中 还需等待%d秒", need / 1000);
rt_thread_mdelay(10000);
now_tick = rt_tick_get();
}
s_hhd_at.last_tick = now_tick;
rt_pin_write(EC200S_PWRKEY_PIN, PIN_HIGH);
rt_thread_mdelay(1000);
return 1;
}
2.2 模组配置
为了保护4G模组的内部Flash,在这里需要引出一个概念:
在设置一个参数前,先查一下当前设置的是不是与期望设置的一致,不一致再进行设置
例如,要设置【AT+CMEE=2】,则应首先查一下【AT+CMEE?】,如果收到【+CMEE: 2】,则无需再继续设置,否则,再执行【AT+CMEE=2】
执行命令【ATV1】,切换AT指令的响应为OK<CR><LF>的文本模式
ATV<value> | |
<value> :整数类型 0 :响应信息: <text><CR><LF> 短结果格式:<numeric code><CR> 1 :响应信息: <CR><LF><text><CR><LF> 长结果格式: <CR><LF><verbose code><CR><LF> | |
ATV0 | ATV1 |
ATV0 0 ATI Quectel EC20F Revision: EC20CEHDLGR06A13M1G 0 | ATV1 OK ATI Quectel EC20F Revision: EC20CEHDLGR06A13M1G OK |
执行命令【ATE0】,关闭AT指令回显
ATE<value> | |
<value> :整数类型 0 :关闭回显 1 :开启回显 | |
ATE0 | ATE1 |
ATE0 OK Quectel EC20F Revision: EC20CEHDLGR06A13M1G OK | ATE1 OK ATI Quectel EC20F Revision: EC20CEHDLGR06A13M1G OK |
执行命令【AT+CMEE?】,查询错误消息格式设置
若上一步执行命令【AT+CMEE?】应答不是【+CMEE: 2】,则执行命令【AT+CMEE=2】,设置为2某些指令错误会返回+CME ERROR:给出详细的错误信息
AT+CMEE? | |||
应答: +CMEE: <n> OK | |||
AT+CMEE=<n> | |||
应答: OK | |||
<n>:整数类型 0:不显示错误码 1:只显示错误码 2:显示错误详情 | |||
AT+CMEE=0 | AT+CMEE=1 | AT+CMEE=2 | |
AT+CMEE=0 OK AT+CPIN? ERROR | AT+CMEE=1 OK AT+CPIN? +CME ERROR: 10 | AT+CMEE=2 OK AT+CPIN? +CME ERROR: SIM not inserted |
执行命令【AT+QSIMDET?】,查询SIM卡检测功能(含热插拔)
若上一步执行命令【AT+QSIMDET?】应答不是【+QSIMDET: 1,<insert_level>】,则执行命令【AT+QSIMDET=1,0】,开启SIM卡检测功能(热插拔)。热插拔功能在模块重新启动后生效
AT+QSIMDET? | |
应答: +QSIMDET: <enable>,<insert_level> OK | |
AT+QSIMDET=<enable>,<insert_level > | |
应答: OK 或 ERROR | |
<enable>:整数类型,启用或禁用SIM卡检测 0:禁用SIM卡检测 1:启用SIM卡检测 <insert_level>:整数类型,SIM卡插入后检测引脚的电平 0:低电平 1:高电平 |
下图为SIM卡部分电路图,可见,当SIM卡插入为低电平
执行命令【AT+QSIMSTAT?】,查询SIM卡插入状态报告状态
若上一步执行命令【AT+QSIMSTAT?】应答不是【+QSIMSTAT: 1,<inserted_status>】,则执行命令【AT+QSIMSTAT=1】,开启SIM卡插入状态报告。
AT+QSIMSTAT? |
应答: +QSIMSTAT: <enable>,<inserted_status> OK |
AT+QSIMSTAT=<enable> |
应答: OK 或 ERROR |
<enable>:整数类型,启用或禁用SIM卡插入状态报告 0:禁用SIM卡插入状态报告 1:启用SIM卡插入状态报告 <inserted_status>:整数类型,已插入或删除SIM卡,不允许设置此参数 0:拔出 1:插入 2:未知 |
2.3. SIM卡检测
执行命令【AT+CPIN?】,查询模块是否需要在操作前所必需的密码
AT+CPIN? |
应答: +CPIN: <code> OK |
<code>:没有双引号的字符串。该模块所需要的密码 READY:没有等待任何密码 其余可能的返回,简单罗列: SIM PIN、SIM PUK、SIM PIN2、SIM PUK2、PH-NET PIN、PH-NET PUK、PH-NETSUB PIN、PH-NETSUB PUK、PH-SP PIN、PH-SP PUK、PH-CORP PIN、PH-CORP PUK |
当前逻辑在未收到READY时,将周期执行命令【AT+CPIN?】。由于目前并未遇到有要求输入密码的场景,因此未对需要输入密码的场景有处理。(DTU11中4G模组开关机逻辑位于网络发送线程中,直接使用while(1)在此等待不影响其他软件逻辑)
若上一步执行命令【AT+CPIN?】应答是【+CPIN: READY】,则执行命令【AT+CIMI】:请求SIM卡的IMSI码(国际移动用户识别码)
AT+CIMI? |
应答: +CIMI: <IMSI> OK 或 +CME ERROR: <err> |
<IMSI>:国际移动用户身份识别码(无双引号的字符串) |
若读取成功,则继续下面的流程
若读取失败,则卡存在异常,重复执行1.2.流程,直到读取SIM卡的IMSI码后,再继续下面的流程。
2.4 APN操作
请注意,给出的自定义APN定义是:char apn[50];
- 有特殊配置:直接使用特殊配置(APN、用户名、密码、身份验证方法)
- 无特殊配置,首先查询运营商,然后设置默认的APN
- 查询运营商使用【AT+COPS?】命令
AT+CPIN? |
应答: +COPS: <mode>[,<format>[,<oper>][,<Act>]] OK |
<oper>:运营商 1 "CHINA MOBILE":中国移动 2 "CHN-UNICOM":中国联通 3 "CHN-CT":中国电信 |
- 配置使用【AT+QICSGP=xxx】命令:
AT+QICSGP=<contextID>[,<context_type>,<APN>[,<username>,<password>][,<authentication>]] |
应答: OK |
<contextID>:上下文ID,[1, 16] <context_type>:协议类型 1 IPv4 2 IPv6 <APN>:即接入点名称,特殊APN需要询问运营商 <username>:用户名,特殊卡需要使用 <password>:密码,特殊卡需要使用 <authentication>:身份验证方法 0 NONE 1 PAP 2 CHAP |
2.5 网络连接检测
使用【AT+QENG="servingcell"】命令查看信号强度:
执行命令后的响应,这里仅介绍LET模式,其余请参考移远AT手册
+QENG: "servingcell",<state>,"LTE",<is_tdd>,<mcc>,<mnc>,<cellID>,<pcid>,<earfcn>,<freq_band_ind >,<ul_bandwidth>,<dl_bandwidth>,<tac>,<rsrp>,<rsrq>,<rssi>,<sinr>,<srxlev>
OK
这里表示信号强度的有<rsrp>,<rssi>
- RSRP:RSRP (Reference Signal Receiving Power,参考信号接收功率) 是LTE网络中可以代表无线信号强度的关键参数以及物理层测量需求之一,是在某个符号内承载参考信号的所有RE(资源粒子)上接收到的信号功率的平均值。
- 通俗理解:只是接收到的有效信号
- 取值范围:-44~-140dBm,值越大越好
- 强度划分:见下表
RSRP(dBm) | 覆盖强度级别 | 备注 |
rx <= -105 | 覆盖强度等级6 | 覆盖较差:业务基本无法起呼。 |
-105 < rx <= -95 | 覆盖强度等级5 | 覆盖差:室外语音业务能够起呼,但呼叫成功率低, 掉话率高;室内业务基本无法发起业务。 |
-95 < rx <= -85 | 覆盖强度等级4 | 覆盖一般:室外能够发起各种业务,可获得低速率 的数据业务;但室内呼叫成功率低,掉话率高。 |
-85 < rx <= -75 | 覆盖强度等级3 | 覆盖较好:室外能够发起各种业务,可获得中等 速率的数据业务;室内能发起各种业务,可获 得低速率数据业务。 |
-75 < rx <= -65 | 覆盖强度等级2 | 覆盖好:室外能够发起各种业务可获得高速率的数 据业务;室内能发起各种业务,可获得中等速率数 据业务。 |
rx > -65 | 覆盖强度等级1 | 覆盖非常好。 |
- SINR:信号与干扰加噪声比(Signal to Interference plus Noise Ratio)。它表示接收到的有用信号的强度与接收到的干扰信号(噪声和干扰)的强度的比值。SINR是无线性能中一个非常重要的指标,用于衡量通信系统的性能。通常认为SINR大于等于10 dB为良好的接收质量,而低于10 dB则表示信号质量较差,可能会导致通信性能下降。
- RSSI:RSSI(Received Signal Strength Indicator接收信号强度指示)。RSSI在无线网络中表示信号的强度,它随距离的增大而衰减,通常为负值,该值越接近零说明信号强度越高。
- 通俗理解:接收到的所有信号
- 正常范围:[-93, -113]
- RSSI等级划分(建议):
RSSI(dBm) | 信号强度 |
> -40dBm | 4格 |
-40dBm ~ -50dBm | 3格 |
-50dBm ~ -70dBm | 2格 |
-70dBm ~ -90dBm | 1格 |
< -90dBm | 0格 |
- 另,【AT+CSQ】命令:移远技术称这个命令表示的2G、3G信号强度,在4G上还是建议使用【AT+QENG="servingcell"】。
- 使用【AT+CEREG?】命令,查看网络连接情况:
AT+CEREG? |
应答: +CEREG: <n>,<stat>[,<tac>,<ci>[,<AcT>]] |
<n>:整数类型。控制一个未经请求的结果代码+CEREG: <stat>的表示。 0禁用网络注册未请求结果代码 1启用网络注册未请求结果代码+CEREG: <stat> 2启用网络注册和位置信息未请求结果代码+CEREG:<stat>[,<tac>,<ci>[,<AcT>]] <stat>:整数类型 0 未注册,没有搜索到可以注册的 1 已注册,本地网络 2 未注册,但仍在尝试注册 3 注册被拒绝 4 未知 5 已注册,漫游网络 |
一般来说,只需简单的判断以下几种应答即可
- 【+CEREG: 0,0】未注册,没有搜索到可以注册的网络
- 【+CEREG: 0,1】已注册,本地网络
- 【+CEREG: 0,2】未注册,但仍在尝试注册网络
- 【+CEREG: 0,3】注册被拒绝
- 【+CEREG: 0,4】未知
- 【+CEREG: 0,5】已注册,漫游网络
- 使用命令【AT+CTZU=3】设置4G模组时区自动更新模式为“通过NITZ启用自动时区更新,并将本地时间更新到RTC”模式:
此模式的作用:4G模组会自动获取当前时区、日期、时间,并保存到模组RTC
用途:部分情况下,需要抓取4G模组的log、平台log、控制器log做数据对比,正确的时间有助于分析数据。
设置方式:
-
- 设置前先回读当前设置的模式
- 若收到<enable>不为3,则进行设置【AT+CTZU=3】
AT+CTZU? |
应答: +CTZU: <enable> OK |
AT+CTZU=<enable> |
应答: OK |
<enable>: 整数类型。时区自动更新的模式。 0通过NITZ禁用自动时区更新。 1通过NITZ启用自动时区更新 3通过NITZ启用自动时区更新,并更新本地时间到RTC |
2.6 PDP操作
1. 执行【AT+QIDEACT=1】,在激活PDP连接前先关闭,确保连接正确
要注意:此命令最大响应时间40s,未收到回复前,不要执行任何其他语句
2. 执行【AT+QIACT=1】, 激活PDP连接,为接下来的TCP/IP连接做准备
要注意:此命令最大响应时间150s,未收到回复前,不要执行任何其他语句
若在执行步骤2时,返回失败,可重新进行一次步骤1、步骤2。