【STM32】STM32学习笔记-读写备份寄存器和实时时钟(43)

00. 目录

01. BKP简介

备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当V DD 电源被切断,他们仍然由V

BAT 维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。

此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。

复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。

● 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟

● 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

02. RTC简介

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。

系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问:

● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和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)

03. BKP相关API

3.1 BKP_ReadBackupRegister

/**
  * @brief  Reads data from the specified Data Backup Register.
  * @param  BKP_DR: specifies the Data Backup Register.
  *   This parameter can be BKP_DRx where x:[1, 42]
  * @retval The content of the specified Data Backup Register
  */
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR)
功能:
	从指定的后备寄存器中读出数据
参数:
	BKP_DR:数据后备寄存器
返回值:
	指定的后备寄存器中的数据

3.2 BKP_WriteBackupRegister

/**
  * @brief  Writes user data to the specified Data Backup Register.
  * @param  BKP_DR: specifies the Data Backup Register.
  *   This parameter can be BKP_DRx where x:[1, 42]
  * @param  Data: data to write
  * @retval None
  */
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data)
功能:
	向指定的后备寄存器中写入用户程序数据
参数:
	BKP_DR:数据后备寄存器
    Data:待写入的数据
返回值:

3.3 PWR_BackupAccessCmd


/**
  * @brief  Enables or disables access to the RTC and backup registers.
  * @param  NewState: new state of the access to the RTC and backup registers.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void PWR_BackupAccessCmd(FunctionalState NewState)
功能:
	使能或者失能 RTC 和后备寄存器访问
参数:
	NewState: RTC 和后备寄存器访问的新状态
返回值:

04. RTC相关API

4.1 RCC_LSEConfig

/**
  * @brief  Configures the External Low Speed oscillator (LSE).
  * @param  RCC_LSE: specifies the new state of the LSE.
  *   This parameter can be one of the following values:
  *     @arg RCC_LSE_OFF: LSE oscillator OFF
  *     @arg RCC_LSE_ON: LSE oscillator ON
  *     @arg RCC_LSE_Bypass: LSE oscillator bypassed with external clock
  * @retval None
  */
void RCC_LSEConfig(uint8_t RCC_LSE)
功能:
	设置外部低速晶振(LSE)

参数:
	RCC_LSE: LSE 的新状态

返回值:

4.2 RCC_GetFlagStatus

/**
  * @brief  Checks whether the specified RCC flag is set or not.
  * @param  RCC_FLAG: specifies the flag to check.
  *   
  *   For @b STM32_Connectivity_line_devices, this parameter can be one of the
  *   following values:
  *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
  *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
  *     @arg RCC_FLAG_PLLRDY: PLL clock ready
  *     @arg RCC_FLAG_PLL2RDY: PLL2 clock ready      
  *     @arg RCC_FLAG_PLL3RDY: PLL3 clock ready                           
  *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
  *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
  *     @arg RCC_FLAG_PINRST: Pin reset
  *     @arg RCC_FLAG_PORRST: POR/PDR reset
  *     @arg RCC_FLAG_SFTRST: Software reset
  *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
  *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset
  *     @arg RCC_FLAG_LPWRRST: Low Power reset
  * 
  *   For @b other_STM32_devices, this parameter can be one of the following values:        
  *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
  *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
  *     @arg RCC_FLAG_PLLRDY: PLL clock ready
  *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
  *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
  *     @arg RCC_FLAG_PINRST: Pin reset
  *     @arg RCC_FLAG_PORRST: POR/PDR reset
  *     @arg RCC_FLAG_SFTRST: Software reset
  *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
  *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset
  *     @arg RCC_FLAG_LPWRRST: Low Power reset
  *   
  * @retval The new state of RCC_FLAG (SET or RESET).
  */
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
功能:
	检查指定的 RCC 标志位设置与否

参数:
	RCC_FLAG:待检查的 RCC 标志位

返回值:
	RCC_FLAG 的新状态(SET 或者 RESET)
    

4.3 RCC_RTCCLKConfig

