Table of contents
A: Read and write backup register
1: Time related
1:Unix timestamp
Unix Timestamp is defined as the number of seconds that have elapsed since 0:00:00 on January 1, 1970 UTC/GMT, regardless of leap seconds.
The timestamp is stored in a seconds counter, which is a 32-bit/64-bit integer variable.
The seconds counter is the same for all time zones in the world. Different time zones add offsets to get the local time.
2: UTC/GMT
GMT (Greenwich Mean Time) Greenwich Mean Time is a time measurement system based on the rotation of the earth. It divides the time interval of one rotation of the earth into 24 hours to determine the timing standard.
UTC (Universal Time Coordinated) is a time measurement system based on atomic clocks. It stipulates that the duration of 9,192,631,770 cycles of transition radiation between the two hyperfine energy levels of the ground state of a cesium 133 atom in a zero magnetic field is 1 second. When the difference between the atomic clock's day time and the Earth's rotation time exceeds 0.9 seconds, UTC will perform a leap second to ensure that its timing is consistent with the Earth's rotation.
3: Timestamp conversion
The time.h module of C language provides related functions for time acquisition and timestamp conversion, which can easily convert between seconds counter, date and time and string.
2:BKP
1: Resume
BKP (Backup Registers) backup registers
BKP can be used to store user application data. When the VDD (2.0~3.6V) power supply is cut off, they are still powered by VBAT (1.8~3.6V). They are also not reset when the system wakes up from standby mode, or when a system reset or power reset occurs
A trespass event generated by the TAMPER pin clears all backup register contents.
The RTC pin outputs RTC calibration clock, RTC alarm pulse or second pulse
Store RTC clock calibration register user data storage capacity:
20 bytes (medium capacity and small capacity) / 84 bytes (large capacity and interconnection type)
2:Basic structure
BKP is in the backup area, and the role of the backup area: when the VDD main power supply is powered off, the backup area can still be powered by the VBAT backup battery; when the VDD main power supply is powered on, the backup area power supply will be switched from VBAT to VDD, that is, the main When the power supply is powered on, VBAT will not be used, thus saving battery power.
The BKP mainly includes: data register, control register, status register and RTC clock calibration register. The data register is the main part and is used to store data. Each data odd register is 16 bits. One data odd register can Store 2 bytes. For the small ones, there are DR1, DR2, up to, and DR10, a total of 10 data registers; for the large-capacity and interconnected types, there are DR11~DR42 data registers.
A detection annunciator can be introduced from the TAMPERS pin at PC13. When TAMPER generates a rising edge or a falling edge, all contents of the BKP will be cleared to ensure safety -----corresponding to the third item in the resume
Clock output, the RTC related clock can be output from the RTC pin at PC13 for external use. When the calibration clock is output, the error of the RTC can be calibrated with this calibration register.
Three: RTC
1: Resume
RTC (Real Time Clock) real-time clock
RTC is an independent timer that can provide clock and calendar functions for the system. The RTC and clock configuration system are in the backup area. The data is not cleared when the system is reset. After VDD (2.0~3.6V) is powered off, VBAT (1.8~ 3.6V) power supply continues to run
32-bit programmable counter, second counter that can correspond to Unix timestamp
20-bit programmable prescaler can adapt to input clocks of different frequencies
Three RTC clock sources can be selected:
HSE clock divided by 128 (usually 8MHz/128)
LSE oscillator clock (typically 32.768KHz)
LSI oscillator clock (40KHz)
2: Block diagram
3:RTC basic structure
There are 3 clocks, choose one as RTCCLK, and then RTCCLK first passes through the prescaler to divide the clock.
Remainder register (DIV): It is a self-decreasing counter that stores the current count value.
Reload register: It is the counting target and determines the frequency division value. After division, a 1Hz second counting signal is obtained, which leads to a 32-bit counter that increments once a second.
Three signals can trigger interrupts, namely the second signal, the counter overflow signal and the alarm signal. The three signals are first controlled by the interrupt output. The three signals are first controlled by the interrupt output. Only the enabled interrupt can be directed to the NVIC.
4: Notes on RTC operation
Doing the following will enable access to BKP and RTC:
Set PWREN and BKPEN of RCC_APB1ENR and enable PWR and BKP clocks
Set the DBP of PWR_CR to enable access to BKP and RTC
If the RTC's APB1 interface has been disabled when reading the RTC register, the software must first wait for the RSF bit (register synchronization flag) in the RTC_CRL register to be set to 1 by hardware.
The CNF bit in the RTC_CRL register must be set so that the RTC can enter the configuration mode before writing to the RTC_PRL, RTC_CNT, and RTC_ALR registers. In fact, this operation is in the library function. Each function that writes odd registers, It automatically adds this operation for us, so we don’t need to call the code separately to enter the configuration mode.
A write operation to any RTC register must be performed after the previous write operation is completed. You can determine whether the RTC register is being updated by querying the RTOFF status bit in the RTC_CR register. Writing to the RTC register is only possible when the RTOFF status bit is 1
Four: Case
A: Read and write backup register
1: Connection diagram
2: Steps
1: Set PWREN and BKPEN of RCC_APB1ENR and enable PWR and BKP clocks
2: Set the DBP of PWR_CR to enable access to BKP and RTC
3: code
Simple implementation of BKP functions
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 1;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
Delay_ms(20);
KeyNum = 2;
}
return KeyNum;
}
/*
执行以下操作将使能对BKP和RTC的访问:
1: 设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
2: 设置PWR_CR的DBP,使能对BKP和RTC的访问
*/
uint16_t ArrayWrite[]={0x1234,0x5678};
uint16_t ArrayRead[2];
uint16_t KeyNum;
int main(void)
{
Key_Init();
OLED_Init();
//1: 设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
//2: 设置PWR_CR的DBP,使能对BKP和RTC的访问
PWR_BackupAccessCmd(ENABLE);
OLED_ShowString(1,1,"W:");
OLED_ShowString(3,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(3,3,ArrayRead[0],4);
OLED_ShowHexNum(3,8,ArrayRead[1],4);
}
}
Doing the following will enable access to BKP and RTC:
1: Set PWREN and BKPEN of RCC_APB1ENR and enable PWR and BKP clocks
2: Set the DBP of PWR_CR to enable access to BKP and RTC
B: real-time clock
1: Connection diagram
2: Function introduction
In the file stm32f10x_rcc.h ----- clock-related functions
void RCC_LSEConfig(uint8_t RCC_LSE);
void RCC_LSICmd(FunctionalState NewState);
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
void RCC_RTCCLKCmd(FunctionalState NewState)
RCC_LSEConfig : configure external low-speed clock (LSE)
RCC_LSICmd : configure internal low-speed clock (LSI)
RCC_RTCCLKConfig : This function is used to select the clock source of RTCCLK. It is actually the data selector that configures the PPT.
RCC_RTCCLKCmd : Enable--turn on or off the RTC clock
After the clock is selected, it is necessary to obtain the flag bit and wait for the flag to be completed before operating
RCC_LSEConfig(RCC_LSE_ON);//选择外部低速时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//LSE准备ok了
In the file stm32f10x_rcc.h -----get the flag bit function
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
In the file stm32f10x_rtc.h -----Enter RTC configuration mode
void RTC_EnterConfigMode(void)
The function of this function is to set the CNF of CRL to 1 and enter the configuration mode.
The CNF bit in the RTC_CRL register must be set so that the RTC enters configuration mode before writing to the RTC_PRL, RTC_CNT, and RTC_ALR registers.
In the file stm32f10x_rtc.h -----Exit RTC configuration mode
void RTC_ExitConfigMode(void)
Function: It is to clear the CNF bit
In the file stm32f10x_rtc.h -----CNT counter related
uint32_t RTC_GetCounter(void)
void RTC_SetCounter(uint32_t CounterValue)
RTC_GetCounter : Get RTC counter value
RTC_SetCounter : the value written to CNT
In the file stm32f10x_rtc.h-----prescaler
void RTC_SetPrescaler(uint32_t PrescalerValue)
RTC_SetPrescaler : Write the value of the prescaler----This value will be written to the PRL reload register of the prescaler and is used to configure the division coefficient of the prescaler
In the file stm32f10x_rtc.h ----- write the value of the alarm clock
void RTC_SetAlarm(uint32_t AlarmValue)
In the file stm32f10x_rtc.h ----- Read the DIV remainder register in the prescaler
uint32_t RTC_GetDivider(void);
The remainder odd register is a self-decreasing counter. Obtaining the value of the remainder odd register is generally to obtain a more detailed time.
In the file stm32f10x_rtc.h -----wait for the completion of the operation
void RTC_WaitForLastTask(void);
void RTC_WaitForSynchro(void);
RTC_WaitForLastTask : Wait for the last operation to complete
A write operation to any RTC register must be performed after the previous write operation is completed. You can determine whether the RTC register is being updated by querying the RTOFF status bit in the RTC_CR register. Writing to the RTC register is only possible when the RTOFF status bit is 1
RTC_WaitForSynchro : Wait for synchronization----clear the RSF flag, then loop until RSF is 1
If the RTC's APB1 interface has been disabled when reading the RTC register, the software must first wait for the RSF bit (register synchronization flag) in the RTC_CRL register to be set to 1 by hardware.
3: Code
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MYRTC.h"
uint16_t MyRTC_Time[] = {2023, 1, 1, 23, 59, 55};
void MYRTC_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR1)!=0xA5A5)
{
//LSE的频率是32.768KHz,也就是32768Hz
RCC_LSEConfig(RCC_LSE_ON);//选择外部低速时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//LSE准备ok了
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//配置RTC时钟RTCCLK
RCC_RTCCLKCmd(ENABLE);//开启RTC时钟
RTC_WaitForLastTask();//等待上次操作完成
RTC_WaitForSynchro();//等待同步时钟
//写预分频器
RTC_SetPrescaler(32768-1);
RTC_WaitForLastTask();
RTC_SetCounter(1672588795); //写入CNT
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1,0xA5A5);
}
else
{
RTC_WaitForLastTask();//等待上次操作完成
RTC_WaitForSynchro();//等待同步时钟
}
}
void MYRTC_Settime(void)
{
//内部的定义typedef unsigned int time_t; /* date/time in unix secs past 1-Jan-70 */
time_t time_cnt;
struct tm time_date;
time_date.tm_year = MyRTC_Time[0] - 1900;
time_date.tm_mon = MyRTC_Time[1] - 1;
time_date.tm_mday = MyRTC_Time[2];
time_date.tm_hour = MyRTC_Time[3];
time_date.tm_min = MyRTC_Time[4];
time_date.tm_sec = MyRTC_Time[5];
//默认是伦敦时间, 转化为北京的东八区的时间
time_cnt=mktime(&time_date)-8*60*60; //mktimer日期类型的时间数据类型--转化为--秒计数器数据类型
RTC_SetCounter(time_cnt);//写入CNT计数器
RTC_WaitForLastTask();
}
void MyRTC_ReadTime(void)
{
time_t time_cnt;
struct tm time_date;
time_cnt = RTC_GetCounter() + 8 * 60 * 60;
time_date = *localtime(&time_cnt); //秒计数器数据类型--转化为---日期类型的时间数据类型
MyRTC_Time[0] = time_date.tm_year + 1900;
MyRTC_Time[1] = time_date.tm_mon + 1;
MyRTC_Time[2] = time_date.tm_mday;
MyRTC_Time[3] = time_date.tm_hour;
MyRTC_Time[4] = time_date.tm_min;
MyRTC_Time[5] = time_date.tm_sec;
}
int main(void)
{
OLED_Init();
MYRTC_init();
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)
{
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);
OLED_ShowNum(4, 6, RTC_GetDivider(), 10);
}
}