江科大STM32入门——读写备份寄存器(BKP)实时时钟(RTC)笔记整理

wx:嵌入式工程师成长日记

ddd39e6b19e14e33897aa6213919c759.png

https://mp.weixin.qq.com/s/hDk7QaXP8yfYIj1gUhtMrw?token=1051786482&lang=zh_CNicon-default.png?t=O83Ahttps://mp.weixin.qq.com/s/hDk7QaXP8yfYIj1gUhtMrw?token=1051786482&lang=zh_CN

RTC是一个独立的定时器,BKP并不能完全掉电不丢失,其可以完成一些主电源掉电时,保存少量数据的任务。而RTC在主电源掉电的时候保证掉电不丢失的关键就是BKP。

(一)时间戳

1、简介

  • Unix时间戳(UnixTimestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数(只用秒来计数,永不进位)
  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量(32位2038年到头,无符号是2106年)
  • 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间

图片

对于计算器来说一个永不进位的数据,无论是存储还是计算,都是非常方便的,因此在计算程序的底层,应用非常广泛。需要显示当前时间时,直接转换成年月日时分秒这个的格式就行了。

【使用好处】:

①简化硬件电路:在设计RTC硬件电路的时候,直接弄一个很大的秒寄存器就行了,不需要考虑年月日进位大小月平年论润,非常友好。

②进行时间间隔的计算非常方便。

③存储方便,只需要一个很大的变量表示秒数。

2、GMT/UTC

图片

3、时间戳转换

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

图片

图片

(二)BKP外设

  • BKP(备份寄存器)

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

  • (VBAT:当使用电池或其他电源连接到VBAT脚上时,当VDD断电时,可以保存备份寄存器的内容和维持RTC的功能。如果应用中没有使用外部电池,VBAT引脚应接到VDD引脚上)

  • TAMPER引脚产生的侵入事件将所有备份寄存器内容清除

    1. TAMPER引脚是用于引入检测信号(可以是或上升沿/下降沿)的,当发生入侵时,将清除BKP所有内容,并申请中断。

    2. 并且是由备用电源供电,主电源断电后侵入检测仍然有效,以保证数据安全

  • RTC引脚输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲

  • 存储RTC时钟校准寄存器

  • 用户数据存储容量:20字节(中容量和小容量)/84字节(大容量和互联型)

  • 如果备用电源VBAT和主电源VCC都断电了,就会清除数据,因为BKP本质是RAM存储器,掉电丢失数据

2、BKP基本结构

橙色的是后背区域,除了BKP还有RTC电路。STM32后备区的特性是的那个VDD主电源掉电时,后备区仍然可以由VBAT的备用电池供电。当VDD主电源上电时候,后背区域会由VBAT切换到VDD,可以节省电池电量。

图片

(三)RTC外设

  • RTC(Real Time Clock)实时时钟

  • RTC是一个独立的定时器,可为系统提供时钟和日历的功能

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

  • 32位的可编程计数器

  • 20位的可编程预分频器,可适配不同频率的输入时钟(确保给到计数器的是1Hz的频率)

  • 可选择三种RTC时钟源:(LSE(低速外部时钟)主要就是供RTC的,只有这一路时钟可以通过VBAT备用电池供电)
    • HSE时钟除以128(通常为8MHz/128)

    • LSE振荡器时钟(通常为32.768KHz)

    • LSI振荡器时钟(40KHz)

2、RTC框图

图片

图片

3、RTC基本结构

图片

4、硬件电路

如果没有外部电池,建议VBAT引脚接到VDD,就是VBAT和主电源接到一起,并且再连接一个100nF的滤波电容

图片

图片

(四)RTC常用函数

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);//RTC 中断使能:通过传入指定的中断类型 RTC_IT 和状态 NewState,实现对 RTC 中断的使能或失能控制。
void RTC_EnterConfigMode(void);//进入 RTC 配置模式:用于进入 RTC 的配置状态,以便进行相关参数的修改。
void RTC_ExitConfigMode(void);//退出 RTC 配置模式:在完成 RTC 配置操作后,使用此函数退出配置模式。
uint32_t RTC_GetCounter(void);//获取 RTC 计数器的值:返回 RTC 计数器的当前数值。
void RTC_SetCounter(uint32_t CounterValue);//设置 RTC 计数器的值:将 RTC 计数器设置为指定的数值 CounterValue。
void RTC_SetPrescaler(uint32_t PrescalerValue);//设置 RTC 预分频的值:为 RTC 预分频设置特定的值 PrescalerValue。
void RTC_SetAlarm(uint32_t AlarmValue);//设置 RTC 闹钟的值:设定 RTC 闹钟的触发值为 AlarmValue。
uint32_t RTC_GetDivider(void);//获取 RTC 预分频分频因子的值:获取当前 RTC 预分频分频因子的数值。
void RTC_WaitForLastTask(void);//等待最近一次对 RTC 寄存器的写操作完成:确保之前对 RTC 寄存器的写入操作已经完成。
void RTC_WaitForSynchro(void);//等待 RTC 寄存器与 RTC 的 APB 时钟同步:等待 RTC 相关寄存器(如 RTC_CNT、RTC_ALR 和 RTC_PRL)与 APB 时钟完成同步。
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);//检查指定的 RTC 标志位设置与否:通过传入标志位 RTC_FLAG,返回其状态。
void RTC_ClearFlag(uint16_t RTC_FLAG);//清除 RTC 的待处理标志位:清除指定的 RTC 标志位。
ITStatus RTC_GetITStatus(uint16_t RTC_IT);//检查指定的 RTC 中断发生与否:根据传入的中断类型 RTC_IT,判断中断是否发生。
void RTC_ClearITPendingBit(uint16_t RTC_IT);//清除 RTC 的中断待处理位:清除指定 RTC 中断的待处理位。

