嵌入式技术
在嵌入式系统中(包括大部分电子设备:手机、平板、手环、手表等等),时间的概念非常重要。如打印log时的时间戳、定时关机、心跳上报、日历功能、闹钟等等。上述这些功能都需要一个相对精确的时间系统。
经常涉及的与时间相关的术语包括:硬件时钟、系统时钟、网络时钟、时区修改和同步。日常生活和工作中可能接触到的时区概念包括:UTC
、GMT
、CST
、DST
。在网络时间中可能接触到的概念又有:NTP
、SNTP
、NITZ
。本文将会对上述涉及到的概念进行系统的整理和探讨。
下面对几个概念进行集中陈述。
时区[1] 是指地球上的不同区域使用同一个时间定义。以前,人们通过观察太阳的位置(时角)决定时间,这就使得不同经度的地方的时间有所不同(地方时)。1863年,首次使用时区的概念。通过设立一个区域的标准时间部分地解决了这个问题。
时区划分规则:将全球按经线从东到西划分为24个时区,其中东、西各12个时区,每个时区跨越经度15°,0区和12区跨越东西各7.5°。规定相邻区域的时间相差1小时,这样24个时区刚好是24小时,地球自转一圈。如下图是全球时区的划分明细。常见的时区概念包括:GMT
、UTC
、CST
、DST
。
GMT 12:00
就是指格林尼治天文台当地的正午12:00,而GMT+8 12:00,则是指东八区的北京当地时间的12:00。格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治时)的时间。由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。GMT + 8 = UTC + 8 = CST
。常见的几个时钟概念包括:硬件时钟、系统时钟、网络时钟。
系统时钟。指软件系统的时钟。在linux
和一些rtos
中,启动时会去读取硬件时钟(RTC),之后则独立运行。独立运行的好处对于普通用户意义不大,但对于linux
网络管理员却有很大的用处。例如,要将一个很大的网络中(跨越若干时区)的服务器同步,假如位于美国纽约的linux
服务器和北京的Linux服务器,其中一台服务器无须改变硬件时钟而只需临时设置一个系统时间,如要将北京服务器上的系统时间设置为纽约时间,两台服务器完成文件的同步后,再与原来的硬件时钟同步一下即可。这样系统时钟和硬件时钟就提供了更为灵活的操作。
网络时钟。网络时钟的时间源来自于专业授时的服务器(SNTP、NTP)。实现方案是在网络上指定若干时钟源服务器,为用户提供授时服务,并且这些服务器之间能够相互比较校正,以提高准确度。在移动蜂窝网络中,基站也可以通过无线网络向移动设备提供本地日期和时间、时区、夏时制偏移。网络时钟的精度一般都很高,可以达到毫秒级,可以用来对嵌入式设备进行时间同步。
时间同步对嵌入式设备很重要,一些功能业务甚至依赖于时间信息来完成。如自注册DM业务,需要周期性的向运营商服务器上报信息,这些信息上报都是以天或者是月为周期,不可能靠软件timer
来实现。和此类似的功能都需要以标准时间为基准,以此完成条件的触发。下面来探讨时间同步的话题。
SNTP是简单网络时间协议(Simple Network Time protocol)的简称,它是目前Internet
网上实现时间同步的一种重要工程化方法。SNTP
由NTP
改编而来,SNTP
其实是NTP
的子集,只是NTP
可以 分发和授时,而SNTP
只有授时没有分发,也就是说你只能从SNTP
获取时间,其他的什么都做不了,SNTP
简化了NTP
的全部流程,这样节约成本,但只能同步一个时间源。SNTP
协议采用客户端/服务器的工作方式。SNTP
服务器通过接收GPS
信号或自带的原子钟作为系统的时间基准。SNTP
客户端(嵌入式设备)能够通过定期访问SNTP
服务器获得准确的时间信息,用于调整客户端自身所在系统的时间,达到同步时间的目的。在linux
系统中一般有现成的SNTP客户端可以安装使用,在其他的嵌入式平台上需要移植或自主开发。一些可用的SNTP服务器汇总如下(亲测可以ping通):
NITZ(Network Identity and Time Zone)是一种通过无线网络向移动设备提供本地日期和时间、时区、夏时制偏移,以及网络提供商身份信息的机制,这通常用于无线蜂窝网络设备(手机、通信模组)的自动更新系统时间。对于其他网络时间协议,NITZ的质量和执行力度都相对较弱。有些运营商根本就不支持,例如在国内,本地测试(广东)发现,中国移动和中国电信是支持NITZ
的,中国联通就根本不支持。再者,与SNTP
相比,SNTP
授时能使时间分辨率达到毫秒级,NITZ
则“对于时间只能精确到数分钟”。但NITZ
不用连上互联网,能驻上无线蜂窝网络就行,而SNTP
必须连接互联网。
linux命令中的date
命令是用来设置和查询系统时间的,而hwclock
命令是用来设置和读写RTC
时间(硬件时间)。有一点需要注意,linux
的时间系统是由「新纪元时间」Epoch开始计算起,单位为秒,Epoch则是指定为1970年1月1日0点0分0秒,格林威治时间(GMT)。date +%s
命令可以读取从1970年1月1日0点0分0秒开始到当前的秒数。
book@zhang.c:~$ date +%s
1653752545
date
;
book@zhang.c:~$ date
Sat May 28 2226 CST 2022
date -s "20220501 1200"
,date -s
命令设置时间只会影响系统时间,不会设置RTC时间,如果需要把当前系统时间同步设置到RTC中,需要额外调用hwclock
命令;
book@zhang.c:~$ date -s "20220501 1200"
Sun May 1 1200 CST 2022
rtc
时间的操作,主要是hwclock
命令使用;
#读取并打印当前的rtc时间
hwclock -r
#读取RTC时间并设置到系统时间中去
hwclock -s
#把当前的系统时间设置到RTC中
hwclock -w
#完整的设置RTC的时间可执行如下命令
date -s "20220501 1200"
hwclock -w
date
命令格式化的显示时间,可以看如下的Command
这一列。
Format/result | Command | Output
--------------------------------+----------------------------+------------------------------
YYYY-MM-DD | date -I | $(date -I)
YYYY-MM-DD_hhss | date +%F_%T | $(date +%F_%T)
YYYYMMDD_hhmmss | date +%Y%m%d_%H%M%S | $(date +%Y%m%d_%H%M%S)
YYYYMMDD_hhmmss (UTC version) | date --utc +%Y%m%d_%H%M%SZ | $(date --utc +%Y%m%d_%H%M%SZ)
YYYYMMDD_hhmmss (with local TZ) | date +%Y%m%d_%H%M%S%Z | $(date +%Y%m%d_%H%M%S%Z)
YYYYMMSShhmmss | date +%Y%m%d%H%M%S | $(date +%Y%m%d%H%M%S)
YYYYMMSShhmmssnnnnnnnnn | date +%Y%m%d%H%M%S%N | $(date +%Y%m%d%H%M%S%N)
YYMMDD_hhmmss | date +%y%m%d_%H%M%S | $(date +%y%m%d_%H%M%S)
Seconds since UNIX epoch: | date +%s | $(date +%s)
Nanoseconds only: | date +%N | $(date +%N)
Nanoseconds since UNIX epoch: | date +%s%N | $(date +%s%N)
ISO8601 UTC timestamp | date --utc +%FT%TZ | $(date --utc +%FT%TZ)
ISO8601 UTC timestamp + ms | date --utc +%FT%T.%3NZ | $(date --utc +%FT%T.%3NZ)
ISO8601 Local TZ timestamp | date +%FT%T%Z | $(date +%FT%T%Z)
YYYY-MM-DD (Short day) | date +%F(%a) | $(date +%F(%a))
YYYY-MM-DD (Long day) | date +%F(%A) | $(date +%F(%A))
在手机(包括Android和功能机)和模组产品中,SNTP
和NITZ
两种同步系统时间的策略一般都会用到。默认使用的是NITZ来获取网络时间,但是需要有运营商的支持才能使用(中国联通就不支持),而有些设备产品只支持WIFI等无线网络,而不支持移动网络,此时就需要采用SNTP
方式来获取网络时间进行同步了。SNTP
协议时间戳是以1900年1月1日0点0分0秒为起点,而linux
时间戳从1970年1月1日0点0分0秒开始记秒数,即记录到SNTP
结构体中的时间包含了JAN_1970(从1900到1970共70年的秒数)。在拿到SNTP
时间后,往linux同步时间时,需要减掉JAN_1970。
UTC
与GMT
时间基本相同;SNTP
或NITZ
来进行同步,尤其SNTP
时间同步精度可以达到毫秒级。linux
系统的计时起点为1970年1月1日0点0分0秒,其他嵌入式系统在做网络时间同步时,也一定要确认好计时起点。
全部0条评论
快来发表一下你的评论吧 !