STM32 introductory tutorial (RTC real-time clock & BKP backup register)

Reference tutorial:[12-1] Unix timestamp_bilibili_bilibili

1. Unix Timestamp is defined asThe number of seconds that have elapsed since 0:00:00 on January 1, 1970 UTC/GMT a>, leap seconds are not considered.

(1)The timestamp is stored in a seconds counter, which is a 32-bit/64-bit integer variable.

(2)The second counter is the same for all time zones in the world. Different time zones add offsets to get the local time.

2. 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.

3. 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 cesium 133 atoms under zero magnetic field is 1 second. When the difference between the atomic clock's time of one day and the time it takes for the Earth to rotate once exceeds 0.9 seconds, UTC will perform a leap second to ensure that its timing is consistent with the Earth's rotation.

4. The time.h module of C language provides related functions for time acquisition and timestamp conversion, which can easily perform seconds counter, date and time (it is a structure, the parameters of which are year, month, day, hour, minute, second, day of the week, etc.) and Conversion between strings.

function

effect

time_t time(time_t*);

Get system clock

struct tm* gmtime(const time_t*);

Seconds counter converted to datetime (GMT)

struct tm* localtime(const time_t*);

Seconds counter converted to datetime (local time)

time_t mktime(struct tm*);

Convert datetime to seconds counter (local time)

char* ctime(const time_t*);

Convert seconds counter to string (default format)

char* asctime(const struct tm*);

Convert datetime to string (default format)

size_t strftime(char*, size_t, const char*, const struct tm*);

Convert datetime to string (custom format)

5. BKP (Backup Registers) backup registers:

(1) 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 will not be reset when the system is woken up in standby mode, or when the system is reset, or the power is reset.

(2) An intrusion event generated by the TAMPER pin will clear the contents of all backup registers and apply for an interrupt. In the interrupt function, you can continue to clear data in other memories and lock the device, which can be used to prevent malignant events such as data theft. .

(3) The RTC pin outputs the RTC calibration clock, RTC alarm pulse or second pulse.

(4) Store the RTC clock calibration register.

(5) User data storage capacity: 20 bytes (medium capacity and small capacity) / 84 bytes (large capacity and interconnected type).

6. Basic structure of BKP:

7. RTC (Real Time Clock) real-time clock:

(1)RTC is an independent timer that can provide clock and calendar functions for the system.

(2)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.

(3) 32-bit programmable counter, which can correspond to the seconds counter of Unix timestamp.

(4) 20-bit programmable prescaler can adapt to input clocks of different frequencies.

(5) Three RTC clock sources can be selected:

①HSE clock divided by 128 (usually 8MHz/128)

②LSE oscillator clock (usually 32.768KHz, this clock is generally selected as RTCCLK)

③LSI oscillator clock (40KHz)

8. RTC block diagram:

(1) The circuit in the backup area can use the backup battery to maintain operation after the main power supply fails.

(2)RTCCLK is the clock input to RTC through the selector. Generally, the LSE oscillator clock is selected. The clock entering RTC is first divided by the prescaler.

(3) The RTC prescaler consists of two registers. RTC_PRL is the reload register (determines the frequency division coefficient), RTC_DIV is the remainder register (essentially a decrement counter), and DIV is negative for the RTCCLK clock pulse. Counting, when it decrements to 0, a clock pulse will be output to TR_CLK, and at the same time, PRL will write the reload value into the DIV, thereby achieving the frequency division effect.

(4)RTC_CNT is the second counter. Every time TR_CLK has a clock pulse, the counter value is +1. In theory, TE_CLK should be configured to generate one clock pulse per second.

(5) RTC_ALR is the alarm clock register. It is the same length as RTC_CNT and is used to set the alarm clock. The user can write a timestamp in ALR. When the values ​​of ALR and CNT are equal, an RTC_Alarm signal will be generated leading to the interrupt system on the right. At the same time It is also possible to bring the STM32 out of standby mode. (The value of RTC_ALR will not change by itself and needs to be set by the user)