读写RTC实时时钟步骤

1.开启PWR和BKP的时钟  PWR的开启函数为RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); 开启后备电源的时钟  BKP的开启函数RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); 开启BKP外设的时钟
2.使能备份区域的访问  在STM32中,想访问RTC和BKP,就要先开启备份区域的访问权限。  函数:PWR_BackupAccessCmd(ENABLE);
3.判断是否需要初始化RTC
4.开启LSE时钟    开启LSE时钟 RCC_LSEConfig(RCC_LSE_ON);    等待LSE时钟开启完毕 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);    选择RTCCLK时钟为LSERCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);    使能RTCCLK时钟 RCC_RTCCLKCmd(ENABLE);
5.等待时钟同步    因为可能在恢复主电源之后,APB1总线刚刚恢复震荡频率,但是RTCCLK需要经过外部震荡源分频后才能有一次输出。    如果直接读取,会导致读取不准确。     所以需要等待RTCCLK产生上升沿来激活更新一下时间戳计数器,这时APB1直接读取。 所以软件读取时必须等待RTCCLK来一个上升沿。    函数:RTC_WaitForSynchro(); (等待时钟同步)
6.等待写入完成    对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。    可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。 当RTOFF状态位是1时,才可以写入RTC寄存器    函数:RTC_WaitForLastTask();
7.设置RTC预分频器    设置预分频器RTC_SetPrescaler(32768 - 1);    等待写入完成RTC_WaitForLastTask();
8.写入前其实是需要设置RTC_CRL寄存器中的CNF位    RTC进入配置模式后,才能写入RTC_PRL(预分频器)、RTC_CNT(时间戳计数器)、RTC_ALR(闹钟寄存器)寄存器
9.设置CNT时间戳计数器时间    利用C语言中time.h来转换时间戳并写入
在BKP备份寄存器中写入特定数据。为下次复位或仅主电源断电后上电时判断是否初始化打下基础
初始RTC:void MyRTC_Init(void){    /*开启时钟*/    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);     //开启PWR的时钟    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);     //开启BKP的时钟    /*备份寄存器、RTC访问使能*/    PWR_BackupAccessCmd(ENABLE);                            //使用PWR开启对备份寄存器和RTC的访问    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)          //通过写入备份寄存器的标志位,判断RTC是否是第一次配置                                                            //if成立则执行第一次的RTC初始化    {        RCC_LSEConfig(RCC_LSE_ON);                          //开启LSE时钟        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);  //等待LSE准备就绪        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);             //选择RTCCLK来源为LSE        RCC_RTCCLKCmd(ENABLE);                              //RTCCLK使能        RTC_WaitForSynchro();                               //等待同步        RTC_WaitForLastTask();                              //等待上一次操作完成        RTC_SetPrescaler(32768 - 1);                        //设置RTC预分频器,预分频后的计数频率为1Hz        RTC_WaitForLastTask();                              //等待上一次操作完成        MyRTC_SetTime();                                    //设置时间,调用此函数,全局数组里时间值刷新到RTC硬件电路        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);           //在备份寄存器写入自己规定的标志位,用于判断RTC是不是第一次执行配置    }    else                                                    //RTC不是第一次配置    {        RTC_WaitForSynchro();                               //等待同步        RTC_WaitForLastTask();                              //等待上一次操作完成    }}
时钟设置:void MyRTC_SetTime(void){    time_t time_cnt = 0;    //定义秒计数器数据类型    struct tm time_date;    //定义日期时间数据类型
    time_date.tm_year = MyRTC_Time[0] - 1900;       //将数组的时间赋值给日期时间结构体    time_date.tm_mon = MyRTC_Time[1] - 1;    time_date.tm_mday = MyRTC_Time[2];    time_date.tm_hour = MyRTC_Time[3];    time_date.tm_min = MyRTC_Time[4];    time_date.tm_sec = MyRTC_Time[5];
    time_cnt = mktime(&time_date) - 8 * 60 * 60;    //调用mktime函数,将日期时间转换为秒计数器格式                                                    //- 8 * 60 * 60为东八区的时区调整    RTC_SetCounter(time_cnt);                       //将秒计数器写入到RTC的CNT中    RTC_WaitForLastTask();                          //等待上一次操作完成}
读取时间:void MyRTC_ReadTime(void){    time_t time_cnt;        //定义秒计数器数据类型    struct tm time_date;    //定义日期时间数据类型
    time_cnt = RTC_GetCounter() + 8 * 60 * 60;      //读取RTC的CNT,获取当前的秒计数器                                                    //+ 8 * 60 * 60为东八区的时区调整
    time_date = *localtime(&time_cnt);              //使用localtime函数,将秒计数器转换为日期时间格式
    MyRTC_Time[0] = time_date.tm_year + 1900;       //将日期时间结构体赋值给数组的时间    MyRTC_Time[1] = time_date.tm_mon + 1;    MyRTC_Time[2] = time_date.tm_mday;    MyRTC_Time[3] = time_date.tm_hour;    MyRTC_Time[4] = time_date.tm_min;    MyRTC_Time[5] = time_date.tm_sec;}

(五)BKP常用函数

void BKP_DeInit(void);//恢复缺省配置(用于清空BKP所有BKP寄存器)
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);//配置TAMPER引脚的有效电平
void BKP_TamperPinCmd(FunctionalState NewState);//是否开启侵入检测功能
void BKP_ITConfig(FunctionalState NewState);//是否开启中断
void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);//时钟输出功能配置(在RTC引脚上输出时钟信号、RTC校准时钟、RTC闹钟脉冲、秒脉冲)
void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);//设置RTC校准值
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data); //写BKP备份寄存器 
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR); //读BKP寄存器 
FlagStatus BKP_GetFlagStatus(void);//查看标志位
void BKP_ClearFlag(void);//清除标志位
ITStatus BKP_GetITStatus(void);//查看中断标志位
void BKP_ClearITPendingBit(void);//清除中断标志位

