STM32-BKP备份寄存器RTC实时时钟
一、原理
Unix:

一些系统是使用32bit有符号数存储,实际范围为-2,147,483,648到2,147,483,647即~
经过计算int32数据会在2038年1月19日溢出,可以看到转换的为北京时间。


STM32的时间戳为无符号时间戳。
我们需要把秒计数器的时间通过计算得到秒技术其对应的时间,然后根据时区进行偏移(考虑到品平年闰年,大月小月闰月等)。
可以根据c语言官方函数直接计算:

UTC、GMT
GMT是之前的时间标准,UTC是计算了偏移量的现行标准。中国一般使用GMT+8/UTC+8。Unix时间戳没有闰秒,即协调世界时间的功能,所以可能秒数会偏差。
时间戳和日期进行转换(数据类型):

time_t实际上是int64类型,用来存储秒计数值

tm类型为定义日期的结构体:struct tm
其中year为从1900年的第几年(最小应该为70);mon月份从0开始;wday表示周几;yday表示每年的第几天;isdst是否使用夏令时,1表示用,0不用,-1表示不知道。

夏令时为在夏天的某段时间将时间提前一个小时。
实际使用:

mktime函数原理,通过输入的年月日时分秒计算,其他参数会自动计算回填,可以通过此函数自动计算星期。


strftime函数参数(char *c,size_length,const *char,const struct tm*),其中const *char为格式字符串。函数使用为,将const struct tm*的内容通过const *char格式化字符存入长度为size_length的数组char *c中。
其他函数:

二、 STM32的BKP备份寄存器&RTC实时时钟
1、BKP原理:
BKP寄存器数据需要VBT保持供电来进行掉电不丢失,实际使用方式和Flash类似。手册建议VBT无外部供电时接到VDD并上100nf的滤波电容。

TAMPER在STM32F103C8T6中在PC13。可以外接上拉电阻和开关接地,做保护措施,接收到低电平清除寄存器内容。主电源断电后,侵入检测仍然有效。RTC校准时钟可以对RTC时钟进行校准。存储RTC时钟校准寄存器可以配合RTC校准时钟对RTC进行校准。

2、BKP的基本结构:

3、STM32的RTC外设

STM32的RTC类似DS1302外置实时时钟。RTC输入时钟具有20bit的分配器,即可分配1-的分频。
RTC框图:

灰色部分为VBT断电供电部分选择RTC时钟-RTCCLK提供时钟-RTC_DIV(余数寄存器,自减)计数溢出后产生TR_CLK,并且通过RTC_PRL(重装载寄存器)进行重装载(预分频器原理)-通过TR_CLK的RTC_CNT进行计数(为无符号32bit),
- RTC_CNT的计满溢出中断为RTC_Overflow。
- 其中RTC_ALR为闹钟,和RTC_CNT一样的uint32寄存器,当RTC_ALR和RTC_CNT计数相同,会产生RTC_Alarm信号,前往中断系统(或唤醒芯片,退出睡眠模式,WKUP-PA0引脚也可以唤醒设备)。
- RTC_Sencond中断来自TR_CLK的秒计数。
- 中断选项中,IE结尾的是中断使能,F结尾的是中断标志位。
晶振选择:
一般可以选择三个时钟源。根据STM32RTC时钟树可以看到,包括2高速、2低俗、2内部、2外部共4个晶振作为晶振源,详细可见定时器文章。高速时钟一般为内部运行和主要外设使用,低速时钟一般供RTC、看门狗等使用。可以看到LSE OSC指向RTCCLK。且RTC有三个来源时钟。


32.768=可直接经过分频1Hz。硬件电路计数器也方便进行计数溢出得到频率信号。一般使用LSE。
4、RTC基本结构

5、电路



CR2032纽扣电池,印制面为正极。
6、操作注意事项

