嵌入式爱好者

嵌入式爱好者 门户 知识库 查看内容

RTC的使用

2024-5-31 19:00| 发布者: Espoir| 查看: 251| 评论: 0

类目:  >  知识库     文档编号: 1425

1.RTC简介

1.1 RTC是什么

RTC (Real Time Clock):实时时钟,是指可以像时钟一样输出实际时间的电子设备。简单来说,RTC就是个32位定时器,每隔1秒,定时器记一次数。修改定时器的值可以修改时间和日期。

为了保证RTC时间断电不丢失,一般还会单独接一个小电池给RTC供电。一旦小电池被取下来,断电之后,RTC的时间会丢失。

但是,电脑右下角的时间、linux下用date看到的时间,都不是RTC时间。系统运行时,会将芯片上的一个高精度寄存器作为系统时间基准。为了避免系统运行时间比较长以后出现偏移,以及掉电之后系统时间丢失的情况,每次启动系统会从RTC获取时间,作为系统时间。

1.2 内部RTC和外部RTC的区别

相较于内部RTC,外部RTC的主要优势有:

  • 功耗低

  • 误差小

所以一般采用外部RTC。

2.unix时间戳

  • Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒

  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量

  • 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间

3.常用操作

3.1 date

date命令可以读/写当前系统时间,也可以查看时区。常用的几种操作:

查看时间:

修改时区之前
root@fl-imx6ull:~# date
Thu Sep 21 04:43:03 UTC 2017

修改时区之后
root@fl-imx6ull:~# date  
Thu Sep 21 12:43:50 HKT 2017

查看时区:

修改时区之前
root@fl-imx6ull:~# date -R
Fri, 26 Apr 2019 19:07:20 +0000

修改时区之后
root@fl-imx6ull:~# date -R
Thu, 21 Sep 2017 12:45:37 +0800

设置时间:

root@fl-imx6ull:~# date -s "20240531 12:00:00"
Fri May 31 12:00:00 UTC 2024

3.2 修改时区

时区文件为/etc/localtime,当需要修改时区时,只需要将对应的时区文件软链接到/etc/localtime

root@fl-imx6ull:~# rm /etc/localtime 
root@fl-imx6ull:~# ln -s /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime

3.3 hwclock

读取rtc时间

root@fl-imx6ull:~# hwclock -r
Thu Sep 21 04:47:03 2017 0.000000 seconds

写入时间

hwclock -w

root@fl-imx6ull:~# date
Thu Sep 21 12:50:41 HKT 2017
root@fl-imx6ull:~# hwclock -w
root@fl-imx6ull:~# hwclock -r
Thu Sep 21 12:51:36 2017 0.000000 seconds

hwclock -wu

root@fl-imx6ull:~# date
Thu Sep 21 12:52:51 HKT 2017
root@fl-imx6ull:~# hwclock -wu
root@fl-imx6ull:~# hwclock -r
Thu Sep 21 04:52:56 2017 0.000000 seconds

注意:如果开启了UTC,并且修改了时区,应该使用hwclock -wu

系统时间同步到RTC

hwclock --systohc

RTC时间同步到系统

hwclock --hctosys

4.系统同步RTC

前文提到,系统启动时,会将RTC时间读出来,作为系统时间。以imx6ull为例,上电之后,关于RTC的操作如下:

/etc/rcS.d/S55bootmisc.sh 当中,有以下内容

#
# This is as good a place as any for a sanity check
#  
# Set the system clock from hardware clock                    
# If the timestamp is more recent than the current time,
# use the timestamp instead.
test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh start
if test -e /etc/timestamp
then                                    
      SYSTEMDATE=`date -u +%4Y%2m%2d%2H%2M%2S`
      read TIMESTAMP < /etc/timestamp
      if [ ${TIMESTAMP} -gt $SYSTEMDATE ]; then
              # format the timestamp as date expects it (2m2d2H2M4Y.2S)
              TS_YR=${TIMESTAMP%??????????}  
              TS_SEC=${TIMESTAMP#????????????}
              TS_FIRST12=${TIMESTAMP%??}
              TS_MIDDLE8=${TS_FIRST12#????}
              date -u ${TS_MIDDLE8}${TS_YR}.${TS_SEC}
              test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh stop
      fi                    
fi    

这部分内容的主要作用是:

  • 调用/etc/init.d/hwclock.sh脚本,参数为start

  • 读取时间戳/etc/timestamp,和现有的系统时间进行对比,如果时间戳时间更靠后,则将时间戳当中的时间通过date写入系统,然后再次调用/etc/init.d/hwclock.sh,参数为stop

/etc/init.d/hwclock.sh内容如下,篇幅原因,只保留部分内容

......
[ "$UTC" = "yes" ] && tz="--utc" || tz="--localtime"
case "$1" in
      start)
......
if [ "$HWCLOCKACCESS" != no ]
then
if [ -z "$TZ" ]
then
                  hwclock $tz --hctosys
else
  TZ="$TZ" hwclock $tz --hctosys
fi
fi
......
      stop|restart|reload|force-reload)
