说在前面。。这是我根据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 |