0x0D RTC&BKP

本文的大部分内容来自B站up主 江协科技, 此文只供本人学习记录用途, 侵删

一、BKP

  • BKP(Backup Registers)备份寄存器
  • BKP可用于存储用户应用程序数据。当VDD(2.03.6V)电源被切断,他们仍然由VBAT(1.83.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位
  • TAMPER引脚产生的侵入事件将所有备份寄存器内容清除(防抄板的)
  • RTC引脚输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲
  • 存储RTC时钟校准寄存器
  • 用户数据存储容量: 20字节(中容量和小容量)/ 84字节(大容量和互联型)

直接看到BKP代码的使用

注意这里BKP里的数据需要给VBAT供电, 当电源断电时, VBAT给BKP供电, 保存数据

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //开启PWR时钟(必备流程),知道原因回来补
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE); //开启BKP时钟 
PWR_BackupAccessCmd(ENABLE); //使能后备区域的访问

BKP_WriteBackupRegister(BKP_DR1, 0xa9); //向DR1写入0xa9
uint8_t data = BKP_ReadBackupRegister(BKP_DR1); //读出DR1的数据

二、Unix时间戳

  • Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒
  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量世界上
  • 所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间
  • 本质上就是一个32位的数, 存放的值直接就能转化成年月日时分秒

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

这是转化的框图, 一目了然

image-20231104183747275

三、RTC

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

stm32的四个晶振 :

  • H代表高速, L代表低速, E代表外部. I代表内部 于是有四种组合:
  • HSI 高速内部时钟信号
  • HSE 高速外部时钟信号
  • LSI 低速内部时钟信号
  • LSE 低速外部时钟信号

VBAT的电路和LSE的晶振 硬件接法 :

image-20231104185920357

这个金属色的晶振(12mHz)是HSE的时钟源 , 这个尼龙色的晶振(32.768kHz)是LSE的时钟源 :

image-20231104190120917

  • 执行以下操作将使能对BKP和RTC的访问:
  • 设置RCC_APB1ENR的PWREN和BKPEN,使能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寄存器

四、常用配置代码

这里使用LSI作为RTCCLK的时钟来源

RTC的基本结构

image-20231104185904437

代码(记得勾选Use MisroLIB):

#include "stm32f10x.h"                  // Device header
#include "time.h"

uint16_t MYRTC_Time[6];//extern出去的时钟数组Time[0]-Time[5]对应 年 月 日 时 分 秒
//初始化
void MYRTC_Init(void){
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //开启PWR时钟(必备流程),知道原因回来补
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE); //开启BKP时钟 
    PWR_BackupAccessCmd(ENABLE); //使能后备区域的访问
    
	RCC_LSICmd(ENABLE); //开启LSI
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)!=SET);//等待LSI就绪
    
    //这里向BKP_DR1写入0x1234标志位 防止每次复位都重新给给RTC的CNT写值, 才能实现掉电不丢失时间
    if(BKP_ReadBackupRegister(BKP_DR1)!=0x1234) {
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //配置RTCCLK的时钟源
    	RCC_RTCCLKCmd(ENABLE); //使能RTCCLK    
        //这两行写不写都行, 写上上个保险
        RTC_WaitForSynchro(); //等待同步
        RTC_WaitForLastTask(); //等待上次写入完成(每次写RTC都调用一下)
        //想给RTCCLK 1Hz 这里把4kHz的LSI分频40000次
        RTC_SetPrescaler(40000-1);
        RTC_WaitForLastTask(); //等待上次写入完成(每次写RTC都调用一下)
        RTC_SetCounter(1695133871); //设置初始时间(RTC中的CNT, 这里写入的是一个时间戳)
        RTC_WaitForLastTask();//等待上次写入完成(每次写RTC都调用一下)
        BKP_WriteBackupRegister(BKP_DR1, 0x1234); //向DR1写入0x1234
    }
	else{
        //上保险
        RTC_WaitForSynchro(); //等待同步
        RTC_WaitForLastTask(); //等待上次写入完成(每次写RTC都调用一下)
    }
}
//更新时间数组
void  MYRTC_UpdateTime(){
	time_t timestamp=RTC_GetCounter();//拿到RTC中CNT的值
	RTC_WaitForLastTask(); //等待上次写入完成(每次写RTC都调用一下)
	struct tm * time; //时间结构体指针 (time.h中的struct tm)
	time=localtime(&timestamp); //将时间戳转化为 struct tm *
	MYRTC_Time[0] = time->tm_year + 1900; //年(从1900开始算)
	MYRTC_Time[1] = time->tm_mon + 1;     //月(从0开始算)
	MYRTC_Time[2] = time->tm_mday;        //日
	MYRTC_Time[3] = time->tm_hour + 8;    //时(+8倒时差)
	MYRTC_Time[4] = time->tm_min;         //分
	MYRTC_Time[5] = time->tm_sec;         //秒
}
//设置时间戳
void  MYRTC_SetTime(uint32_t Time){
	RTC_SetCounter(Time);  //设置时间(RTC中的CNT, 这里写入的是一个时间戳)
	RTC_WaitForLastTask(); //等待上次写入完成(每次写RTC都调用一下)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值