STM32单片机-BKP和RTC

STM32单片机-BKP和RTC

  • 一、Unix时间戳
    • 1.1 时间戳转换
  • 二、BKP(备份寄存器)
  • 三、RTC(实时时钟)
    • 3.1 RTC工作原理
  • 四、代码部分
    • 4.1 BKP备份寄存器
    • 4.2 RTC实时时钟

一、Unix时间戳

  • Unix时间戳定义为从伦敦时间1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒
  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位整形变量
  • 世界上所有时区秒计数器相同,不同时区通过添加偏移来得到当地时间

在这里插入图片描述

1.1 时间戳转换

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

在这里插入图片描述
  下图为时间戳转换图
  time_t是int32或者int64数据类型,存储时间戳中自增的秒数
  struct tm是一个封装的结构体类型,结构体成员是秒,分,时等
  char*指向一个表示时间的字符串

在这里插入图片描述

二、BKP(备份寄存器)

  • BKP用于存储用户应用程序数据,当VDD主电源被切断,它们仍然由VBRT备用电源维持供电,当系统在待机模式下被唤醒,或系统复位或电源复位时,它们也不会被复位
  • TAMPER引脚产生的侵入事件将所有备份寄存器内容清除
  • RTC引脚输出RTC校准时钟RTC闹钟脉冲或者秒脉冲
  • 存储RTC时钟校准寄存器
  • 用户数据存储容量20字节/84字节

  下图为BKP基本结构
  BKP由数据寄存器-存储数据、控制寄存器、状态寄存器和RTC时钟校准寄存器组成,TAMPER有上升沿或者下降沿出现时,清除寄存器内容,保证安全

在这里插入图片描述

三、RTC(实时时钟)

  • RTC是一个独立的定时器,可以为系统提供时钟日历的功能
  • RTC时钟配置处于系统的后备区域系统复位时数据不清零,VDD断电后可以借助VBRT供电继续走时
  • 32位的可编程计数器,可对应Unix时间戳秒计数器
  • 20位的可编程预分频器,可适配不同频率的输入时钟
  • 可选择三种RTC时钟源:HSE时钟除以128(8MHz/128)、LSE振荡器时钟(VBRT)(32.768KHz)和LSI振荡器时钟(40KHz)

3.1 RTC工作原理

  下图为RTC框图
  灰色填充部分属于后备区域,在主电源掉电后,可以使用备用电源维持工作。RTCCLK是时钟源,一般选择LSE振荡器时钟,经过分频器分频,重装载的值加1就是分频系数。32位可编程计数器RTC_CNT存放时间数据,RTC_ALR是闹钟寄存器
  进入中断有3个中断源,RTC_Second秒中断,每秒进一次中断。RTC_Overflow溢出中断,当32位计数器溢出进入中断。RTC_Alarm闹钟中断

在这里插入图片描述

  下图为RTC基本结构
  选择时钟,RTCCKL先通过预分频器对时钟进行预分频,重装寄存器是计数目标,决定分频值余数寄存器是一个自减计数器,存储当前的计数值,最终得到1Hz的秒计数信号通向32位计数器,1秒自增一次,同时可以设定闹钟,最终也可以进入中断

在这里插入图片描述

四、代码部分

  注意事项

  • RTC的时钟开启没有单独选项,需要开启PWR和BKP时钟,设置PWR_CR的DBP,使能对BKP和RTC的访问
  • 若在读取RTC寄存器时,RTC的APB1接口曾经处在禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1
  • 必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL(重装值)、RTC_CNT(计数器)、RTC_ALR(闹钟值)寄存器
  • 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器

4.1 BKP备份寄存器

  STM32的VBRT引脚接在ST-Link的3.3V,PB1接一个按键
  步骤:开启RCC(PWR和BKP) — 使能BKP-PWR_BackupAccessCmd(ENABLE) — 写入和读取
  下面为main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Key.h"

uint8_t KeyNum;
uint16_t ArrayWrite[] = {0x1234,0x5678};
uint16_t ArrayRead[2];