读写BKP备份寄存器步骤

1.开启PWR(电源控制)和BKP的时钟    PWR的开启函数为RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); (开启后备电源VBAT)    BKP的开启函数RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); 开启BKP外设的时钟,都在APB1总线下
2.使能备份区域的访问    因为RTC实时时钟和BKP备份寄存器,都处于备份区域中。在STM32中,想访问RTC和BKP,就要先开启备份区域的访问权限。    函数:PWR_BackpAccessCmd(ENABLE);
3.读写操作    写入:BKP_WriteBackupRegister(BKP_DR1,Data);    读出:Data = BKP_ReadBackupRegister(BKP_DR1);
uint16_t WriteArr[] = {0x0000, 0x0001};uint16_t ReadArr[2] = { 0 };
int main(){    //使能时钟电源和后备接口时钟    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
    //使能备份访问控制    PWR_BackupAccessCmd(ENABLE);    while(1)    {        if(KEY_Get() == 1)        {            //写入BKP            BKP_WriteBackupRegister(BKP_DR1,WriteArr[0]);            BKP_WriteBackupRegister(BKP_DR2,WriteArr[1]);
            WriteArr[0]++;            WriteArr[1]++;        }        //读取BKP        ReadArr[0] = BKP_ReadBackupRegister(BKP_DR1);        ReadArr[1] = BKP_ReadBackupRegister(BKP_DR2);    }}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GitLab CI/CD使用runner实现自动化部署前端Vue2 后端.Net 7 Zr.Admin项目