(6) RTC_Second is a second interrupt signal. Every clock pulse will generate a second interrupt signal; RTC_Overflow is an overflow interrupt signal, but for RTC_CNT, it stores a 32-bit unsigned number, which will not be available until 2016. A count overflow occurred. (SECF, OWF, and ALRF are interrupt flag bits, SECIE, OWIE, and ALRIE are interrupt enable bits)

(7) Reading and writing registers in RTC requires passing the APB1 bus (RTC is a device on the APB1 bus).

9. Hardware circuit:

10. Precautions for BKP and RTC operation:

(1) Performing the following operations 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 and enable access to BKP and RTC. (Using PWR_BackupAccessCmd function)

(2)If the APB1 interface of RTC has been in a disabled state when reading the RTC register, the software must first wait for the RSF bit (register synchronization flag) in the RTC_CRL register Set by hardware to 1.

(3)The CNF bit in the RTC_CRL register must be set so that the RTC enters the configuration mode before writing to the RTC_PRL, RTC_CNT, and RTC_ALR registers.

(4)The 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. The RTC register can be written to only when the RTOFF status bit is 1.

11. Read and write backup register:

(1) Connect the circuit as shown in the figure below, and make a copy of the OLED display project folder to use as a template.

(2) There are BKP related functions in the stm32f10x_bkp.h file:

[1]BKP_DeInit function: Restore the default configuration and can be used to clear all BKP data.

[2]BKP_TamperPinLevelConfig function: Configure whether TAMPER is a high-level trigger or a low-level trigger (intrusion detection function).

[3]BKP_TamperPinCmd function: Choose whether to turn on the intrusion detection function.

[4]BKP_ITConfig function: Choose whether to enable interrupts.

[5]BKP_RTCOutputConfig function: configure the clock output function and select the output clock source.

[6]BKP_SetRTCCalibrationValue function: Set the RTC calibration value.

[7]BKP_WriteBackupRegister function: Write backup register.

[8]BKP_ReadBackupRegister function: Read the backup register.

[9]BKP_GetFlagStatus function: Get the flag bit.

[10]BKP_ClearFlag function: clear the flag bit.

[11]BKP_GetITStatus function: Get the flag bit in the interrupt function.

[12]BKP_ClearITPendingBit function: clear the flag bit in the interrupt function.

(3) Paste the following code in the main.c file, then compile it, download the program to the development board and debug it (mainly the difference between the VBAT pin powered on and off after the development board is powered off, observe the BKP in both cases Whether the data in will be reset).

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

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

uint8_t KeyNum;

int main()
{
	OLED_Init();
	Key_Init();
	
	OLED_ShowString(1, 1, "W:");
	OLED_ShowString(2, 1, "R:");
	
	//使能PWR和BKP时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	
	//使能对BKP和RTC的访问
	PWR_BackupAccessCmd(ENABLE);
	
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)   //按下按键1,ArrayWrite中的数据自增并写入BKP
		{
			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);
		}
		//读取BKP中的数据
		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);
	}
}

12. Real-time clock:

(1) Connect the circuit as shown in the figure below, and make a copy of the OLED display project folder to use as a template.

(2) There are several functions related to this example in the stm32f10x_rcc.h file.

[1]RCC_LSEConfig function: Configure the LES external low-speed clock.

[2]RCC_LSICmd function: Configure LSI internal low-speed clock.

[3]RCC_RTCCLKConfig function: Configure the data selector of RTCCLK and select the clock source of RTCCLK.

[4]RCC_RTCCLKCmd function: Allow the clock selected by RTCCLK to enter the RTC.

[5]RCC_GetFlagStatus function: Get the flag bit.

[6]RCC_ClearFlag function: Clear the flag bit.

(3) There are functions related to the RTC module in the stm32f10x_rtc.h file.