int main(void)
{
	OLED_Init();
	Key_Init();
	//开启RCC-PWR和BKP
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
	//使能BKP
	
	OLED_ShowString(1,1,"W:");
	OLED_ShowString(2,1,"R:");
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			ArrayWrite[0] ++;
			ArrayWrite[1] ++;
			BKP_WriteBackupRegister(BKP_DR1,ArrayWrite[0]);
			BKP_WriteBackupRegister(BKP_DR2,ArrayWrite[1]);//写入
			
			OLED_ShowHexNum(1,3,ArrayWrite[0],4);
			OLED_ShowHexNum(1,8,ArrayWrite[1],4);
		}
		ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);
		ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2);//读取
		OLED_ShowHexNum(2,3,ArrayRead[0],4);
		OLED_ShowHexNum(2,8,ArrayRead[1],4);
	}
}

4.2 RTC实时时钟

  下面是RTC相关的库函数

void RCC_LSEConfig(uint8_t RCC_LSE);//启动LSE时钟
void RCC_LSICmd(FunctionalState NewState);//配置LSI时钟
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);//选择RTCCLK的时钟源
void RCC_RTCCLKCmd(FunctionalState NewState);//RTCCLK使能
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);//等待RCC标志位,时钟启动完成

void RTC_EnterConfigMode(void);//设置CNF位,使RTC进入配置模式
void RTC_ExitConfigMode(void);//退出配置模式
uint32_t  RTC_GetCounter(void);//获取CNT计数器的值
void RTC_SetCounter(uint32_t CounterValue);//写入计数器的值
void RTC_SetPrescaler(uint32_t PrescalerValue);//写入预分频器
void RTC_SetAlarm(uint32_t AlarmValue);//写入闹钟值
uint32_t  RTC_GetDivider(void);//读取余数寄存器值
void RTC_WaitForLastTask(void);//等待上一次操作完成
void RTC_WaitForSynchro(void);//等待同步
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);//等待标志位

  步骤:开启PWRBKP时钟,使能BKP和RTC的访问 — 开启LSE时钟并等待LSE时钟启动完成 — 选择RCCCLK时钟源-LSE — 等待同步和等待上一次写入操作完成 — 设置预分频器初始时间写入数据读取数据
  其中想要实现复位不重置时间数据和主电源断开时不切断时间,需要使用BKP判断
  利用c语言库time.h中的函数,实现写入和读取时间,即计数器值和时间数据的相互转换
  下面为MyRTC.c和MyRTC.h

#include "stm32f10x.h"                  // Device header
#include "MyRTC.h"                  // Device header
#include <time.h>

uint16_t MyRTC_Time[] = {2024,1,1,1,1,1};//时间数据

void MyRTC_Init()
{
	//开启RCC-BKP、PWR和使能访问
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	//第一次上电或者完全断电,BKPDR1默认为0时,才会初始化时间
	if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
	{
		//开启LSE时钟,等待LSE时钟启动完成(标志位)
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
		
		//选择RCCCLK时钟源-LSE
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		
		//等待同步和等待上一次写入操作完成
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		//配置预分频器 =  32768MHz /32768 = 1Hz
		RTC_SetPrescaler(32768-1);
		RTC_WaitForLastTask();//等待写入操作
		
		//设置初始时间
		MyRTC_SetTime();
		
		BKP_WriteBackupRegister(BKP_DR1,0xA5A5);//DR1写入A5A5
	}
	else
	{
		//等待同步和等待上一次写入操作完成
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}
}
/*
@brief:写入时间数据
*/
void MyRTC_SetTime()
{
	time_t time_cnt;//计数器值
	struct tm time_data;//时间数据
	
	time_data.tm_year = MyRTC_Time[0] - 1900;
	time_data.tm_mon = MyRTC_Time[1] - 1;
	time_data.tm_mday = MyRTC_Time[2];
	time_data.tm_hour = MyRTC_Time[3];
	time_data.tm_min = MyRTC_Time[4];
	time_data.tm_sec = MyRTC_Time[5];//写入数据
	
	time_cnt = mktime(&time_data)- 8*60*60;//时间数据--计数器(北京时间)
	RTC_SetCounter(time_cnt);
	RTC_WaitForLastTask();//等待写入操作
}
/*
@brief:读取时间数据
*/
void MyRTC_ReadTime()
{
	time_t time_cnt;//计数器值
	struct tm time_data;//时间数据
	
	time_cnt = RTC_GetCounter()+ 8*60*60;//读取时间存到计数器(北京时间)
	time_data = *localtime(&time_cnt);//将时间数据转到结构体
	
	MyRTC_Time[0] = time_data.tm_year + 1900;
	MyRTC_Time[1] = time_data.tm_mon + 1;
	MyRTC_Time[2] = time_data.tm_mday;
	MyRTC_Time[3] = time_data.tm_hour;
	MyRTC_Time[4] = time_data.tm_min;
	MyRTC_Time[5] = time_data.tm_sec;//读取数据
}
#ifndef __MYRTC_H
#define __MYRTC_H

