很多场景中,由于业务需要,模块需要保持正确的系统时钟,才能正常工作。但是模块上电后的初试时间戳是1338516000(即2012/06/01,10:00:00),所以同步时钟成为了开发者要解决的重要问题。
首先我们捋一下思路——模块要如何执行动作,执行何种动作,才可以同步时钟呢?基于这个疑问,我们先做一个定义:
只有当模块和外界以某种方式产生数据交互,且模块收到完整数据并正确解析时,才可以完成对应操作。
定义中指的“某种方式”是没有局限性的,也就是说开发者可以自由发挥想象力,只有你想不到,没有它做不到。接下来为大家介绍一些常见的和不常见的方式,方便开发者根据不同场景选择合适的方式。
(下文中,如无额外说明,均指Lua方式的二次开发)
NTP是大家众所周知的、广泛使用的、精确可靠的时钟同步方式。具有高效、准确、流量少,易实现的特点。NTP这种方式,就是使用“定义”中的蜂窝网络,和远端NTP服务器交互数据,收到服务器的回应并解析,重新设定系统时钟,完成同步。
我司的lua代码也提供了相应的基础库,开发者只需要简单的调用相应的函数,即可实现同步时钟:
luaScript:
require”ntp” --对,就这一行代码即可哦
luaTask:
require”ntp”
ntp.timeSync() --只同步一次
--ntp.timeSync(1) --每1小时同步一次
实际运行一下,看看效果如何:
需要注意的是,NTP使用的是多个免费公共的NTP服务器来同步时钟,所以不能保证任何时间任何地点都能百分百同步到正确的时间。如果开发者项目中的业务逻辑严格依赖于时钟同步功能,建议使用开发者自己的服务器进行同步。
如果开发者使用的是Air8xx系列模块,或者是其他挂载GPS模块的Air2xx系列产品,那么可以是用这个方式进行同步。
由于卫星定位系统的特性,每颗卫星都有精确到纳秒级的铯原子钟,才能实现全球的精确定位。故此,当开发者使用含GPS功能的模块时,可以使用GPS授时特性实现同步时钟。此种方式,就是使用“定义”中的GPS卫星信号,解析数据,设定模块系统时钟,完成同步。
实现原理并不复杂,只要解析GPS模块上报GGA即可:
格式:$--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
示例:$GPGGA,065545.789,2109.9551,N,12023.4047,E,1,9,0.85,18.1,M,8.0,M,,*5E
名称 |
样例 |
单位 |
描述 |
消息ID |
$GPGGA |
|
GGA 协议头 |
UTC 时间 |
065545.789 |
|
hhmmss.sss |
纬度 |
2109.9551 |
|
ddmm.mmmm |
N/S |
N |
|
N=北,S=南 |
经度 |
12023.4047 |
|
dddmm.mmmm |
E/W |
|
|
W=西,E=东 |
定位指示 |
|
|
0:未定位 1:SPS 模式,定位有效 2:差分,SPS 模式,定位有效 3:PPS 模式,定位有效 |
卫星数目 |
9 |
|
范围 0 到 12 |
HDOP |
0.85 |
|
水平精度 |
MSL 幅度 |
18.1 |
米 |
|
单位 |
M |
米 |
|
大地 |
-2.2 |
米 |
|
单位 |
M |
|
- |
差分时间 |
8.0 |
秒 |
当没有 DGPS 时,无效 |
差分 ID |
0000 |
|
|
校验和 |
*5E |
|
|
<CR><LF> |
|
|
消息结束 |
当然,解析RMC亦可哦:
格式:$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh
例句:$GPRMC,100646.000,A,3109.9704,N,12123.4219,E,0.257,335.62,291216,,,A*59
名称 |
样例 |
单位 |
描述 |
消息ID |
$GPRMC |
|
RMC 协议头 |
UTC 时间 |
100646.000 |
|
hhmmss.sss |
状态 |
A |
|
A=数据有效;V=数据无效 |
纬度 |
2109.9704 |
|
ddmm.mmmm |
N/S |
N |
|
N=北,S=南 |
经度 |
11123.4219 |
|
dddmm.mmmm |
E/W |
|
|
W=西,E=东 |
地面速度 |
0.257 |
Knot(节) |
|
方位 |
335.62 |
度 |
|
日期 |
291216 |
|
ddmmyy |
磁变量 |
|
|
- |
校验和 |
*59 |
|
|
<CR><LF> |
|
|
消息结束 |
我司的lua代码也提供了相应的基础库,开发者只需要简单的调用相应的函数,即可实现同步时钟:
luaScript:
require"gps"
gps.init() --初始化
gps.setfixmode(0) --GPS+BD定位
gps.settimezone(gps.GPS_BEIJING_TIME) --设置时区为北京
gps.open(gps.DEFAULT,{cause="time_sync"}) --打开gps
--剩下的gps.lua都会自动处理好了
luaTask:
require"gps"
require”sys”
require”misc”
gps.open(gps.DEFAULT,{tag="time_sync"})
sys.timeLoopStart( function()
If gps.isFix then
misc.setClock(gps.getUtcTime())
end
end, 60000)
相对于使用NTP等方式,此方法不受蜂窝网络限制,即使无卡或者卡欠费,也可以准确校时。但是需要注意的是,此种方法略有局限性:
如果我告诉你,基站也有授时服务哦,惊不惊喜,意不意外?
模块首次搜到基站的时候,即可获得基站下发的时间信息。发AT+CLTS即可。
由于此方法通用性并不是非常强,所以仅贴出AT交互流程,有能力的开发者请自行改写lua代码吧:
需要注意的是,此方法存在一定局限性:1、不是所有的基站都会下发,存在返回是nil的情况(具体要看基站的配置);2、只有附着的那一刻是准确的,随后再发AT+CLTS都是恒定值(即附着时),除非进入飞行模式后再离开飞行模式,重新获取一次;3、需要有卡才能使用。
有什么办法让运营商来给你打工吗?当然啦,今天就让运营商来出一次血——利用运营商下行短信的时间同步模块时钟。
luaScript & luaTask:
require”sms”
local function procnewsms(num, data, datetime)
print("procnewsms", num, data, datetime)
end
sms.regnewsmscb(procnewsms)
sms.send("10086", "hi, china mobile")
--给10068发一条内容为“hi, china mobile”的短信,等他返回短信的时候,就自带datetime啦,开发者可以根据datetime同步时系统时钟。
此种方法基本上百试百灵,而且给运营商发短信时双向免费的哦;不过一定要注意使用的SIM卡是否又短信功能。如果没有,是无法使用这个方法同步时钟的。
不论是直接去访问time.123cha.com这种提时钟的网页,抓取关键数据;还是通过mqtt传输时间字符串;哪怕打电话给模块,通过DTMF设置时间,都是完全没问题的。
正如“定义”所言,只要能产生数据交互,一切就皆有可能。
43 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!