当前位置: 首页 > news >正文

STM32基础篇:RTC × Unix时间戳 × BKP

Unix时间戳

最早是在Unix系统使用的,之后很多由Unix演变而来的系统也都继承了Unix时间戳的规定。目前,Linux、Windows、安卓这些系统,其底层的计时系统都是使用Unix时间戳。

Uinx时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒。也就是说时间戳是一个秒计数器,且只记秒,不会向分钟、小时进位。

其年月日小时分钟均通过计算秒得出。

世界上所有时区共用一个时间戳的秒计数器,不同时区通过添加偏移来得到当地时间。如上图所示,相比于伦敦,北京时间偏移了8个小时。


UTC/GMT

GMT格林尼治标准时间,可理解为伦敦时间,是一种以地球自转为基础的时间计量系统。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准。

但GMT是以前的时间标准,因为地球自转一周的时间是不固定的,由于潮汐力、地球活动等原因,地球目前是越转越慢的,因此时间基准也是不固定的(即1秒到底是多长)。

为了时间的定义更标准,科学家又提出来新的计时系统,叫做UTC,即协调世界时。是一种以原子钟为基础的时间计量系统。它规定铯133原子基态的两个超精细能级间在零磁场下跃迁辐射9192631770周所持续的时间为1秒。

当原子钟计时一天的时间与地球自转一周的时间相差超过0,9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致。

闰秒:计时标准是恒定不变的,但是地球越转越慢,误差超过0.9秒时,计时系统就多走一秒来等一下地球的自转。


时间戳转换

C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换。

函数

作用
time_t time(time_t *seconds)获取系统时钟

struct tm *gmtime(const time_t *timer)

秒计数器转换为日期时间(格林尼治时间)

struct tm *localtime(const time_t *timer)

秒计数器转换为日期时间(当地时间)

time_t mktime(struct tm *timeptr)

日期时间转换为秒计数器(当地时间)

char *ctime(const time_t *timer)

秒计数器转换为字符串(默认格式)

char *asctime(const struct tm *timeptr)

日期时间转换为字符串(默认格式)

size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)

日期时间转换为字符串(自定义格式)

数据类型:

1、秒计数器时间类型:time_t,64位有符号的整型数据,用于存储时间戳中一直自增的秒数。

2、日期时间类型:struct tm,是一个结构体,具体如下:

3、字符串时间类型:char*,就是char类型数据的指针。用来指向一个表示时间的字符串。


BKP简介