[1]RTC_ITConfig function: configure interrupt output.

[2]RTC_EnterConfigMode function: RTC enters configuration mode (set the CNF bit of the CRL register to 1).

[3]RTC_ExitConfigMode function: RTC exits configuration mode (set CNF bit 01 in CRL register).

[4]RTC_GetCounter function: Read CNT counter (get time).

[5]RTC_SetCounter function: Write CNT counter (set time).

[6]RTC_SetPrescaler function: Write the PRL reload register of the prescaler, that is, set the frequency division coefficient.

[7]RTC_SetAlarm function: Write alarm register.

[8]RTC_GetDivider function: Read the DIV remainder register of the prescaler.

[9]RTC_WaitForLastTask function: Wait for the last operation to complete (wait for RTOFF=1).

[10]RTC_WaitForSynchro function: Wait for synchronization (wait for REF=1).

[11]RTC_GetFlagStatus function: Get the flag bit.

[12]RTC_ClearFlag function: clear the flag bit.

[13]RTC_GetITStatus function: Get the flag bit in the interrupt function.

[14]RTC_ClearITPendingBit function: clear the flag bit in the interrupt function.

(3) Add the MyRTC.h file and MyRTC.c file to the System group of the project to encapsulate the code of the RTC module.

①MyRTC.h file:

#ifndef __MyRTC_H
#define __MyRTC_H

extern uint16_t MyRTC_Time[];

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

#endif

②MyRTC.c file:

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

uint16_t MyRTC_Time[] = {2023, 1, 1, 23, 59, 55};  //2023年1月1日23:59:55

void MyRTC_SetTime(void);

void MyRTC_Init(void)
{
	//使能PWR和BKP时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	
	//使能对BKP和RTC的访问
	PWR_BackupAccessCmd(ENABLE);
	
	if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)  //RTC只需初始化一遍即可(关机后再开机,计时不会被重置)
	{
		//开启LSE的时钟
		RCC_LSEConfig(RCC_LSE_ON);
		
		//等待LES时钟开启
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
		
		//配置RTCCLK的数据选择器,指定LSE为时钟源
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		
		//允许RTCCLK选择的时钟进入RTC
		RCC_RTCCLKCmd(ENABLE);
		
		//等待同步,等待前一次写操作结束
		RTC_WaitForLastTask();
		RTC_WaitForSynchro();
		
		//配置预分频器,输出1Hz的时钟(RTC_SetPrescaler函数中有使RTC进入配置模式的过程)
		RTC_SetPrescaler(32768 - 1);  //32.768KHz / 32768 = 1Hz
		RTC_WaitForLastTask();  //等待前一次写操作结束
		
		//给RTC一个初始时间
		MyRTC_SetTime();
		
		//第一次初始化RTC时给BKP写值,如果程序复位,初始化函数会再执行一遍
		//而程序复位时BKP不会被重置,可以依据BKP中的值是否为A5A5判断是否需要初始化RTC
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
	}
	else
	{
		RTC_WaitForLastTask();
		RTC_WaitForSynchro();
	}
}

void MyRTC_SetTime(void)
{
	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;  
	//日期时间结构体转换为伦敦时间的时间戳,再调整为北京时间的时间戳
	//(这步只是为了CNT使用得到北京时间的时间戳,即使使用伦敦的时间戳也不影响最终结果)
	
	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;
	//当前时间戳是北京时间的时间戳,进行转换时需要换回伦敦时间的时间戳
	//(这步只是为了CNT使用北京时间的时间戳,即使使用伦敦的时间戳也不影响最终结果)
	
	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;
}

(3) Paste the following code in the main.c file, then compile it, download the program to the development board and debug it (mainly the difference between the VBAT pin powered on and off after the development board is powered off, observe the RTC in both cases whether the timing has been reset).

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

int main()
{
	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);
	}
}

Guess you like

Origin blog.csdn.net/Zevalin/article/details/134788248