• stm32f4xx-RTC实时时钟_calendar_alarm


    一、RTC

    RTC(Real_Time Clock)

    实时时钟 (RTC) 是一个独立的 BCD 定时器/计数器。RTC 提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC 还包含用于管理低功耗模式的自动唤醒单元。

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

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

    其它 32 位寄存器还包含可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。

    此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。

    上电复位后,所有 RTC 寄存器都会受到保护,以防止可能的非正常写访问。无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC 便不会停止工作。

    原理图

    static	uint32_t uwSynchPrediv = 0xFF;//异步分频
    static	uint32_t uwAsynchPrediv = 0x7F;//同步分频
    /*ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
    32.768KHz /128/256 = 1Hz
    
    • 1
    • 2
    • 3
    • 4

    LSE-RTC_PER–RTC_PER–RTC_WUTR–WUTF唤醒标志

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    二、中断配置

    《STM32F4xx中文参考手册.pdf》第585页

    1、 所有 RTC 中断均与 EXTI 控制器相连。

    2、要使能 RTC 闹钟中断,需按照以下顺序操作:

    1.将 EXTI 线 17 配置为中断模式并将其使能,然后选择上升沿有效。

    2.配置 NVIC 中的 RTC_Alarm IRQ 通道并将其使能。

    3.配置 RTC 以生成 RTC 闹钟(闹钟 A 或闹钟 B)。

    3、要使能 RTC 唤醒中断,需按照以下顺序操作:

    1.将 EXTI 线 22 配置为中断模式并将其使能,然后选择上升沿有效。

    2.配置 NVIC 中的 RTC_WKUP IRQ 通道并将其使能。

    3.配置 RTC 以生成 RTC 唤醒定时器事件。

    三、BCD码

    ​ 二进制编码的十进制数,简称BCD码。这种方式是用4位二进制码的组合代表十进制数的0,1,2,3,4,5,6,7,8,9十个数符,4位 二进制码有16种组合,原则上可任选其中的10种作为代码,分别代表十进制中的0,1,2,3,4,5,6,7,8,9这个 十个数符,最常用的BCD码称为8421BCD码,8421分别是4位二进制的位权值。

    在这里插入图片描述

    在这里插入图片描述

    四、库函数

    在这里插入图片描述

    1.RTC时钟源和时钟操作函数

     void RCC_RTCCLKConfig(uint32_t CLKSource)//时钟源选择
    
     void RCC_RTCCLKCmd(FunctionalState NewState)//时钟使能
    
    • 1
    • 2
    • 3

    2.RTC初始化函数

    ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
    typedef struct
    { 
     uint32_t RTC_HourFormat;  //小时格式:24/12
     uint32_t RTC_AsynchPrediv; //异步分频 系数
     uint32_t RTC_SynchPrediv; //同步分频系数
    }RTC_InitTypeDe
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.RTC日历配置相关函数

     ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
     void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
     ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
     void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
     uint32_t RTC_GetSubSecond(void);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.RTC闹钟相关函数

    ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm, FunctionalState NewState)
    void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm,  
                                RTC_AlarmTypeDef* RTC_AlarmStruct);
    void RTC_GetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, 
                                 RTC_AlarmTypeDef* RTC_AlarmStruct);
    void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm, uint32_t RTC_AlarmSubSecondValue, 
                                    uint32_t RTC_AlarmSubSecondMask) 
    uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.RTC 中断配置以及状态相关函数

    
    void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState);
    FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);
    void RTC_ClearFlag(uint32_t RTC_FLAG);
    ITStatus RTC_GetITStatus(uint32_t RTC_IT);
    void RTC_ClearITPendingBit(uint32_t RTC_IT);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7. RTC周期唤醒相关函数

    void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock);
    void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter);
    uint32_t RTC_GetWakeUpCounter(void);
    RTC_WakeUpCmd(DISABLE);//关闭WAKE UP
    
    • 1
    • 2
    • 3
    • 4

    8.RTC相关约束函数

     void RTC_WriteProtectionCmd(FunctionalState NewState);//取消写保护
     ErrorStatus RTC_EnterInitMode(void);//进入配置模式,RTC_ISR_INITF位设置为1
     void RTC_ExitInitMode(void)//退出初始化模式。
    
    • 1
    • 2
    • 3

    9.其他相关函数

    uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR)void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data)
    void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState)
    • 1
    • 2
    • 3

    10.RTC日期配置

    在这里插入图片描述

    11.RTC闹钟配置

    在这里插入图片描述

    12.RTC周期性自动唤醒配置

    在这里插入图片描述

    四、test

    calendar&alarm

    uint8_t G_RTCWakeUp_Status = 0;	//RTC_WakeUp中断flag
    uint8_t G_AlarmA_Status = 0;//AlarmA中断flag
    static	uint32_t uwSynchPrediv = 0xFF;//异步分频
    static	uint32_t uwAsynchPrediv = 0x7F;//同步分频
    void RTC_init(void)
    {
    	RTC_InitTypeDef RTC_InitStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR时钟
    	PWR_BackupAccessCmd(ENABLE);					 	//使能后备寄存器访问 
        if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x1234)		//是否第一次配置?
    	{
    		RCC_LSEConfig(RCC_LSE_ON);//LSE 开启    
    		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
    		{
    		}
    			
    		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
    		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟 
    
    		RTC_InitStructure.RTC_AsynchPrediv = uwSynchPrediv;//RTC异步分频系数(1~0X7F)
    		RTC_InitStructure.RTC_SynchPrediv  = uwAsynchPrediv;//RTC同步分频系数(0~7FFF)
    		RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;//RTC设置为,24小时格式
    		RTC_Init(&RTC_InitStructure);
     
            /* Set the date: Tuesday September 06th 2022 */
    		RTC_DateStructure.RTC_Year = 0x22;
    		RTC_DateStructure.RTC_Month = RTC_Month_September;
    		RTC_DateStructure.RTC_Date = 0x06;
    		RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Tuesday;
    		RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);
    	
    		/* Set the time to 14h 30mn 00s PM */
    		RTC_TimeStructure.RTC_H12     = RTC_H12_PM;
    		RTC_TimeStructure.RTC_Hours   = 0x14;
    		RTC_TimeStructure.RTC_Minutes = 0x30;
    		RTC_TimeStructure.RTC_Seconds = 0x00; 
    		RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);   
            
    		RTC_WriteBackupRegister(RTC_BKP_DR0,0x1234);	//标记已经初始化过了
    	} 
    }
    
    
    //周期性唤醒定时器设置  
    /*wksel:  @ref RTC_Wakeup_Timer_Definitions
    #define RTC_WakeUpClock_RTCCLK_Div16        ((uint32_t)0x00000000)
    #define RTC_WakeUpClock_RTCCLK_Div8         ((uint32_t)0x00000001)
    #define RTC_WakeUpClock_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(uint32_t wksel,uint16_t cnt)
    { 
    	EXTI_InitTypeDef   EXTI_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	RTC_WakeUpCmd(DISABLE);//关闭WAKE UP
    	RTC_WakeUpClockConfig(wksel);//唤醒时钟选择
    	RTC_SetWakeUpCounter(cnt);//设置WAKE UP自动重装载寄存器
    	
    	RTC_ClearITPendingBit(RTC_IT_WUT); //清除RTC WAKE UP的标志
        EXTI_ClearITPendingBit(EXTI_Line22);//清除LINE22上的中断标志位 
    	RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启WAKE UP 定时器中断
    	RTC_WakeUpCmd( ENABLE);//开启WAKE UP 定时器 
    	
    	EXTI_InitStructure.EXTI_Line = EXTI_Line22;//LINE22
    	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
    	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
    	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE22
    	EXTI_Init(&EXTI_InitStructure);//配置
     
    	NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn; 
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    	NVIC_Init(&NVIC_InitStructure);//配置
    }
    //#define RTC_AlarmDateWeekDaySel_Date      ((uint32_t)0x00000000)	每天    闹
    //#define RTC_AlarmDateWeekDaySel_WeekDay   ((uint32_t)0x40000000)  每星期	  闹
    //设置闹钟时间(按星期闹铃,24小时制)
    //week:星期几(1~7) @ref  RTC_Alarm_Definitions
    //hour,min,sec:小时,分钟,秒钟
    void RTC_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
    { 
    	EXTI_InitTypeDef   EXTI_InitStructure;
    	RTC_AlarmTypeDef RTC_AlarmTypeInitStructure;
    	RTC_TimeTypeDef RTC_TimeTypeInitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);//关闭闹钟A 
    	
        RTC_TimeTypeInitStructure.RTC_Hours=hour;//小时
    	RTC_TimeTypeInitStructure.RTC_Minutes=min;//分钟
    	RTC_TimeTypeInitStructure.RTC_Seconds=sec;//秒
    	RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
      
    	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDay=week;//星期
    	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;//按星期闹
    	RTC_AlarmTypeInitStructure.RTC_AlarmMask=RTC_AlarmMask_None;//精确匹配星期,时分秒
    	RTC_AlarmTypeInitStructure.RTC_AlarmTime=RTC_TimeTypeInitStructure;
        RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmTypeInitStructure);
     
    	
    	RTC_ClearITPendingBit(RTC_IT_ALRA);//清除RTC闹钟A的标志
    	EXTI_ClearITPendingBit(EXTI_Line17);//清除LINE17上的中断标志位 
    	
    	RTC_ITConfig(RTC_IT_ALRA,ENABLE);//开启闹钟A中断
    	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟A 
    	
    	EXTI_InitStructure.EXTI_Line = EXTI_Line17;//LINE17
    	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
    	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
    	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE17
    	EXTI_Init(&EXTI_InitStructure);//配置
    
    	NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn; 
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    	NVIC_Init(&NVIC_InitStructure);//配置
    }
    
    //RTC中断服务函数
    void RTC_WKUP_IRQHandler(void)
    {
    	if(RTC_GetITStatus(RTC_IT_WUT) == SET)
    	{
    		printf("RTC_WKUP_IRQHandler\r\n");
    		G_RTCWakeUp_Status = 1;
    		
    		//清空标志位
    		RTC_ClearITPendingBit(RTC_IT_WUT);
    		EXTI_ClearITPendingBit(EXTI_Line22);
    	}
    }
    //RTC_AlarmA中断服务函数
    void RTC_Alarm_IRQHandler(void)
    {
    	if(RTC_GetITStatus(RTC_IT_ALRA) == SET)
    	{
    		printf("RTC_Alarm_IRQHandler\r\n");
    		G_AlarmA_Status = 1;
    		
    		//清空标志位
    		RTC_ClearITPendingBit(RTC_IT_ALRA);
    		EXTI_ClearITPendingBit(EXTI_Line17);
    	}
    }
    
    int main(void)
    {
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        RTC_TimeTypeDef RTC_TimeStructure;
    	RTC_DateTypeDef RTC_DateStructure;
        USART1_init(115200);
        RTC_Init();
        RTC_Set_AlarmA(2,15,30,30);
        while(1)
    	{
    //		if(G_RTCWakeUp_Status)//中断唤醒方式
    //		{
    			//获取时间
    			RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure);
    			printf("%02x:%02x:%02x\r\n", RTC_TimeStructure.RTC_Hours, 
    										 RTC_TimeStructure.RTC_Minutes, 
    										 RTC_TimeStructure.RTC_Seconds);
    			
    			//获取日期
    			RTC_GetDate(RTC_Format_BCD, &RTC_DateStructure);
    			printf("20%02x/%02x/%02x Week:%x\r\n", RTC_DateStructure.RTC_Year, 
    												  RTC_DateStructure.RTC_Month, 
    												  RTC_DateStructure.RTC_Date, 
    												  RTC_DateStructure.RTC_WeekDay);
    			delay_ms(1000);
    //			G_RTCWakeUp_Status = 0;
    //		}
    		if(G_AlarmA_Status)
    		{
    			printf("Wake up the alarm clock is ringing\r\n");
    			break;
    
    			//G_AlarmA_Status = 0;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
  • 相关阅读:
    管理文件系统
    AI+医疗:使用神经网络进行医学影像识别分析 ⛵
    新闻快报| 虹科与瑞士Dimetix已联手合作三周年, 致力于提供高效、精确的激光测距解决方案!
    springboot基于JAVA的邮件过滤系统设计与实现
    小鹏汽车在滴滴上眺望远方
    【C语言】每日一题,快速提升(2)!
    多校联测11 THUSC
    Shell之wc命令
    中级-面试题目整理
    distroless 镜像介绍及 基于cbl-mariner的.NET distroless 镜像的容器
  • 原文地址:https://blog.csdn.net/qq_45698138/article/details/126732729