[STM32] RTC program example

00. Table of Contents

01. Introduction to RTC clock

Compared with STM32F1, the real-time clock (RTC) of STM32F4 has improved a lot, with a calendar function. The RTC of STM32F4 is an independent BCD timer/counter. RTC provides a calendar clock (including year, month, day, hour, minute, and second information), two programmable alarms (ALARM A and ALARM B) interrupts, and a
periodic programmable wake-up flag with interrupt function . The RTC also contains an automatic wake-up unit for managing low-power modes.

Two 32-bit registers (TR and DR) contain the second, minute, hour (12 or 24 hour format), day of the week, date, month, and year in binary decimal format (BCD). In addition, sub-second values ​​in binary format can also be provided.

The RTC of STM32F4 can automatically compensate the number of days of the month to 28, 29 (leap year), 30 and 31 days. And can also compensate for daylight saving time.

The RTC module and clock configuration are in the backup area, that is, the RTC settings and time remain unchanged after the system is reset or wake up from standby mode. As long as the backup area is powered normally, the RTC will continue to run. However, after the system is reset, access to the backup register and RTC is automatically prohibited to prevent accidental write operations to the backup area (BKP). Therefore, before setting the time, cancel the write protection of the backup area (BKP).

02. Hardware design

The hardware resources used are:
1) Indicator light DS0
2) Serial port
3) TFTLCD module
4) RTC

03. RTC calendar configuration steps

①Enable PWR clock: RCC_APB1PeriphClockCmd();

② Enable backup register access: PWR_BackupAccessCmd()

③ Configure the RTC clock source and enable the RTC clock:

RCC_RTCCLKConfig();

RCC_RTCCLKCmd();

If using LSE, open LSE: RCC_LSEConfig(RCC_LSE_ON);

④ Initialize RTC (synchronous/asynchronous frequency division coefficient and clock format): RTC_Init ();

⑤ Set time: RTC_SetTime ();

⑥ Set date: RTC_SetDate();

04. Example of setting and obtaining date

rtc.h

#ifndef __RTC_H__
#define __RTC_H__

#include "sys.h"

//RTC初始化
u8 MY_RTC_Init(void);

//RTC时间设置
ErrorStatus RTC_Set_Time(u8 hour, u8 min, u8 sec, u8 ampm);

//RTC日期设置
ErrorStatus RTC_Set_Date(u8 year, u8 mon, u8 day, u8 week);

#endif /*__RTC_H__*/

rtc.c

#include "rtc.h"
#include "delay.h"


//RTC时间设置
ErrorStatus RTC_Set_Time(u8 hour, u8 min, u8 sec, u8 ampm)
{
    
    
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_TimeStruct.RTC_H12 = ampm;
	RTC_TimeStruct.RTC_Hours = hour;
	RTC_TimeStruct.RTC_Minutes = min;
	RTC_TimeStruct.RTC_Seconds = sec;

	return RTC_SetTime(RTC_Format_BIN,&RTC_TimeStruct);
}

//RTC日期设置
ErrorStatus RTC_Set_Date(u8 year, u8 mon, u8 day, u8 week)
{
    
    
	RTC_DateTypeDef RTC_DateStruct;
	
	RTC_DateStruct.RTC_Year = year;
	RTC_DateStruct.RTC_Month = mon;
	RTC_DateStruct.RTC_Date = day;
	RTC_DateStruct.RTC_WeekDay = week;

	return RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
}

//RTC初始化
u8 MY_RTC_Init(void)
{
    
    
	u16 retry = 0x1fff;
	
	RTC_InitTypeDef RTC_InitStruct;

	//使能PWR时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	
	//使能后备寄存器访问
	PWR_BackupAccessCmd(ENABLE);
	
	//判断是否第一次初始化
	if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x8080)
	{
    
    
	
		//开启LSE
		RCC_LSEConfig(RCC_LSE_ON);
		//等待LSE准备就绪
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
		{
    
    
			retry++;
			delay_ms(10);
		}
		
		//开始LSE失败
		if (0 ==  retry)
		{
    
    
			return 1;
		}
		
		//设置RTC时钟为LSE
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		
		//使能RTC时钟
		RCC_RTCCLKCmd(ENABLE);
		
		//初始化RTC
		RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
		RTC_InitStruct.RTC_AsynchPrediv = 0x7F;
		RTC_InitStruct.RTC_SynchPrediv = 0xFF;
		
		RTC_Init(&RTC_InitStruct);
		
		//设置时间
		RTC_Set_Time(16, 06, 50, RTC_H12_AM);
		
		//设置日期
		RTC_Set_Date(20, 9, 9, RTC_Weekday_Wednesday);
		
		//标记已经初始化
		RTC_WriteBackupRegister(RTC_BKP_DR0, 0x8080);
		
	}

	return 0;
}

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "usmart.h"
#include "lcd.h"
#include "rtc.h"

//LED状态设置函数
void led_set(u8 sta)
{
    
    
	LED1 = sta;
}

//函数参数调用测试函数
void test_fun(void(*ledset)(u8), u8 sta)
{
    
    
	ledset(sta);
}