/**
  * @brief  Configures the RTC clock (RTCCLK).
  * @note   Once the RTC clock is selected it can't be changed unless the Backup domain is reset.
  * @param  RCC_RTCCLKSource: specifies the RTC clock source.
  *   This parameter can be one of the following values:
  *     @arg RCC_RTCCLKSource_LSE: LSE selected as RTC clock
  *     @arg RCC_RTCCLKSource_LSI: LSI selected as RTC clock
  *     @arg RCC_RTCCLKSource_HSE_Div128: HSE clock divided by 128 selected as RTC clock
  * @retval None
  */
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)
功能:
	设置 RTC 时钟(RTCCLK)

参数:
	RCC_RTCCLKSource: 定义 RTCCLK

返回值:

4.4 RCC_RTCCLKCmd

/**
  * @brief  Enables or disables the RTC clock.
  * @note   This function must be used only after the RTC clock was selected using the RCC_RTCCLKConfig function.
  * @param  NewState: new state of the RTC clock. This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_RTCCLKCmd(FunctionalState NewState)
功能:
	使能或者失能 RTC 时钟

参数:
	NewState:RTC 时钟的新状态, 这个参数可以取:ENABLE 或者 DISABLE

返回值:

4.5 RTC_WaitForSynchro

/**
  * @brief  Waits until the RTC registers (RTC_CNT, RTC_ALR and RTC_PRL)
  *   are synchronized with RTC APB clock.
  * @note   This function must be called before any read operation after an APB reset
  *   or an APB clock stop.
  * @param  None
  * @retval None
  */
void RTC_WaitForSynchro(void)
功能:
	等待最近一次对 RTC 寄存器的写操作完成

参数:
	无

返回值:

4.6 RTC_WaitForLastTask

/**
  * @brief  Waits until last write operation on RTC registers has finished.
  * @note   This function must be called before any write to RTC registers.
  * @param  None
  * @retval None
  */
void RTC_WaitForLastTask(void)
功能:
	等待最近一次对 RTC 寄存器的写操作完成

参数:
	无

返回值:

4.7 RTC_SetPrescaler

/**
  * @brief  Sets the RTC prescaler value.
  * @param  PrescalerValue: RTC prescaler new value.
  * @retval None
  */
void RTC_SetPrescaler(uint32_t PrescalerValue)
功能:
	设置 RTC 预分频的值

参数:
	PrescalerValue:新的 RTC 预分频值

返回值:

4.8 RTC_SetCounter

/**
  * @brief  Sets the RTC counter value.
  * @param  CounterValue: RTC counter new value.
  * @retval None
  */
void RTC_SetCounter(uint32_t CounterValue)
功能:
	设置 RTC 计数器的值

参数:
	CounterValue:新的 RTC 计数器值

返回值:

4.9 RTC_GetCounter

/**
  * @brief  Gets the RTC counter value.
  * @param  None
  * @retval RTC counter value.
  */
uint32_t RTC_GetCounter(void)
功能:
	获取 RTC 计数器的值

参数:
	无

返回值:
	RTC 计数器的值    
    

05. 读写备份寄存器和实时时钟接线图

在这里插入图片描述

06. 读写备份寄存器示例

main.c

#include "stm32f10x.h"

#include "delay.h"
#include "oled.h"
#include "key.h"


uint8_t key = 0;

uint16_t array_w[] = {0x1234, 0x5678};
uint16_t array_r[2];


 int main(void)
 {	
	//使能时钟
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	 
	 //使能访问
	 PWR_BackupAccessCmd(ENABLE);
	 
	 
	 //初始化
	 OLED_Init();
	 
	 key_init();

	 //显示字符串
	 //OLED_ShowString(1, 3, "HelloWorld!");

	 //显示十六进制
	 //OLED_ShowHexNum(3, 1, 0xAA55, 4);
	 
	 
	 OLED_ShowString(1, 1, "W:");
	 OLED_ShowString(2, 1, "R:");
	 
	 //BKP_WriteBackupRegister(BKP_DR1, 0x1234);
	 //OLED_ShowHexNum(1, 1, BKP_ReadBackupRegister(BKP_DR1), 4);
	 
	 

	 while(1)
	 {
		 key = key_scan();
		 
		 if (1 == key)
		 {
			array_w[0]++;
			array_w[1]++;
			BKP_WriteBackupRegister(BKP_DR1, array_w[0]); 
			BKP_WriteBackupRegister(BKP_DR2, array_w[1]); 
			 
			OLED_ShowHexNum(1, 3, array_w[0], 4);
			OLED_ShowHexNum(1, 8, array_w[1], 4); 			 
		 }
		 
		 array_r[0] = BKP_ReadBackupRegister(BKP_DR1);
		 array_r[1] = BKP_ReadBackupRegister(BKP_DR2);

		 OLED_ShowHexNum(2, 3, array_r[0], 4);
		 OLED_ShowHexNum(2, 8, array_r[1], 4); 	
	 }
	 
	 return 0;
 }

