【STM32】RTC程序示例

00. 目录

01. RTC时钟简介

STM32F4 的实时时钟(RTC)相对于 STM32F1 来说,改进了不少,带了日历功能了,STM32F4 的 RTC,是一个独立的 BCD 定时器/计数器。RTC 提供一个日历时钟(包含年月日时分秒信息)、两个可编程闹钟(ALARM A 和 ALARM B)中断,以及一个具有中断功能的周
期性可编程唤醒标志。RTC 还包含用于管理低功耗模 式的自动唤醒单元。

两个 32 位寄存器(TR 和 DR)包含二进码十进数格式 (BCD) 的秒、分钟、小时(12 或24 小时制)、星期、日期、月份和年份。此外,还可提供二进制格式的亚秒值。

STM32F4 的 RTC 可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。并且还可以进行夏令时 补偿。

RTC 模块和时钟配置是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变,只要后备区域供电正常,那么 RTC 将可以一直运行。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前,先要取消备份区域(BKP)写保护。

02. 硬件设计

用到的硬件资源有:
1) 指示灯 DS0
2) 串口
3) TFTLCD 模块
4) RTC

03. RTC日历配置步骤

①使能PWR时钟:RCC_APB1PeriphClockCmd();

② 使能后备寄存器访问: PWR_BackupAccessCmd()

③ 配置RTC时钟源,使能RTC时钟:

RCC_RTCCLKConfig();

RCC_RTCCLKCmd();

如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);

④ 初始化RTC(同步/异步分频系数和时钟格式):RTC_Init ();

⑤ 设置时间:RTC_SetTime ();

⑥设置日期:RTC_SetDate();

04. 设置和获取日期示例

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. 设置闹钟中断示例

//设置闹钟时间(按星期闹铃,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. 设置唤醒中断示例


//周期性唤醒定时器设置  
/*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. 附录

7.1 【STM32】STM32系列教程汇总

网址:【STM32】STM32系列教程汇总

08. 声明

该教程参考了正点原子的《STM32 F4 开发指南》

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/108493983