首先是理论知识Unix时间戳:
时间戳只显示秒,没有进位,永不进位的秒计数器,60秒就是60秒,100秒就是100秒,它可以和年月日/时分秒进行转换
优点:1、简化硬件电路(只需要考虑秒的容量,不需要考虑其他年月日时分等的数值)
2、时间间隔计算方便,例如:1月1日8点到3月1日18点之间经过了多少个小时,使用时间戳就直接两个秒数相减/60即可
3、存储方便,只有一个变量
缺点:占用软件资源,在秒转化为其他形式如:年月日时分时就需要进行一系列转换操作
32位有符号的时间戳会在2038年1月19日溢出,32位无符号则是在2106年溢出
时间标准:从GMT(与地球实际自转时间有关,不固定)到UTC
闰秒:1分钟可能出现61秒的情况,可能会出现23:59:60
以下是时间戳和其他的转换,第2、3、4最重要
其中mktime是依据当地时间进行转换秒数
time_t是64位的int类型;
最后一个参数表示是否使用夏令时
调用localtime函数显示时间的年月日时分秒和星期
之后是BKP和RTC的理论知识
1、BKP
当VDD掉电时,由VBAT供电,此时数据仍然存在,如果VBAT也掉电,此时数据消失。
VDD供电时,VBAT不供电
本节使用的是C8T6因此使用20字节的BKP
侵入检测:当TAMPER为上升沿/下降沿时,BKP的数据寄存器里边数据全部清空,以保证安全
2、RTC
HSE/128,为保证最后等得到1Hz,先分频,之后再适当分频即可得到,RTC备选时钟;
一般选用LSE振荡器时钟,因为它存在自然溢出,32.768KHz表示2^15次,当计数值到32767时再计一位就会溢出,此时刚好就是1Hz,不需要再设置什么计数目标值;只有这一路可以用VBAT供电;
LSI一般是RTC的备选方案,它一般用于看门狗;
以下是硬件电路设计:
灰色部分表示VDD掉电后,备用供电还可运行
当RTCCLK时钟信号来临,由于32.768KHz过大,因此需要先进行分频操作。DIV属于自减计数器,当计数值为32767时,来一个时钟信号,减1,直到为0后再输入一个就会溢出并产生溢出信号重新回到32767,分频输出的频率为1Hz,提供给后续秒计数器。
当CNT=ALR就会产生一个RTC闹钟信号引发中断,并唤醒待机模式(或者WKUP唤醒闹钟)
需要配置数据选择器选择哪一个为时钟来源、配置重装寄存器选择分频系数、配置32位计数器得到日期等的书写
可以不用ALR;
在代码方面,使用BKP和RTC时需要注意:
1、开启PWR和BKP的时钟;之后将PWR的DBP开启使能,对BKP和RTC访问
2、当APB1刚开启时,需要等待RTC_CRL时钟的RSF位置1(RTC_CRL来一个上升沿,此时RTC将值同步到总线上),这表明此时有数计入,不然直接读取可能为0还未读入
代码部分:定义变量
1、由于BKP代码少,直接在main函数进行编辑:
进行实验:
1、写入数据之后,复位数据依然没有变化,不为0
2、主电源拔下又插入,数据依然没有变化,由备用电源供电
3、备用电源拔掉,主电源重新拔掉又插上
此时BKP数据清零
2、RTC实时时钟
需要对RTC进行封装:开启PWR和BKP时钟,并对pwr开启使能------开启LSE时钟------配置RTCCLK的时钟数据选择器------调用等待函数(等待数据同步、上一次操作完成)------配置预分频器(确保输出1Hz)------配置CNT值,给RTC初始时间------中断(需要配置,不需要不用)
当BKP的数据不清零时,表示主电源掉电但是备用电源依然有;
如果BKP存储的数据清零,则表示主电源和备用电源都掉电,此时则整体数据重置。
当BKP的标志位是0xA5A5(随意写入,除0x00),则表明RTC初始化过,且备用电源没断电,则不需要再初始化:
自定义时间:注意不要在数字前补0,在C语言中前有0默认为8进制,当写入09时就会报错:
转换日期为秒数等函数,调用time.h
将数组自定义填充时间放到struct tm中------使用mktime得到秒数------将秒数写到CNT中
之后是将秒数转换为日期等:
在main函数直接显示:
DIV是自减寄存器,如果想让它的取值在0-999
实验结果: