00. 目录
文章目录
-
- [00. 目录](#00. 目录)
- [01. BKP简介](#01. BKP简介)
- [02. RTC简介](#02. RTC简介)
- [03. BKP相关API](#03. BKP相关API)
-
- [3.1 BKP_ReadBackupRegister](#3.1 BKP_ReadBackupRegister)
- [3.2 BKP_WriteBackupRegister](#3.2 BKP_WriteBackupRegister)
- [3.3 PWR_BackupAccessCmd](#3.3 PWR_BackupAccessCmd)
- [04. RTC相关API](#04. RTC相关API)
-
- [4.1 RCC_LSEConfig](#4.1 RCC_LSEConfig)
- [4.2 RCC_GetFlagStatus](#4.2 RCC_GetFlagStatus)
- [4.3 RCC_RTCCLKConfig](#4.3 RCC_RTCCLKConfig)
- [4.4 RCC_RTCCLKCmd](#4.4 RCC_RTCCLKCmd)
- [4.5 RTC_WaitForSynchro](#4.5 RTC_WaitForSynchro)
- [4.6 RTC_WaitForLastTask](#4.6 RTC_WaitForLastTask)
- [4.7 RTC_SetPrescaler](#4.7 RTC_SetPrescaler)
- [4.8 RTC_SetCounter](#4.8 RTC_SetCounter)
- [4.9 RTC_GetCounter](#4.9 RTC_GetCounter)
- [05. 读写备份寄存器和实时时钟接线图](#05. 读写备份寄存器和实时时钟接线图)
- [06. 读写备份寄存器示例](#06. 读写备份寄存器示例)
- [07. 实时时钟程序示例](#07. 实时时钟程序示例)
- [08. 示例程序下载](#08. 示例程序下载)
- [09. 附录](#09. 附录)
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.0~3.6V)断电后可借助VBAT(1.8~3.6V)供电继续走时
•32位的可编程计数器,可对应Unix时间戳的秒计数器
•20位的可编程预分频器,可适配不同频率的输入时钟
•可选择三种RTC时钟源:
HSE时钟除以128(通常为8MHz/128)
LSE振荡器时钟(通常为32.768KHz)
LSI振荡器时钟(40KHz)
03. BKP相关API
3.1 BKP_ReadBackupRegister
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @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
c
/**
* @brief Gets the RTC counter value.
* @param None
* @retval RTC counter value.
*/
uint32_t RTC_GetCounter(void)
功能:
获取 RTC 计数器的值
参数:
无
返回值:
RTC 计数器的值
05. 读写备份寄存器和实时时钟接线图
06. 读写备份寄存器示例
main.c
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
c
#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
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
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;
}