- PWR是电源管理
- 第二点寄存器同步操作的原因:因为PCLK1(APB1总线时钟,36MHz)在主电源掉电时会停止。为了保证RTC掉电不丢失,RTC都是在RTCCLK(32.768Hz)同步下变更的。所以用APB1总线读取RTC寄存器内容,存在时钟不同步问题。时钟不同步会导致读取到错误数据。所以在APB总线刚开启时要进行时钟同步。
- RTC_CRL为时钟配置使能标志位,使用时需要先配置。库函数自动进行了配置。
- RTC的RTOFF为等待结束标志位。等待即可,当RTOFF=1才可写入。主要还是因为时钟频率不一样,不能立即更新。
三、程序实例
问题1:VBT供电导致STM32系统供电指示灯和OLED下电后还会有一些微弱显示。
问题2:有些芯片RTC晶振不起振。会导致程序卡死在晶振等待起振的地方。
1、写入BKP备份寄存器和从备份寄存器读出,显示到OLED。
将STM32断电、VBT不断电,STM32上电查看BKP数据是否掉电保存。(保存数据)
将VBT断电、STM32断电,然后STM32在上电查看BKP数据是否掉电保存。(不保存数据)


main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"uint16_t Data[4]={0x01,0x02,0x03,0x04};//写入的数据
uint16_t GetData[4];//BKP读出的数据
int main(void){OLED_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//开启BKP时钟PWR_BackupAccessCmd(ENABLE);//开启RTC和BKP的访问使能BKP_WriteBackupRegister(BKP_DR1,Data[0]);//数据写入,在做STM32下电测试时,写入代码注释BKP_WriteBackupRegister(BKP_DR2,Data[1]);BKP_WriteBackupRegister(BKP_DR3,Data[2]);BKP_WriteBackupRegister(BKP_DR4,Data[3]);OLED_ShowString(1,1,"BKP:");GetData[0] = BKP_ReadBackupRegister(BKP_DR1);//数据读出GetData[1] = BKP_ReadBackupRegister(BKP_DR2);GetData[2] = BKP_ReadBackupRegister(BKP_DR3);GetData[3] = BKP_ReadBackupRegister(BKP_DR4);OLED_ShowHexNum(2,1,GetData[0],2);OLED_ShowHexNum(2,4,GetData[1],2);OLED_ShowHexNum(2,7,GetData[2],2);OLED_ShowHexNum(2,10,GetData[3],2);while(1){Delay_ms(200);}return 0;
}
2、RTC时钟