BKP备份寄存器,可用于存储用户应用程序数据,当VDD(2.0~3.6V)电源被切断,他们仍然由VBAT(1.8~3.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位(除非VBAT掉电)。

用户数据存储容量:

20字节中容量和小容量
84字节大容量和互联型

对于C8T6芯片,为中容量,对应20字节。可以看出BKP的容量其实非常小,一般只能存储少量的参数。


BKP基本结构

  • 后备区域

图中的橙色部分,我们可以叫做后备区域。注意,是BKP处于后备区域,但后备区域不只有BKP,还有RTC的相关电路。

STM32后备区域的特性就是:当VDD主电源掉电时,后备区域仍然可以由VBAT的备用电池供电;当VDD上电时,后备区域供电会由VBAT切换为VDD,可以节省电池电量。

  • 内部寄存器

BKP里主要有状态寄存器、控制寄存器、数据寄存器、RTC时钟校准寄存器。其中数据寄存器是主要部分,用来存储数据的。每个数据寄存器都是16位的(一个数据寄存器可以存2个字节),对于中容量和小容量的设备,里面有DR1~DR10总共10个数据寄存器,共20个字节。

  • 侵入检测

BKP可以从PC13位置的TAMPER引脚引入一个检测信号,当TAMPER产生一个上升沿或者下降沿时,会清除BKP所有的内容,以保证安全。

  • 时钟输出

将RTC的相关时钟从PC13位置的RTC引脚输出出去,供外部使用。其中,输出校准时钟时,再配合RTC时钟校准寄存器,可以对RTC的误差进行校准。


RTC简介

RTC即实时时钟,STM32中RTC是一个独立的定时器,可为系统提供时钟和日历(年月日时分秒)的功能。挂在APB1总线上。

RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD(2.0~3.6V)断电后可借助VBAT(1.8~3.6V)供电继续走时。

  • 秒计数器与分频器

在RTC中,负责计数的装置只有一个32位的秒计数器。且1秒就要自增一次,所以驱动秒计数器的时钟---TR_CLK是一个1Hz的信号。但实际提供给RTC的时钟,也就是RTCCLK,一般频率都比较高。所以显然需要在这之间加一个分频器,保证输出给计数器的频率为1Hz。

RTC中的预分频器,是一个20位的分频器(可编程),可以选择对输入时钟进行1~2^20分频,这样可以适配不同频率的输入时钟。

  • RTC时钟来源

RTCCLK的来源主要有以下3种:

HSE时钟除以1288MHz/128
LSE振荡器时钟37.768KHz
LSI振荡器时钟40KHz

其中HSE是高速外部时钟信号(通常为高速晶振)、LSE低速外部时钟信号、LSI低速内部时钟信号。具体可参考RCC章节知识。

【注意】为了更好使用RTC模块,外部硬件电路也需要配置好。即备用电池模块、外部低速晶振等。


RTC框图

左边阴影区为核心的分频和计数区域,右边为中断输出使能和NVIC部分,上面为APB1总线读写部分,下面阴影区是与PWR关联的部分。(阴影区均为后备区域)

【注意】对于RTC和BKP的寄存器,其实都是16位的。例如左边的RTC_CR控制寄存器,实际上是两个16位的寄存器(RTC_CRH和RTC_CRL)。

  • 分频器

由两个寄存器组成,即重装载寄存器RTC_PRL余数寄存器RTC_DIV,与定时器时基单元的计数器CNT和重装寄存器ARR是一样作用。(且计几个数,溢出一次,就是几分频)

RTC_DIV是自减的计数器,每来一个输入时钟,DIV的值自减一次,自减到0时,再来一个时钟,DIV输出一个脉冲(溢出信号),同时从PRL获取重装值,回到重装值继续自减。

  • 闹钟寄存器

RTC内部除了32位的秒寄存器(RTC_CNT)外,还有一个32位的闹钟寄存器(RTC_ALR),其作用为设置闹钟。

我们可以在ALR里写一个秒数,设定闹钟,当CNT值与ALR设定的闹钟值一样时,就会产生RTC_Alarm闹钟信号,通向右边的中断系统。在中断函数里,可执行需要的操作。

【注意】RTC_Alarm闹钟信号还可使主机退出待机模式。

  • 中断

除了上述的RTC_Alarm闹钟信号能触发中断外,还有RTC_SecondRTC_Overflow能够触发中断。

其中RTC_Second是秒中断,开启后每秒触发一个中断。RTC_Overflow是指当32位的秒计数器计满后溢出时触发的中断,这个中断得到2106年才会触发。


RTC操作注意事项

  • 1、使能

对于一般的片上外设,只需要开启时钟使能即可使用。但对于RTC模块却有些复杂,首先要设置RCC_APB1ENR(开启APB1上外设的时钟),要同时开启PWR和BKP的时钟。然后设置PWR_CR的DBP位,来使能对BKP和RTC的访问。

  • 2、关于读取

若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1。

可观察RTC内部框图,可以看出APB1的时钟为PCLK1,在主电源掉电时会停止;而RTC里的寄存器时钟为RTCCLK。当我们用PCLK1驱动的总线去读取RTCCLK驱动的寄存器时,就会有一个时钟不同步的问题。PCLK1的频率为36MHz,远大于RTCCLK的36KHz,如果在APB1刚开启时就立刻读取RTC寄存器,有可能RTC寄存器还没有更新到APB1总线上,这样读取到的值为错误的。

所以APB1总线刚开启时,要等一下RTCCLK,只要RTCCLK来一个上升沿,RTC把它的寄存器值同步到APB1总线上。

  • 3、关于写入

必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器。

在STM32的标准库函数中,写寄存器的函数都自动帮我们加上了这个操作,不需要我们再配置了。

  • 4、写等待机制

对于RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF为1时,才可以写入RTC寄存器。

因为RCLK1与RTCCLK时钟频率不同,用PCLK的频率写入后,这个值还不能立刻更新到RTC寄存器里面,要等RTCCLK时钟来一个上升沿,值更新到RTC寄存器里,写入才算完成。


相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • [Deepin] 简单使用 RustDesk 实现远程访问Deepin
  • LeetCode 热题100-70 最小栈
  • [数据库][oracle]ORACLE EXP/IMP的使用详解
  • MySQL数据类型-介绍
  • 服务器安装pytorch-阿里云-centos7
  • springboot启动很慢,加载xml时卡住 或者 {dataSource-1} inited卡住 或者 primary数据库配置错误,很久启动不起来
  • PHP + Redis 实现抽奖算法(ThinkPHP5)
  • 145. 利用 Redis Bitmap实践: 用户签到统计
  • 【ArcGIS Pro原理第一期】各种空间插值原理:GPI、LPI、IDW等
  • 七月刚入职字节跳动的测试开发面试题,附答案
  • 【全网最全】《2024高教社杯/国赛》 C题 思路+代码+文献 蒙特卡洛+遗传算法 一到三问 农作物的种植策略
  • Linux系统运行模式以及链接文件
  • 高级java每日一道面试题-2024年9月04日-前端篇-前端的框架分类有哪些?
  • Google Research 推出高效的Prompt Tuning方法
  • pointer-events: auto; 是一个 CSS 属性,
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • Angular Elements 及其运作原理
  • css系列之关于字体的事
  • ES6系统学习----从Apollo Client看解构赋值
  • Javascript 原型链
  • Java知识点总结(JavaIO-打印流)
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • vagrant 添加本地 box 安装 laravel homestead
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 少走弯路,给Java 1~5 年程序员的建议
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 微信支付JSAPI,实测!终极方案
  • 写代码的正确姿势
  • mysql面试题分组并合并列
  • ​Java基础复习笔记 第16章:网络编程
  • (阿里云万网)-域名注册购买实名流程
  • (笔试题)分解质因式
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (九)c52学习之旅-定时器
  • (九)信息融合方式简介
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (十七)Flink 容错机制
  • (十五)使用Nexus创建Maven私服
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET Core 项目指定SDK版本
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET Micro Framework初体验
  • .Net 基于.Net8开发的一个Asp.Net Core Webapi小型易用框架
  • .NET 某和OA办公系统全局绕过漏洞分析
  • .Net接口调试与案例
  • .NET企业级应用架构设计系列之开场白
  • .Net下使用 Geb.Video.FFMPEG 操作视频文件
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • @ConditionalOnProperty注解使用说明