1、查看gitlab版本 建议安装的runner版本和gitlab保持一致 2、查找runner 执行 yum list gitlab-runner --showduplicates | sort -r 找到符合gitlab版本的runner,我这里选择 14.9.1版本 如果执行出现找不到下载源,添加官方仓库 执行 curl -L &quo…

MySQL解压版(保姆级教程)

文章目录 1. 下载MySQL2. 解压压缩包3. 添加环境变量4. 创建配置文件5. 启动管理员模式下的CMD6. 重启mysql7. 检查服务是否成功启动8. 可能遇见的错误🎯 数据目录未正确初始化🎯 MySQL服务已存在但路径错误🎯 端口被占用🎯 MySQL…

人工智能实验(四)-A*算法求解迷宫寻路问题实验

零、A*算法学习参考资料 1.讲解视频 A*寻路算法详解 #A星 #启发式搜索_哔哩哔哩_bilibili 2.A*算法学习网站 A* 算法简介 一、实验目的 熟悉和掌握A*算法实现迷宫寻路功能,要求掌握启发式函数的编写以及各类启发式函数效果的比较。 二、实验要求 同课本 附录…

【Vue实战】Vuex 和 Axios 拦截器设置全局 Loading

目录 1. 效果图 2. 思路分析 2.1 实现思路 2.2 可能存在的问题 2.2.1 并发请求管理 2.2.2 请求快速响应和缓存带来的问题 3. 代码实现 4. 总结 1. 效果图 如下图所示,当路由变化或发起请求时,出现 Loading 等待效果,此时页面不可见。…

Github配置ssh key,密钥配对错误怎么解决?

解决密钥配对的方案如下: 方法一、最有效的方案:重新配置,验证 SSH 密钥是否已添加到 GitHub 确保您的 SSH 密钥已经正确添加到了 GitHub 账户中。您可以打开命令行控制台(cmd/powerShell都可以),按照以下…

Java基础知识(六) -- 常用类