时间显示,如果VBT供电,那么STM32复位或下电RTC时钟不会丢失(RTC和BKP都可通过VBT供电)。
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"
#include "time.h"
Unixdate GetTime;
time_t CNT;
time_t DIVData;int main(void){OLED_Init();MyRTC_Init();OLED_ShowString(1,1,"Date: - - ");OLED_ShowString(2,1,"Time: : : ");OLED_ShowString(3,1,"CNT :");OLED_ShowString(4,1,"DIV :");while(1){GetTime = GetNowTime();//获取RTC内的时间CNT = GetCounter();DIVData = GetDIV();OLED_ShowNum(1,6,GetTime.years,4);OLED_ShowNum(1,11,GetTime.months,2);OLED_ShowNum(1,14,GetTime.day,2);OLED_ShowNum(2,6,GetTime.hours,2);OLED_ShowNum(2,9,GetTime.minutes,2);OLED_ShowNum(2,12,GetTime.second,2);OLED_ShowNum(3,6,CNT,10);OLED_ShowNum(4,6,DIVData,10);}return 0;
}
MyRTC.c
#include "stm32f10x.h" // Device header
#include "time.h"
#include "MyRTC.h"
Unixdate SetTime;
void MyRTC_Init(void){//时钟配置RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//使能RTC和BKP访问PWR_BackupAccessCmd(ENABLE);//开启LSE/LSI,并等待启动完成RCC_LSEConfig(RCC_LSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET);
// RCC_LSICmd(ENABLE);//备用配置LSI为内部时钟,并启动
// while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)!=SET);//等待启动完成//使用BKP来判断是否断电,若断电则进行初始化,相当于用BKP做了一个标志位if(BKP_ReadBackupRegister(BKP_DR1)!=0xA5A5){//选择LSE为时钟源,并使能时钟RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//备用选择LSI作为时钟源RCC_RTCCLKCmd(ENABLE);//等待时钟同步,等待RTC上一次操作完成RTC_WaitForSynchro();RTC_WaitForLastTask();//配置预分频器,LSE=32768Hz,分频32768后为1Hz,LSI=40000HzRTC_SetPrescaler(32768-1);//函数内置写CNF=1/=0进入了配置模式/退出配置模式,只有配置模式可以写入寄存器// RTC_SetPrescaler(40000-1);//备用使用LSI作为时钟源 RTC_WaitForLastTask();Time_Init(&SetTime);SetNowTime(SetTime);BKP_WriteBackupRegister(BKP_DR1,0xA5A5);}else{//若BKP不断电则不初始化//等待时钟同步,等待RTC上一次操作完成RTC_WaitForSynchro();RTC_WaitForLastTask();}}/*** @brief 获取当前CNT* @param * @arg * @param * @arg * @retval None*/
uint32_t GetCounter(void){return RTC_GetCounter();
}/*** @brief 获取当前余数值计数值* @param * @arg * @param * @arg * @retval None*/
uint32_t GetDIV(void){return RTC_GetDivider();
}/*** @brief 设置当前时间* @param 输入为Unixdate自定义日期类型* @arg * @param * @arg * @retval None*/
void SetNowTime(Unixdate UnixdataStructure){struct tm NowTime;time_t count;NowTime.tm_min = UnixdataStructure.minutes;NowTime.tm_hour = UnixdataStructure.hours;NowTime.tm_mday = UnixdataStructure.day;NowTime.tm_mon = UnixdataStructure.months;NowTime.tm_year = UnixdataStructure.years;NowTime.tm_sec = UnixdataStructure.second;count = mktime(&NowTime)-8*60*60;//设置时间到RTC,输入东八区时间,偏移到0时区RTC_SetCounter(count);RTC_WaitForLastTask();//等待完成
}/*** @brief 获取RTC当前时间* @param * @arg * @param * @arg * @retval 返回当前RTC对应的日期时间*/
Unixdate GetNowTime(void){struct tm NowTime;Unixdate UnixdataStructure;time_t count;count = RTC_GetCounter()+8*60*60;//获取当前计数,偏移到东八区(STM32默认函数为0区时间)RTC_WaitForLastTask();//等待完成NowTime = *localtime(&count);//根据计数值换算成日期时间,将值传给NowTimeUnixdataStructure.years = NowTime.tm_year+1900;UnixdataStructure.months = NowTime.tm_mon+1;UnixdataStructure.day = NowTime.tm_mday;UnixdataStructure.hours = NowTime.tm_hour;UnixdataStructure.minutes = NowTime.tm_min;UnixdataStructure.second = NowTime.tm_sec;return UnixdataStructure;
}/*** @brief 日期变量初始化* @param 输入为日期变量结构体地址,直接对其进行改变* @arg * @param * @arg * @retval None*/
void Time_Init(Unixdate *UnixdataStructure){UnixdataStructure->years = 2025-1900;UnixdataStructure->months = 1-1;UnixdataStructure->day = 3;UnixdataStructure->hours = 23;UnixdataStructure->minutes = 59;UnixdataStructure->second = 56;
}
MyRTC.h
#ifndef __MYRTC_H
#define __MYRTC_H
#include "stm32f10x.h" // Device header//#pragma pack(n)可修改编译器字节对齐数
typedef struct{uint8_t second;//(0-60)suint8_t minutes;//(0-59)minuint8_t hours;//(0-23)huint8_t months;//月(1-12)uint8_t day;//月中第几天(1-31)uint16_t years;//年
}Unixdate;void MyRTC_Init(void);
uint32_t GetCounter(void);
uint32_t GetDIV(void);
Unixdate GetNowTime(void);
void Time_Init(Unixdate *UnixdataStructure);
void SetNowTime(Unixdate UnixdataStructure);
#endif
其他
数据范围原理:
int32范围为~
,数据在计算机中为补码存储,
即int32范围:
在最大值情况下,符号位为 0,其余 31 位均为 1
0111 1111 1111 1111 1111 1111 1111 1111
在最小值情况下,符号位为 1,其余 31 位全为 0
1000 0000 0000 0000 0000 0000 0000 0000
最高位表示符号位,1为负,第32bit为,如上,所以正数可以达到
,负数可以达到
。
- 最大值:(2^{31} - 1 = 2147483647)
- 最小值:(-2^{31} = -2147483648)
同理int16范围为2^15-1 ~ -2^15 (32767~-32768)
int8_t范围为2^7-1 ~ -2^7 (127~-128)
相关文章:
STM32-BKP备份寄存器RTC实时时钟
一、原理 Unix: 一些系统是使用32bit有符号数存储,实际范围为-2,147,483,648到2,147,483,647即~ 经过计算int32数据会在2038年1月19日溢出,可以看到转换的为北京时间。 STM32的时间戳为无符号时间戳。 我们需要把秒计数器的时间通过计算…...
HTML-文本标签
历史上,网页的主要功能是文本展示。所以,HTML 提供了大量的文本处理标签。 1.<div> <div>是一个通用标签,表示一个区块(division)。它没有语义,如果网页需要一个块级元素容器,又没…...
香橙派5plus单独编译并安装linux内核无法启动的原因分析与解决记录
1 说明 我依照官方手册编译单独编译linux内核,安装后重启出现内核启动失败的问题,编译和安装步骤如下:# 1. 克隆源码 git clone --depth1 -b orange-pi-6.1-rk35xx https://github.com/orangepi-xunlong/linux-orangepi# 2 配置源码 make rockchip_linu…...
嵌入式应用软件开发中C语言方向面试题
嵌入式应用软件开发中C语言方向面试题随笔 前言一、C语言基础二、嵌入式开发相关三、硬件相关知识五、实际编程问题前言 做嵌入式开发这么多年了,简单记录下C语言方向常见面试题,这里是应用软件方向的。 一、C语言基础 C语言的指针与数组的区别是什么?指针:指针是一个变量…...
linux 系统配置ip
最常见的配置方法是通过 DHCP 获取动态 IP 地址,或者手动配置一个静态 IP 地址。下面我将详细说明这两种常见的配置方法。 通过 DHCP 自动获取 IP 地址 如果你的开发板连接到网络(比如通过网线或者 Wi-Fi),并且网络环境支持 DHCP…...
低代码开发:开启企业数智化转型“快捷键”
一、低代码开发浪潮来袭,企业转型正当时 在当今数字化飞速发展的时代,低代码开发已如汹涌浪潮,席卷全球。从国际市场来看,诸多企业巨头纷纷布局低代码领域,像微软的 PowerApps、OutSystems 等平台,凭借强大…...
Tailwind CSS 实战:性能优化最佳实践
在现代网页开发中,性能优化就像是一场精心策划的马拉松。记得在一个电商项目中,我们通过一系列的性能优化措施,让页面加载时间减少了 60%,转化率提升了 25%。今天,我想和大家分享如何使用 Tailwind CSS 进行性能优化。 优化理念 性能优化就像是在打磨一块璞玉。我们需要通过各…...
[redux] useDispatch的两种用法
先重写2个方法先, 方便ts类型推导,如果你看不懂为什么这么写, 先看我这篇 [redux] ts声明useSelector和useDispatch-CSDN博客 export type RootState ReturnType<typeof store.getState>; export type AppDispatch typeof store.dispatch; export const useAppDispat…...
Postgresql 命令还原数据库
因为PgAdmin打不开,但是数据库已经安装成功了,这里借助Pg命令来还原数据库 C:\Program Files\PostgreSQL\15\bin\psql.exe #链接数据库 psql -U postgres -p 5432#创建数据库 CREATE DATABASE "数据库名称"WITHOWNER postgresENCODING UTF8…...
电脑找不到mfc110.dll文件要如何解决?Windows缺失mfc110.dll文件快速解决方法
一、mfc110.dll文件的重要性 mfc110.dll,全称Microsoft Foundation Class Library 110,是Microsoft Visual C Redistributable for Visual Studio 2012的一部分。这个动态链接库(DLL)文件对于支持基于MFC(Microsoft F…...
Elasticsearch与数据库数据一致性:最佳实践与解决方案
在现代应用程序中,Elasticsearch(ES)作为一个高效的分布式搜索引擎,常常与数据库一同使用,以提供强大的搜索、分析和数据可视化功能。然而,数据库和Elasticsearch之间的同步与一致性常常成为一个挑战。如何…...
vue导入导出excel、设置单元格文字颜色、背景色、合并单元格(使用xlsx-js-style库)
npm i xlsx-js-style <template><button click"download">下载 Excel 表格</button><el-table :data"tableData" style"width: 100%"><el-table-column prop"date" label"日期" width"180…...
电子电气架构 --- 中央处理器HPC及软件架构
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
代码实战:基于InvSR对视频进行超分辨率重建
Diffusion Models专栏文章汇总:入门与实战 前言:上一篇博客《使用Diffusion Models进行图像超分辩重建》中讲解了InvSR的原理,博主实测的效果是非常不错的,和PASD基本持平。这篇博客就讲解如何利用InvSR对视频进行超分辨率重建。 目录 环境准备 代码讲解 环境准备...
一文读懂主成分分析法(PCA)
主成分分析法(PCA) 主成分分析法(PCA)主成分分析的基本思想主成分的计算主成分分析的原理主成分分析的特点主成分分析的应用 主成分分析法(PCA) 主成分分析的基本思想 PCA是1901 年Pearson在研究回归分析…...
Redis(基础篇 + 实践篇 )
01 | 基本架构:一个键值数据库包含什么? Redis 作为一个内存数据存储系统,它的架构设计非常简洁,但功能非常强大。理解其核心架构对高效使用 Redis 至关重要。 客户端与服务器架构: 客户端通过 TCP 协议连接到 Redis …...
高质量C++小白教程:2.10-预处理器简介
当你在编译项目时,你可能希望编译器完全按照你编写的方式编译每一个代码文件,当事实并非如此。 相反,在编译之前,每一个.cpp文件都会经历一个预处理的阶段,在此阶段中,称为预处理器的程序对代码文件的文本进行各种更改. 预处理器实际上不会以任何方式修改原始代码文件,预处理…...
一、二极管(模电理论篇)
导论:PN结(结电容)是构成二极管,三极管,场效应管的原理基础 1.二极管特性(单向导电性) 1.1 P型半导体与N型半导体 在单晶体硅(原子核为正四价电子,可以形成四条共价键&…...
JAVA学习笔记_JVM
文章目录 初识jvm内存结构程序计数器(寄存器) 栈问题辨析内存溢出 线程诊断本地方法栈Heap堆内存溢出内存诊断 方法区内存溢出常量池 stringTable直接内存垃圾回收 初识jvm JRE JVM 基础类库 JDK JRE 编译工具 JavaSE JDK IDE工具 JavaEE JDK 应用服务器 IDE工具 jvm是…...
SQL 中复杂 CASE WHEN 嵌套逻辑优化
目标:优化复杂的 CASE WHEN 逻辑,提升 SQL 语句的可读性与执行效率,减少多层嵌套带来的复杂性。 1. CASE WHEN 的常见问题 嵌套过深:多个条件判断嵌套,难以阅读和维护。重复逻辑:相似逻辑在多个分支中重复…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