extern uint16_t MyRTC_Time[];


void MyRTC_Init();
void MyRTC_SetTime();
void MyRTC_ReadTime();


#endif

  下面为main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	MyRTC_Init();
	OLED_Init();
	
	OLED_ShowString(1,1,"Data:XXXX-XX-XX");
	OLED_ShowString(2,1,"Time:XX:XX:XX");
	OLED_ShowString(3,1,"CNT:");
	
	while(1)
	{
		MyRTC_ReadTime();
		OLED_ShowNum(1,6,MyRTC_Time[0],4);
		OLED_ShowNum(1,11,MyRTC_Time[1],2);
		OLED_ShowNum(1,14,MyRTC_Time[2],2);
		OLED_ShowNum(2,6,MyRTC_Time[3],2);
		OLED_ShowNum(2,9,MyRTC_Time[4],2);
		OLED_ShowNum(2,12,MyRTC_Time[5],2);
		
		OLED_ShowNum(3,6,RTC_GetCounter(),10);
	}
}


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Django集成OpenAI

Django集成OpenAI 通过前面 django 框架的基本开发知识&#xff0c;我们现在可以开始在 django 上做稍微深一点当然应用开发了。 这一章开始编写怎么集成调用 openai &#xff0c;设置环境以及 openai 的基础知识。 大家都知道 ai 的多模态逐渐扩大&#xff0c;各种应用层出…

【LeetCode:2663. 字典序最小的美丽字符串 + 贪心】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

性能工具之 JMeter 常用组件介绍(五)

文章目录 一、Jmeter中参数取值1、Test Plan中添加变量2、User Defined Variables 二、Jmeter中CSV Data Set Config三、Timer:定时器4、Gaussian Random Timer 高斯随机定时器5、JSR223 Timer JSR223定时器6、Poisson Random Timer 泊松随机定时器7、Synchronizing Timer 同步…

复分析——第4章——Fourier变换(E.M. Stein R. Shakarchi)

第4章 Fouier变换 Raymond Edward Alan Christopher Paley, Fellow of Trinity College, Cambridge, and International Research Fellow at the Massachusetts Institute of Technology and at Harvard University, was killed by an avalanche on April 7, 1933, whi…

记某模版菠菜管理后台登录思路

1.前言 由于小程序的便捷性&#xff0c;越来越多的应用迁移到了了小程序上&#xff0c;由此伴随着小程序上线前的日常渗透测试工作也开始增加。但小程序的测试中经常会遇到数据包被加密了&#xff0c;导致无法进行改包测试。和测试网页数据包加密一样&#xff0c;就需要找到小…

Stable Diffusion 3 文本生成图像 在线体验 原理分析

前言 本文分享使用Stable Diffusion 3实现文本生成图像&#xff0c;可以通过在线网页中免费使用的&#xff0c;也有API等方式访问。 同时结合论文和开源代码进行分析&#xff0c;理解其原理。 Stable Diffusion 3是Stability AI开发的最新、最先进的文本生成图像模型&#x…

Linux中部署MySQL环境方法(仓库安装)

1.进入MySQL官网 2.进入MySQL社区版下载 3.使用yum方式下载MySQL 4.使找到对应系统的对应包的链接 复制 5.linux命令行中使用命令通过对应链接下载该软件包 rpm -i https://repo.mysql.com//mysql80-community-release-el9-1.noarch.rpm 警告&#xff1a;/var/tmp/rpm-tmp.so…

45、基于深度学习的螃蟹性别分类(matlab)

1、基于深度学习的螃蟹性别分类原理及流程 基于深度学习的螃蟹性别分类原理是利用深度学习模型对螃蟹的图像进行训练和识别&#xff0c;从而实现对螃蟹性别的自动分类。整个流程可以分为数据准备、模型构建、模型训练和性别分类四个步骤。 数据准备&#xff1a; 首先需要收集包…

分享一个 Fail2ban 过滤规则

今天明月给大家分享个 Fail2ban 的过滤&#xff08;Filter&#xff09;规则&#xff0c;有关 Fail2ban 的文章大家可以参考【服务器全面使用 Fail2Ban 初见成效】和【使用 Fail2ban 禁止垃圾采集爬虫&#xff0c;保护 Nginx 服务器】等文了解&#xff0c;总之 Fail2ban 是 Linu…