int main(void)
{
    
     
	u8 buf[40];
	u8 t = 0;
	
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_DateTypeDef RTC_DateStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	
	delay_init(168);
	
	uart_init(115200);
	
	usmart_dev.init(84);
	
	LED_Init();
	LCD_Init();
	
	//RTC初始化
	MY_RTC_Init();
	
	
	POINT_COLOR = RED;
	
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"USMART TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2020/09/09");	 
	
	while(1)
	{
    
    
		t++;
		
		//每隔100ms更新显示
		if (0 == t % 10)
		{
    
    
			RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
			sprintf((char*)buf, "Time: %02d:%02d:%02d", RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, RTC_TimeStruct.RTC_Seconds);
			LCD_ShowString(30, 140, 210, 16, 16, buf);
			
			
			RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
			sprintf((char*)buf, "Date: 20%02d-%02d-%02d", RTC_DateStruct.RTC_Year, RTC_DateStruct.RTC_Month, RTC_DateStruct.RTC_Date);
			LCD_ShowString(30, 160, 210, 16, 16, buf);
			
			sprintf((char*)buf, "Week: %d", RTC_DateStruct.RTC_WeekDay);
			LCD_ShowString(30, 180, 210, 16, 16, buf);		
			
		}
		
		
		if (0 == t % 20)
		{
    
    
			LED1 = !LED1;
		}
		
		//睡眠10毫秒
		delay_ms(10);
	}
}

05. Example of setting alarm interrupt

//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref  RTC_Alarm_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(u8 week,u8 hour,u8 min,u8 sec)
{
    
    
	RTC_TimeTypeDef RTC_TimeStruct;
	
	RTC_AlarmTypeDef RTC_AlarmStruct;
	
	EXTI_InitTypeDef EXTI_InitStruct;
	
	NVIC_InitTypeDef NVIC_InitStruct;
	
	
	//关闭闹钟A
	RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
	
	//设置闹钟参数
	RTC_TimeStruct.RTC_H12 = RTC_H12_AM;
	RTC_TimeStruct.RTC_Hours = hour;
	RTC_TimeStruct.RTC_Minutes = min;
	RTC_TimeStruct.RTC_Seconds = sec;
	
	
	RTC_AlarmStruct.RTC_AlarmTime = RTC_TimeStruct;
	RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_None;
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay;
	RTC_AlarmStruct.RTC_AlarmDateWeekDay = week;
	
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStruct);

	//清除闹钟A的中断标志
	RTC_ClearITPendingBit(RTC_IT_ALRA);
	//清除中断线17上的中断标志
	EXTI_ClearITPendingBit(EXTI_Line17);
	
	//开启闹钟A中断
	RTC_ITConfig(RTC_IT_ALRA, ENABLE);
	
	//开启闹钟
	RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
	
	//初始化中断
	EXTI_InitStruct.EXTI_Line = EXTI_Line17;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStruct);
	
	//初始化中断优先级
	NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =  0x2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;
	NVIC_Init(&NVIC_InitStruct);
}

//闹钟中断处理函数
void RTC_Alarm_IRQHandler(void)
{
    
    
	if (RTC_GetFlagStatus(RTC_FLAG_ALRAF) == SET)
	{
    
    
		RTC_ClearFlag(RTC_FLAG_ALRAF);
		printf("ALARM A!\r\n");
	}
	
	//清中断
	EXTI_ClearITPendingBit(EXTI_Line17);	
}

06. Example of setting wake-up interrupt


//周期性唤醒定时器设置  
/*wksel:  @ref RTC_Wakeup_Timer_Definitions
#define RTC_WakeUpClock_RTCCLK_Div16        ((uint32_t)0x00000000)
#define RTC_WakeUpClock_RTCCLK_Div8         ((uint32_t)0x00000001)
#define RTC_WakeUpClok_RTCCLK_Div4         ((uint32_t)0x00000002)
#define RTC_WakeUpClock_RTCCLK_Div2         ((uint32_t)0x00000003)
#define RTC_WakeUpClock_CK_SPRE_16bits      ((uint32_t)0x00000004)
#define RTC_WakeUpClock_CK_SPRE_17bits      ((uint32_t)0x00000006)
*/
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(u32 wksel,u16 cnt)
{
    
    
		
	EXTI_InitTypeDef EXTI_InitStruct;
	
	NVIC_InitTypeDef NVIC_InitStruct;
	
	//关闭WakeUP
	RTC_WakeUpCmd(DISABLE);
	
	//配置WakeUP时钟分频系数或者来源
	RTC_WakeUpClockConfig(wksel);
	
	//设置WakeUP自动装载值
	RTC_SetWakeUpCounter(cnt);
	
	//清除中断标志
	RTC_ClearITPendingBit(RTC_IT_WUT);
	//清除中断线17上的中断标志
	EXTI_ClearITPendingBit(EXTI_Line22);
	
	//开启WakeUP中断
	RTC_ITConfig(RTC_IT_WUT, ENABLE);
	
	//使能WakeUp
	RTC_WakeUpCmd(ENABLE);
	
		//初始化中断
	EXTI_InitStruct.EXTI_Line = EXTI_Line22;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStruct);
	
	//初始化中断优先级
	NVIC_InitStruct.NVIC_IRQChannel = RTC_WKUP_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =  0x2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;
	NVIC_Init(&NVIC_InitStruct);


}


//唤醒中断处理函数
void RTC_WKUP_IRQHandler(void)
{
    
    
	if (RTC_GetFlagStatus(RTC_FLAG_WUTF) == SET)
	{
    
    
		RTC_ClearFlag(RTC_FLAG_WUTF);
		LED2 = !LED2;
	}
	
	//清中断
	EXTI_ClearITPendingBit(EXTI_Line22);	

}

07. Appendix

7.1 [STM32] STM32 series tutorial summary

Website: [STM32] STM32 series tutorial summary

08. Statement

This tutorial refers to the "STM32 F4 Development Guide" of Punctual Atom

Guess you like

Origin blog.csdn.net/dengjin20104042056/article/details/108493983