......
if [ "$HWCLOCKACCESS" != no ]
then
hwclock $tz --systohc
fi
if [ "$VERBOSE" != no ]
then
echo "Hardware Clock updated to `date`."
fi
              exit 0
              ;;
......

这部分内容的主要作用如下:

  • 当启用UTC时,将tz变量赋值为“--utc”,反之为“--localtime”

  • 当参数为start时,执行hwclock $tz --hctosys,将硬件时间同步到系统时间;

    • 如果$UTC为yes,则认为读到的时间是UTC时间,反之认为读到的是localtime。

    • 这里的区别主要在于,如果系统认为读到的时间是UTC时间,则根据/etc/localtime指向的时区,对时间进行调整。比如当前时区为东八区,如果加了--utc,则系统会将读出来的时间加8小时。如果不加--utc,或者加--localtime,系统会认为读到的时间就是当前时间,不会再进行调整。

    • 注意hwclock -w默认写入的时间,是系统时间。hwclock -w是将当前系统时间写入到RTC;

    • hwclock -wu默认写入的时间,是utc时间。以东八区为例,hwclock -wu是将当前系统时间减8小时写入到RTC;

  • 当参数为stop时,执行hwclock $tz --systohc将系统时间写入到硬件RTC当中

    • 前文提到的当时间戳时间更靠后时,会进入这个分支;

    • 如果$UTC为yes,则认为将要写入的时间是UTC时间,反之认为将要写入的是localtime。

    • 这里的主要区别在于,如果加--utc参数,系统将date得到的系统时间,调整之后再写入硬件RTC,反之系统将时间直接写入RTC。以东八区为例,如果加了--utc参数,则将当前时间减八小时写入到RTC。如果不加--utc,或者加--localtime,系统会将当前系统时间直接写入到硬件RTC;

注:hctosys的全拼是hardware clock to system

systohc的全拼是system to hardware clock

timestamp时间戳的由来:

ls /etc/rc6.d/S25save-rtc.sh当中,有这样的内容:

date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp

由于系统的runlevel是5,系统启动时执行的是/etc/rc5.d可以从开机过程中的打印信息看出:

INIT: Entering runlevel: 5

通过在脚本当中加打印信息如下:

......
echo -e "\033[32mupdate timestamp\033[0m"
date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp
......

在调用reboot时,可以看到添加的打印信息:

root@fl-imx6ull:~# reboot
......
update timestamp
Unmounting remote filesystems...
urandom stop: failed.
Deactivating swap...
Unmounting local filesystems...
Rebooting... reboot: Restarting system

得出结论:执行reboot时,会将当前的系统时间,写入到时间戳当中。这样下次启动后的系统时间,一定会比reboot的时间要晚。

5.RTC测试

注意:以下几个案例都是以东8区为例

案例1:

将RTC时间手动设置比较靠前,比如2022年。

root@fl-imx6ull:~# date
Wed May 22 16:58:20 HKT 2024
root@fl-imx6ull:~# date -s "20220101 09:00:00"
Sat Jan 1 09:00:00 HKT 2022
root@fl-imx6ull:~# hwclock -wu
root@fl-imx6ull:~# hwclock -r
Sat Jan 1 01:00:50 2022 0.000000 seconds

此时执行reboot,重启后当前时间减去八小时变成了时间戳,同时时间戳被写入到了硬件时间。重启后的系统时间为:

root@fl-imx6ull:~# cat /etc/timestamp 
20220101010109
root@fl-imx6ull:~# date
Sat Jan 1 09:01:52 HKT 2022

