• STM32 Cortex-M4 RTC实时时钟保姆级别总结


    一、概述

    实时时钟的缩写是RTC,RTC是集成电路,通常称为时钟芯片。RTC通常情况下需要外接32.768kHz晶体,匹配电容、备份电源等元件。

    作用:经常用来做时间的计算和显示来源。使用定时器,通过定时一秒钟也可以达到这个时间的计算和显示,定时器程序复位会回复到默认的数值。

    RTC的优点是:只要优点,时间就会一直的走下去,就算程序复位,时间也不会重置,有纽扣电池,就算单片机没电,时间也会一直计算下去,就算没有纽扣电池,拔掉单片机所有的输入电源,RTC才会停止。

    二、 特性

    包含亚秒、秒、分钟、小时( 12/24 小时制)、星期几、日期、月份和年份的日历。软件可编程的夏令时补偿。

    两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
    ● 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
    ● 参考时钟检测:可使用更加精确的第二时钟源(50 Hz 或 60 Hz)来提高日历的精确度。
    ● 利用亚秒级移位特性与外部时钟实现精确同步。
    ● 可屏蔽中断/事件:
    — 闹钟 A
    — 闹钟 B
    — 唤醒中断
    — 时间戳
    — 入侵检测
    ● 数字校准电路(周期性计数器调整)
    — 精度为 5 ppm
    — 精度为 0.95 ppm,在数秒钟的校准窗口中获得
    ● 用于事件保存的时间戳功能( 1 个事件)
    ● 入侵检测:
    — 2 个带可配置过滤器和内部上拉的入侵事件
    ● 20 个备份寄存器( 80 字节)。发生入侵检测时间时,可以复位备份寄存器。

    三、RTC的时钟

       LSE:外部低速时钟

     

    初始化配置

    RTC寄存器是一个32位的寄出去你,除了当BYPSHAD=0时对日历影子寄存器执行的读访问之外,APB接口会在访问RTC寄存器时引入2个等待周期。

     日历配置

      系统复位后,应用可读取 RTC_ISR 寄存器中的 INITS 标志,以检查日历是否已初始化。如 
    果该标志为 0,表明日历尚未初始化,因为年份字段设置为其上电复位时的默认值 (0x00)。
    要在初始化之后读取日历,必须首先用软件检查 RTC_ISR 寄存器的 RSF 标志是否置 1。

    复位RTC

     

     同步RTC

      初始化平移操作前,用户必须检查确认 SS[15] = 0,以确保不会发生上溢。对 RTC_SHIFTR 寄存器执行写操作以启动平移操作时,硬件会将 SHPF 标志置 1 以指示平 移操作挂起。完成平移操作时,硬件会将将该位清零。该同步功能与参考时钟检测功能不兼容:当 REFCKON=1 时,固件不能对 RTC_SHIFTR 执 行写操作。

    RTC初始化步骤

    1、选择时钟源

     在时钟树开启相应的时钟,顺序如下:

     

    这一步的代码

    1. void rtc_init()
    2. {
    3. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开电源
    4. PWR_BackupAccessCmd(ENABLE ); //使能后备寄存器访问
    5. }

    打开LSE后,需要进行精密校准,需要精密校准RTC的LSE时钟。

    使能RTC时钟,RCC文件里面专门为RTC提供时钟函数 ;

     

     2、使能PWR时钟

    使能PWR的电源接口时钟,

     想要激活RTC的写保护,那么必须显示使能PWR电源控制寄存器,因为这个控制器控制这RTC的写保护。

    接下来,就要进行对备份区的使能操作,

     

    3、使能后备区寄存器访问

    后备区和RTC内存是一起,所以后备区也需要使能,作用:第一次初始化完后,写入一个值,用于记录已经初始化过RTC的时间了,系统重启或者复位,我们需要读取这个备份区的数据,判断是否需要重新设置初始化时间。

     

    4、初始化RTC结构体

    在设置时间格式、预分频、初始化时间和日期,需要先进入初始化模式,时间和日期的值才可以更新。

    rtc.c

    1. void rtc_init()
    2. {
    3. RTC_InitTypeDef RTC_InitStructure;
    4. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开电源
    5. PWR_BackupAccessCmd(ENABLE ); //使能后备寄存器访问
    6. if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0X11)
    7. {
    8. RCC_LSEConfig(RCC_LSE_ON);//LSE开启
    9. while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));//等待lse稳定
    10. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//设置LSE为RTC时钟
    11. RCC_RTCCLKCmd(ENABLE);
    12. rtc_SetTimeData(11,22,54,22,4,26,2);
    13. RTC_WriteBackupRegister(RTC_BKP_DR0,0X11);
    14. }
    15. RTC_Set_AlarmA(2,11,38,20);
    16. RTC_Set_AlarmB(2,16,21,0);
    17. }

    5、设置时间

    1. RTC_TimeTypeInitStructure.RTC_Hours=hour;
    2. RTC_TimeTypeInitStructure.RTC_Minutes=min;
    3. RTC_TimeTypeInitStructure.RTC_Seconds=sec;
    4. RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;

     6、时钟日期

    现在相应的功能文件stm32f407x.rtc.h找到相应的时间和日期结构体函数;

     设置日期

    1. RTC_DateTypeInitStructure.RTC_Date=date;
    2. RTC_DateTypeInitStructure.RTC_Month=month;
    3. RTC_DateTypeInitStructure.RTC_WeekDay=week;
    4. RTC_DateTypeInitStructure.RTC_Year=year;

     7、备份区读写,用于判断是否初始化过时间

    1. void rtc_init()
    2. {
    3. RTC_InitTypeDef RTC_InitStructure;
    4. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开电源
    5. PWR_BackupAccessCmd(ENABLE ); //使能后备寄存器访问
    6. if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0X11)
    7. {
    8. RCC_LSEConfig(RCC_LSE_ON);//LSE开启
    9. while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));//等待lse稳定
    10. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//设置LSE为RTC时钟
    11. RCC_RTCCLKCmd(ENABLE);
    12. rtc_SetTimeData(11,22,54,22,4,26,2);
    13. RTC_WriteBackupRegister(RTC_BKP_DR0,0X11);
    14. }
    15. RTC_Set_AlarmA(2,11,38,20);
    16. RTC_Set_AlarmB(2,16,21,0);
    17. }

     完整代码

    rtc.c

    1. #include "rtc.h"
    2. #include "beep.h"
    3. #include "lcd.h"
    4. #include "stdio.h"
    5. u32 rct_AlarmA_flag;
    6. RTC_TimeTypeDef RTC_TimeTypeInitStructure;
    7. RTC_DateTypeDef RTC_DateTypeInitStructure;
    8. RTC_AlarmTypeDef RTC_AlarmStruct;
    9. //RTC时间设置函数
    10. //hour,min,sec:时,分,秒设定值
    11. //ampm:@RTC_AM_PM_Definitions:RTC_H12_AM/RTC_H12_PM
    12. //返回值:SUCEE(1),成功;ERROR(0),进入初始化模式失败
    13. void rtc_SetTimeData(u8 hour,u8 min,u8 sec,u8 year,
    14. u8 month,u8 date,u8 week)
    15. {
    16. RTC_TimeTypeInitStructure.RTC_Hours=hour;
    17. RTC_TimeTypeInitStructure.RTC_Minutes=min;
    18. RTC_TimeTypeInitStructure.RTC_Seconds=sec;
    19. RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
    20. RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
    21. RTC_DateTypeInitStructure.RTC_Date=date;
    22. RTC_DateTypeInitStructure.RTC_Month=month;
    23. RTC_DateTypeInitStructure.RTC_WeekDay=week;
    24. RTC_DateTypeInitStructure.RTC_Year=year;
    25. RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
    26. }
    27. void RTC_GetTimeDate(void)
    28. {
    29. static u8 temp=0;
    30. RTC_GetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
    31. RTC_GetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
    32. if(temp !=RTC_TimeTypeInitStructure.RTC_Seconds)
    33. {
    34. temp=RTC_TimeTypeInitStructure.RTC_Seconds;
    35. printf("%d:%d:%d\r\n",RTC_TimeTypeInitStructure.RTC_Hours,RTC_TimeTypeInitStructure.RTC_Minutes,RTC_TimeTypeInitStructure.RTC_Seconds);
    36. }
    37. }
    38. void RTC_Set_AlarmA(u8 week,u8 hour,u8 min,u8 sec)
    39. {
    40. NVIC_InitTypeDef NVIC_InitStruct;
    41. EXTI_InitTypeDef EXTI_InitStruct;
    42. RTC_AlarmCmd(RTC_Alarm_A, DISABLE);//关闭闹钟A
    43. RTC_TimeTypeInitStructure.RTC_Hours=hour;
    44. RTC_TimeTypeInitStructure.RTC_Minutes=min;
    45. RTC_TimeTypeInitStructure.RTC_Seconds=sec;
    46. RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
    47. RTC_AlarmStruct.RTC_AlarmDateWeekDay=week;
    48. RTC_AlarmStruct.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;
    49. RTC_AlarmStruct.RTC_AlarmMask=RTC_AlarmMask_None;
    50. RTC_AlarmStruct.RTC_AlarmTime=RTC_TimeTypeInitStructure;
    51. RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A,&RTC_AlarmStruct);
    52. EXTI_InitStruct.EXTI_Line = EXTI_Line17;//中断线号0
    53. EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断线使能
    54. EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
    55. EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
    56. EXTI_Init(&EXTI_InitStruct);
    57. NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn ;//中断源
    58. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能中断
    59. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
    60. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;//响应优先级
    61. NVIC_Init(&NVIC_InitStruct);
    62. RTC_ITConfig( RTC_IT_ALRA, ENABLE);//S使能闹钟A中断
    63. RTC_AlarmCmd(RTC_Alarm_A, ENABLE);//开启闹钟A
    64. }
    65. void RTC_Alarm_IRQHandler (void)
    66. {
    67. if(RTC_GetFlagStatus(RTC_FLAG_ALRAF))
    68. {
    69. rct_AlarmA_flag=1;
    70. RTC_ClearITPendingBit(RTC_IT_ALRA);
    71. EXTI_ClearITPendingBit( EXTI_Line17);
    72. }
    73. else if(RTC_GetFlagStatus(RTC_FLAG_ALRBF ))
    74. {
    75. RTC_ClearITPendingBit(RTC_IT_ALRB);
    76. EXTI_ClearITPendingBit( EXTI_Line17);
    77. }
    78. }
    79. void RTC_Set_AlarmB(u8 week,u8 hour,u8 min,u8 sec)
    80. {
    81. NVIC_InitTypeDef NVIC_InitStruct;
    82. EXTI_InitTypeDef EXTI_InitStruct;
    83. RTC_AlarmCmd(RTC_Alarm_B, DISABLE);//关闭闹钟B
    84. RTC_TimeTypeInitStructure.RTC_Hours=hour;
    85. RTC_TimeTypeInitStructure.RTC_Minutes=min;
    86. RTC_TimeTypeInitStructure.RTC_Seconds=sec;
    87. RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
    88. RTC_AlarmStruct.RTC_AlarmDateWeekDay=week;
    89. RTC_AlarmStruct.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;
    90. RTC_AlarmStruct.RTC_AlarmMask=RTC_AlarmMask_None;
    91. RTC_AlarmStruct.RTC_AlarmTime=RTC_TimeTypeInitStructure;
    92. RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B,&RTC_AlarmStruct);
    93. EXTI_InitStruct.EXTI_Line = EXTI_Line17;//中断线号0
    94. EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断线使能
    95. EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
    96. EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
    97. EXTI_Init(&EXTI_InitStruct);
    98. NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn ;//中断源
    99. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能中断
    100. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
    101. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;//响应优先级
    102. NVIC_Init(&NVIC_InitStruct);
    103. RTC_ITConfig( RTC_IT_ALRB, ENABLE);//S使能闹钟A中断
    104. RTC_AlarmCmd(RTC_Alarm_B, ENABLE);//开启闹钟A
    105. }
    106. void Rtc_Lcd_Display(void)
    107. {
    108. char hour[10];
    109. char min[10];
    110. char sec[10];
    111. RTC_GetTimeDate();
    112. sprintf(hour,"%.2d",RTC_TimeTypeInitStructure.RTC_Hours);
    113. sprintf(min,"%.2d",RTC_TimeTypeInitStructure.RTC_Minutes);
    114. sprintf(sec,"%.2d",RTC_TimeTypeInitStructure.RTC_Seconds);
    115. LCD_Show_Str_ChineseorChar(50,70,(u8 *)hour,BLACK,WHITE);
    116. LCD_Show_Str_ChineseorChar(80,70,(u8 *)min,BLACK,WHITE);
    117. LCD_Show_Str_ChineseorChar(110,70,(u8 *)sec,BLACK,WHITE);
    118. }
    119. void rtc_init()
    120. {
    121. RTC_InitTypeDef RTC_InitStructure;
    122. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开电源
    123. PWR_BackupAccessCmd(ENABLE ); //使能后备寄存器访问
    124. if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0X11)
    125. {
    126. RCC_LSEConfig(RCC_LSE_ON);//LSE开启
    127. while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));//等待lse稳定
    128. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//设置LSE为RTC时钟
    129. RCC_RTCCLKCmd(ENABLE);
    130. rtc_SetTimeData(11,22,54,22,4,26,2);
    131. RTC_WriteBackupRegister(RTC_BKP_DR0,0X11);
    132. }
    133. RTC_Set_AlarmA(2,11,38,20);
    134. RTC_Set_AlarmB(2,16,21,0);
    135. }

     rtc.h

    1. #ifndef __RTC_DECLS
    2. #define __RTC_DECLS
    3. #include "stm32f4xx.h"
    4. #include "io_bit.h"
    5. extern u32 rct_AlarmA_flag;
    6. void beep_init(void);
    7. void rtc_init(void);
    8. void RTC_GetTimeDate(void);
    9. void Rtc_Lcd_Display(void);
    10. #endif

    点赞加关注,打赏就更好了!!!

  • 相关阅读:
    10.1 校招 实习 内推 面经
    Java基础之jvm2
    Pikachu靶场——目录遍历漏洞和敏感信息泄露
    移动目标轨迹预测方法研究综述
    前端常用的编辑器、框架以及一些常用工具,帮助前端开发者更快成长。
    通知可以根据切入点表达式来进行增强,也可以根据自己的注解值来进行增强
    宝塔控制面板登陆不进去_宝塔磁盘已满
    java入门,@interface
    c语言练习题库
    INSERT INTO(实操十三)
  • 原文地址:https://blog.csdn.net/Lushengshi/article/details/126310174