1.包装类 1.1 概述 Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,但当使用只针对对象设计的API或新特性(例如泛型),那么基本数据类型的数据就需要用包装类来包装。 序号基本数据类型包装类(java…

【Linux】深入理解文件系统(超详细)

目录 一.磁盘 1-1 磁盘、服务器、机柜、机房 📌补充: 📌通常网络中用高低电平,磁盘中用磁化方向来表示。以下是具体说明: 📌如果有一块磁盘要进行销毁该怎么办? 1-2 磁盘存储结构 ​编辑…

【硬件介绍】Type-C接口详解

一、Type-C接口概述 Type-C接口特点:以其独特的扁头设计和无需区分正反两面的便捷性而广受欢迎。这种设计大大提高了用户的使用体验,避免了传统USB接口需要多次尝试才能正确插入的问题。Type-C接口内部结构:内部上下两排引脚的设计虽然可能不…

Linux第二课:LinuxC高级 学习记录day02

2.4、shell中的特殊字符 2.4.4、命令置换符 或者 $() 反引号:esc下面的按键,英文状态下直接按 功能:将一个命令的输出作为另一个命令的参数 echo 不会认为hostname是一个命令 加上 之后,先执行hostname,拿到主机名…

图生生AI描述生图:一句话生成蛇年海报素材

2025年春晚吉祥物“巳升升”的亮相,引发了广泛讨论。其整体造型参考甲骨文中的“巳”字,以青绿色为主调,象征春意盎然、蓬勃生机。从头部轮廓、脸颊螺旋形状到五官设计,都蕴含着丰富的传统文化元素。巳升升的亮相,春节…

KMP前缀表 ≈ find() 函数——28.找出字符串中第一个匹配项的下标【力扣】

class Solution { public: //得到前缀表void getNext(int *next,string needle){int j0;for(int i1;i<needle.size();i){while(j>0 && needle[j]!needle[i]) jnext[j-1];//**j>0**>j0是出口if(needle[i]needle[j]) j;next[i]j;//若写入if中&#xff0c;则该…

前端笔记----

在我的理解里边一切做页面的代码都是属于前端代码。 之前用过qt框架&#xff0c;也是用来写界面的&#xff0c;但是那是用来写客户端的&#xff0c;而html是用来写web浏览器的&#xff0c;相较之下htmlcssJavaScript写出来的界面是更加漂亮的。这里就记录我自个学习后的一些笔…

FairGuard游戏安全2024年度报告

导 读&#xff1a;2024年&#xff0c;国内游戏市场实际销售收入3257.83亿元&#xff0c;同比增长7.53%&#xff0c;游戏用户规模6.74亿人&#xff0c;同比增长0.94%&#xff0c;市场收入与用户规模双双实现突破&#xff0c;迎来了历史新高点。但游戏黑灰产规模也在迅速扩大&…

C++ STL之容器介绍(vector、list、set、map)

1 STL基本概念 C有两大思想&#xff0c;面向对象和泛型编程。泛型编程指编写代码时不必指定具体的数据类型&#xff0c;而是使用模板来代替实际类型&#xff0c;这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C泛型编程的一个杰出例子。STL&#xff08;Standard …

uniapp 抖音小程序 getUserProfile:fail must be invoked by user tap gesture

项目场景&#xff1a; uniapp 抖音小程序 getUserProfile:fail must be invoked by user tap gesture,在实现点击头像需要出发抖音小程序获取用户原生头像的操作中&#xff0c;无论如何也无法触发抖音的原生窗口&#xff01; 问题描述 这个问题我找了很多博主的方法&#xff…

.NET Core NPOI 导出图片到Excel指定单元格并自适应宽度

NPOI&#xff1a;支持xlsx&#xff0c;.xls&#xff0c;版本>2.5.3 XLS&#xff1a;HSSFWorkbook&#xff0c;主要前缀HSS&#xff0c; XLSX&#xff1a;XSSFWorkbook&#xff0c;主要前缀XSS&#xff0c;using NPOI.XSSF.UserModel; 1、导出Excel添加图片效果&#xff0…

SpringCloud微服务:基于Nacos组件,整合Dubbo框架

dubbo和fegin的差异 一、Feign与Dubbo概述 Feign是一个声明式的Web服务客户端&#xff0c;使得编写HTTP客户端变得更简单。通过简单的注解&#xff0c;Feign将自动生成HTTP请求&#xff0c;使得服务调用更加便捷。而Dubbo是一个高性能、轻量级的Java RPC框架&#xff0c;提供了…

Jenkins触发器--在其他项目执行后构建

前言&#xff1a; jenkins中有多种触发器可用&#xff0c;可以方便的控制构建的启动 这里简单介绍下项目后构建的配置方法 1. 解释&#xff1a; Build after other projects are built Set up a trigger so that when some other projects finish building, a new build is…

4、蓝牙打印机-定时器驱动

蓝牙打印机实现打印内容&#xff0c;需要先通过定时器发送固定的节拍驱动步进电机转动&#xff0c;从而驱动打印头打印相应的内容。 因此想要实现打印&#xff0c;先要实现定时器功能。 本例采用通用定时器2完成发送节拍功能。 1、硬件 定时器总线 由上图知道TIM2是挂载在A…

(纯小白教程)Mac OS中安装配置Anaconda及常用conda命令回顾

本教程介绍了如何在Mac OS系统中下载、安装、配置 Anaconda3&#xff0c;并介绍了换源的方法&#xff0c;最后介绍了常用的conda命令。本教程适用于苹果系统&#xff0c;如需要在Windows系统或者Liunx系统中安装Anaconda3&#xff0c;可移步至主页的其他博客。 &#xff08;纯…