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);
- }
复制代码
|