此时给板子断电十分钟左右,确保RTC电池有电,十分钟后再次给板子上电,可以看到板子的时间为:

root@fl-imx6ull:~# cat /etc/timestamp 
20220101010109
root@fl-imx6ull:~# date
Sat Jan 1 09:13:49 HKT 2022

时间戳依旧保持不变

案例2:

将RTC时间手动设置比较靠前,比如2022年。

root@fl-imx6ull:~# date
Sat Jan 1 09:03:49 HKT 2022
root@fl-imx6ull:~# hwclock -w
root@fl-imx6ull:~# hwclock -r
Sat Jan 1 09:05:44 2022 0.000000 seconds

使用ntpdate对时,然后执行reboot,触发更新时间戳

root@fl-imx6ull:~# ntpdate cn.ntp.org.cn
22 May 18:05:10 ntpdate[664]: step time server 182.92.12.11 offset 75372823.050443 sec

更新后的时间戳为系统时间减8小时

root@fl-imx6ull:~# cat /etc/timestamp 
20240522100608
root@fl-imx6ull:~# date
Wed May 22 18:07:30 HKT 2024

此时断电10分钟左右,确保RTC电池有点,10分钟后再次给板子上电,板子的时间为:

root@fl-imx6ull:~# date
Wed May 22 18:17:57 HKT 2024
root@fl-imx6ull:~# cat /etc/timestamp
20240522100608

时间戳依旧保持不变

案例3:

使用hwclock -w将系统时间直接写入RTC,然后断电,不更新时间戳,重新上电

root@fl-imx6ull:~# hwclock -w
root@fl-imx6ull:~# hwclock -r
Wed May 22 19:01:17 2024 0.000000 seconds
root@fl-imx6ull:~# date      
Wed May 22 19:02:18 HKT 2024

此时时间戳保持不变,但系统时间往后移了8小时

root@fl-imx6ull:~# cat /etc/timestamp 
20240522022104
root@fl-imx6ull:~# date
Thu May 23 03:04:00 HKT 2024

案例4:

将RTC时间直接读出来作为系统时间,然后直接断电再重新上电

root@fl-imx6ull:~# date
Wed May 22 19:25:44 HKT 2024
root@fl-imx6ull:~# hwclock -wu
root@fl-imx6ull:~# hwclock -r
Wed May 22 11:25:53 2024 0.000000 seconds
root@fl-imx6ull:~# date
Wed May 22 19:25:56 HKT 2024
root@fl-imx6ull:~# hwclock --localtime --hctosys
root@fl-imx6ull:~# date
Wed May 22 11:26:49 HKT 2024
root@fl-imx6ull:~# cat /etc/timestamp
20240522022104

注意,系统时间要比时间戳时间靠后,才不会受时间戳影响

再次启动后,系统将RTC时间加八小时作为系统时间,所以时间是正常的

root@fl-imx6ull:~# date
Wed May 22 19:28:49 HKT 2024
root@fl-imx6ull:~# hwclock -r
Wed May 22 11:28:55 2024 0.000000 seco=nds

6.常见问题排查

6.1 断电时间丢失

  • 排查软件上有没有将时间写入到RTC

  • 测量小电池电压

  • 查看/dev下有几个rtc设备,一般有两个,如果只有1个说明外部RTC没有识别

6.2 外部RTC不识别

首先用i2ctools扫描I2C总线,看能否找到RTC芯片的I2C地址。RX8010的地址是0x32,PCF8563的地址是0x51。

如果找不到,排查硬件,可以检查焊接、晶振、供电、更换芯片;

如果能找到,但是显示的I2C地址是数字,说明驱动没有加载,检查镜像版本,是不是用的比较老的镜像,没有支持PCFD8563;

如果能找到,并且显示UU,这种情况出现的可能性不大。如果遇见,可以从这几个方面排查:查看系统启动的打印信息,RTC加载的部分,内核有没有报错;排查硬件上是不是有地址冲突。

RX8010

root@fl-imx6ull:~# i2cdetect -r -y 0
    0 1 2 3 4 5 6 7 8 9 a b c d e f
00:         -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --    


已解决

未解决

只是看看

最新评论

QQ|小黑屋| 飞凌嵌入式 ( 冀ICP备12004394号-1 )

GMT+8, 2025-7-10 00:54

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

返回顶部