07. 实时时钟程序示例

rtc.h

#ifndef __RTC_H__
#define __RTC_H__

#include "stm32f10x.h" 

extern uint16_t rtc_time[];

void rtc_init(void);

void rtc_set_time(void);

void rtc_get_time(void);

#endif 


rtc.c

#include "rtc.h"

#include "stm32f10x.h"      
#include <time.h>

uint16_t rtc_time[] = {2024, 1, 1, 23, 59, 55};

//实时始终初始化
void rtc_init(void)
{
	//使能时钟
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	 
	 //使能访问
	 PWR_BackupAccessCmd(ENABLE);


	
	if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
	{
		//开启外部低速晶振
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
		
		RTC_SetPrescaler(32768 - 1);
		RTC_WaitForLastTask();
		
		
		//设置RTC
		rtc_set_time();
		
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
	}
	else
	{
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}
}


//设置实时时钟
void rtc_set_time(void)
{

	time_t cnt;
	
	struct tm t;
	
	
	t.tm_year = rtc_time[0] - 1900;
	t.tm_mon = rtc_time[1] - 1;
	t.tm_mday = rtc_time[2];
	t.tm_hour = rtc_time[3];
	t.tm_min = rtc_time[4];
	t.tm_sec = rtc_time[5];
	
	cnt = mktime(&t) - 8 * 60 * 60;

	RTC_SetCounter(cnt);
	RTC_WaitForLastTask();
}


void rtc_get_time(void)
{
	time_t cnt;
	
	struct tm t;
	
	cnt = RTC_GetCounter() + 8 * 60 * 60;
	
	t = *localtime(&cnt);
	
	rtc_time[0] = t.tm_year + 1900;
	rtc_time[1] = t.tm_mon + 1;
	rtc_time[2] = t.tm_mday;
	rtc_time[3] = t.tm_hour;
	
	rtc_time[4] = t.tm_min;
	rtc_time[5] = t.tm_sec;
		
}

main.c

#include "stm32f10x.h"

#include "delay.h"
#include "oled.h"
#include "key.h"
#include "rtc.h"


 int main(void)
 {	

	 
	 //初始化
	 OLED_Init();
	 
	 key_init();
	 
	 rtc_init();

	 //显示十六进制
	//OLED_ShowHexNum(3, 1, 0xAA55, 4);
	OLED_ShowString(1, 1, "Date:XXXX-XX-XX");
	OLED_ShowString(2, 1, "Time:XX:XX:XX");
	OLED_ShowString(3, 1, "CNT :");
	OLED_ShowString(4, 1, "DIV :");
		 


	 while(1)
	 {
		rtc_get_time();
		 			
		OLED_ShowNum(1, 6, rtc_time[0], 4);		//显示MyRTC_Time数组中的时间值,年
		OLED_ShowNum(1, 11, rtc_time[1], 2);		//月
		OLED_ShowNum(1, 14, rtc_time[2], 2);		//日
		OLED_ShowNum(2, 6, rtc_time[3], 2);		//时
		OLED_ShowNum(2, 9, rtc_time[4], 2);		//分
		OLED_ShowNum(2, 12, rtc_time[5], 2);		//秒
		
		OLED_ShowNum(3, 6, RTC_GetCounter(), 10);	//显示32位的秒计数器
		OLED_ShowNum(4, 6, RTC_GetDivider(), 10);	//显示余数寄存器
		 
	 }
	 
	 return 0;
 }

08. 示例程序下载

32-读写备份寄存器.rar

33-实时时钟.rar

09. 附录

参考: 【STM32】江科大STM32学习笔记汇总

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Print World

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值