如何跳出认知偏差,个人认知能力升级

一、教程描述 什么是认知力&#xff1f;认知力&#xff08;cognitive ability&#xff09;&#xff0c;实际上就是指一个人的认知能力&#xff0c;是指人的大脑加工、储存和提取信息的能力&#xff0c;或者主观对非主观的事物的反映能力&#xff0c;如果变成大白话&#xff0c…

力扣SQL 即时食物配送 II min函数 嵌套查询

Problem: 1174. 即时食物配送 II &#x1f468;‍&#x1f3eb; 参考题解 Code -- 计算立即配送的订单百分比 select round (-- 计算订单日期与客户偏好配送日期相同的订单数量sum(case when order_date customer_pref_delivery_date then 1 else 0 end) * 100 /-- 计算总订…

媒体邀约中媒体采访应该如何做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 在媒体邀约中&#xff0c;媒体采访应该遵循以下几个步骤和…

[C#]使用深度学习算法opencvsharp部署RecRecNet广角图像畸变矫正校正摄像广角镜头畸变图像

【论文地址】 https://arxiv.org/abs/2301.01661 【训练源码】 https://github.com/KangLiao929/RecRecNet 【参考源码】 https://github.com/hpc203/recrecnet-opencv-dnn 【算法介绍】 广角镜头在VR技术中显示出诱人的应用&#xff0c;但它会在捕获的图像中引入严重的径…

如何下载和安装SQLynx数据库管理工具? (MySQL作为测试数据库)

目录 1. 官网下载 2. 安装软件 3. 启动SQLynx软件 4. 开始使用 5. 执行第一条SQL语句 6. 总结 SQLynx是一款先进的Web SQL集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为数据库管理、查询和数据分析设计。作为一个基于浏览器的工具&#xff08;同时也支持桌面…

《计算机英语》Unit2 Operating System and Computer Architecture 操作系统和计算机构造

SectionA Operating System操作系统 不同操作系统 批处理操作系统(Batch Processing Operating System) 分时操作系统(Time Sharing Operating System) 实时操作系统(Real Time Operating System) 个人操作系统(Personal Operating System) 网络操作系统(NOS, Network Operati…

Android设计模式系列--模板方法模式

认识到模板方法的这种思想&#xff0c;父类可以让未知的子类去做它本身可能完成的不好或者根本完成不了的事情&#xff0c;对框架学习大有帮助。 本文以View中的draw方法为例&#xff0c;展开分析。 模板方法&#xff0c;TemplateMethod&#xff0c;光是学习这个模式&#xf…

SwiftUI 6.0(iOS 18)ScrollView 全新的滚动位置(ScrollPosition)揭秘

概览 在只有方寸之间大小的手持设备上要想体面的向用户展示海量信息&#xff0c;滚动视图&#xff08;ScrollView&#xff09;无疑是绝佳的“东牀之选”。 在 SwiftUI 历史的长河中&#xff0c;总觉得苹果对于 ScrollView 视图功能的升级是在“挤牙膏”。这不&#xff0c;在本…

“一站式企业服务平台”的功能架构

为提升区域营商环境&#xff0c;为促进区域经济发展&#xff0c;实现资源高效配置&#xff0c;全国各区域政府及产业园区都越来越重视如何创新企业服务机制、提升企业服务水平&#xff0c;来保障区域内的企业稳定及帮扶企业高质量的发展。随着近年来大数据、人工智能等新一代信…

多线程环境下 System.out.println 导致死锁问题分析

背景 一个文件采集系统&#xff0c;使用了多线程递归采集指定目录下的文件&#xff0c;并为每个目录创建一个线程去采集。 这个应用每隔几天就出现罢工情况&#xff0c;查看进程还在&#xff0c;堆内存空间还很充足&#xff0c;就是导出堆栈时&#xff0c;发现几乎所有的采集…

Docker:安装RediSearch全文搜索

1、简述 在本文中&#xff0c;我们将介绍如何使用Docker快速、简便地安装RediSearch&#xff0c;Redis的全文搜索模块。RediSearch提供了高效的全文搜索功能&#xff0c;通过Docker安装&#xff0c;可以轻松地在任何环境中部署和管理RediSearch。 官网地址&#xff1a;https:/…