在使用Air系列模块开发项目时,有时会要求模块提供准确的时间,目前主要有三种同步时间的主流方案可供选择,分别是:
1、基站同步时间
2、NTP同步时间
3、自建服务器同步时间
三种方案在可靠性和易用性上各有优势,您可以根据设备所需的安全等级和实际的产品逻辑灵活选择,方案对比如下图所示
|
基站同步 |
NTP同步 |
自建服务器同步 |
可靠性 |
一般 部分基站不支持时间同步功能 |
一般 取决于免费的公共NTP服务器稳定性,NTP服务器出问题之后,无法及时修复 |
可靠 自建服务器,命运掌握在自己手中,即使服务器出问题,也可以及时修复 |
易用性 |
容易 |
4G AT版本:困难 2G AT版本:困难 Lua版本:容易 |
一般 |
其他注意事项 |
4G版本的基站同步时间无法关闭,默认一直处于开启状态;只要掉网后或者重启后,再次注册上网络,如果基站支持时间同步功能,都会自动下发同步指令,模块更新本地时间 |
|
|
二、时间同步方案选择以及编码逻辑
本章节根据两个典型的应用场景来阐述方案选择和编码逻辑,如果不能满足实际产品需求,可根据不同方案的特点自行修改
1、应用场景一:时间必须同步
因为此场景要求时间必须同步,所以我们的同步逻辑直接使用“自建服务器同步”方案,下面从模块和版本两方面来详述
1.1、4G AT版本/2G AT版本
MCU端伪代码逻辑如下
uint8 bTimeSyned = 0 //时间同步标志初始化为“未同步” if (收到了自建服务器的时间同步报文 && bTimeSyned==0) { 发送AT+CCLK=...命令来设置模块的系统时间 if
(AT+CCLK=...命令返回设置成功) {
bTimeSyned = 1 //时间同步标志初始化为“已同步” }
else {
//自定义重试逻辑,建议请求服务器再次下发时间同步报文
//如果一直设置失败,可以尝试软重启 } } |
MCU端可以通过AT+CCLK?命令来查询模块系统时间
4G模块AT命令手册:http://www.openluat.com/Product/4g/Air720D.html
资料下载->相关文档->[AT 手册] Luat 4G模块AT命令手册VX.X.X.pdf
2G模块AT命令手册:http://www.openluat.com/Product/gprs/Air202.html
资料下载->相关文档-> [使用手册] AirM2M 无线模块AT命令手册VX.XX
1.2、4G Lua版本/2G Lua版本
脚本伪代码逻辑如下
local bTimeSyned = false --时间同步标志初始化为“未同步” if 收到了自建服务器的时间同步报文 and not bTimeSyned then
misc.setClock(要设置的时间,
function(tm,result)
bTimeSyned = result
if not result then --自定义重试逻辑,建议请求服务器再次下发时间同步报文 --如果一直设置失败,可以尝试软重启
end
end
) end |
脚本可以通过os.time()或者os.date("*t")来查询模块系统时间
2、应用场景二:时间可选同步
因为此场景要求时间可选同步,所以我们的同步逻辑中可采用“基站同步+NTP同步”或者“基站同步+NTP同步+自建服务器同步”方案组合,下面从模块和版本两方面来详述
2.1、4G AT版本
MCU端伪代码逻辑如下
uint8 bTimeSyned = 0 //时间同步标志初始化为“未同步” //检查基站同步是否成功 if (收到了类似于+NITZ: 19/08/02,09:19:33+32,0的URC提示) {
bTimeSyned = 1 //时间同步标志初始化为“已同步” } // 如果基站时间同步失败,则参考AT命令手册,发送如下AT命令序列,尝试NTP同步 AT+SAPBR=3,1,"Contype","GPRS" AT+SAPBR=3,1,"APN","CMNET" AT+SAPBR=1,1 AT+CNTPCID=1 AT+CNTP AT+SAPBR=0,1 //如果NTP时间同步失败,并且存在用户自建服务器同步时间的方案,则参考1.1章节的代码逻辑来同步 |
MCU端可以通过AT+CCLK?命令来查询模块系统时间
4G模块AT命令手册:http://www.openluat.com/Product/4g/Air720D.html
资料下载->相关文档->[AT 手册] Luat 4G模块AT命令手册VX.X.X.pdf
2.2、2G AT版本
MCU端伪代码逻辑如下
uint8 bTimeSyned = 0 //时间同步标志初始化为“未同步” //模块开机后,AT命令通道准备就绪之后(一定要在网络注册成功之前) //向模块发送AT+CLTS=1命令,打开基站同步时间功能 //检查基站同步是否成功 if (收到了类似于*PSUTTZ: 2019,8,2,23,59,52,"+32",0的URC提示) {
bTimeSyned = 1 //时间同步标志初始化为“已同步” } // 如果基站时间同步失败,则参考AT命令手册,发送如下AT命令序列,尝试NTP同步 AT+SAPBR=3,1,"Contype","GPRS" AT+SAPBR=3,1,"APN","CMNET" AT+SAPBR=1,1 AT+CNTPCID=1 AT+CNTP AT+SAPBR=0,1 //如果NTP时间同步失败,并且存在用户自建服务器同步时间的方案,则参考1.1章节的代码逻辑来同步 |
MCU端可以通过AT+CCLK?命令来查询模块系统时间
2G模块AT命令手册:http://www.openluat.com/Product/gprs/Air202.html
资料下载->相关文档-> [使用手册] AirM2M 无线模块AT命令手册VX.XX
2.3、4G Lua版本
脚本代码如下(timeSync.lua)
--- 模块功能:时间同步. -- 注意:本文件仅仅演示了基站同步和NTP同步两种方案,此两种方案都不是百分百可靠 -- 如果产品需要百分百时间同步,则建议使用自建服务器方案来实现 -- @author openLuat module(...,package.seeall) require"ril" require"ntp" local function printTime()
local tClock = os.date("*t")
log.info("printTime",
string.format("%04d-%02d-%02d %02d:%02d:%02d",tClock.year,tClock.month,tClock.day,tClock.hour,tClock.min,tClock.sec)) end --每隔1秒输出1次当前模块系统时间 sys.timerLoopStart(printTime,1000) --bTimeSyned :时间是否已经成功同步过 local bTimeSyned --注册基站时间同步的URC消息处理函数 ril.regUrc("+NITZ",
function()
log.info("cell.timeSync")
printTime()
bTimeSyned = true end) --IP网络准备就绪后,如果基站尚未成功同步时间,则尝试使用NTP同步时间 sys.subscribe("IP_READY_IND",
function() if
not bTimeSyned then
ntp.timeSync(nil,function(tClock,success)
log.info("ntp.timeSync",success)
printTime()
bTimeSyned = success
end)
end end) --如果NTP时间同步失败,并且存在用户自建服务器同步时间的方案,则自行实现自建服务器同步时间代码 |
脚本可以通过os.time()或者os.date("*t")来查询模块系统时间
2.4、2G Lua版本
脚本代码如下(timeSync.lua)
--- 模块功能:时间同步. -- 注意:本文件仅仅演示了基站同步和NTP同步两种方案,此两种方案都不是百分百可靠 -- 如果产品需要百分百时间同步,则建议使用自建服务器方案来实现 -- @author openLuat module(...,package.seeall) require"ril" require"ntp" local function printTime()
local tClock = os.date("*t")
log.info("printTime",
string.format("%04d-%02d-%02d
%02d:%02d:%02d",tClock.year,tClock.month,tClock.day,tClock.hour,tClock.min,tClock.sec)) end --每隔1秒输出1次当前模块系统时间 sys.timerLoopStart(printTime,1000) --bTimeSyned :时间是否已经成功同步过 local bTimeSyned --发送AT+CLTS=1,打开基站同步时间功能 ril.request("AT+CLTS=1") --注册基站时间同步的URC消息处理函数 ril.regUrc("*PSUTTZ",
function()
log.info("cell.timeSync")
printTime()
bTimeSyned = true end) --IP网络准备就绪后,如果基站尚未成功同步时间,则尝试使用NTP同步时间 sys.subscribe("IP_READY_IND",
function() if
not bTimeSyned then
ntp.timeSync(nil,function(tClock,success)
log.info("ntp.timeSync",success)
printTime()
bTimeSyned = success
end)
end end) --如果NTP时间同步失败,并且存在用户自建服务器同步时间的方案,则自行实现自建服务器同步时间代码 |
脚本可以通过os.time()或者os.date("*t")来查询模块系统时间
三、其他补充
其他还有很多方案可以同步时间,参考:http://oldask.openluat.com/article/30
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!