当前位置:   article > 正文

STM32学习和实践笔记(38):RTC实时时钟实验

STM32学习和实践笔记(38):RTC实时时钟实验

1.STM32F1 RTC介绍

 STM32 的实时时钟( RTC)是一个独立的定时器。

STM32 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 

RTC模块和时钟配置是在后备区域,无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要保证后备区域供电正常,RTC便不会停止工作,所以通常会在后备区域供电端加一个纽扣电池,即使主电源停止供电,后备电源也会启动供电,从而保证RTC时钟不停的运行,只有当主电源和后备纽扣电池都没有电的时,RTC才停止工作。 

从 RTC 的定时器特性来说,它是一个 32 位的计数器,只能向上计数。它的时钟来源有三种,分别为高速外部时钟的 128 分频( HSE/128)、 低速内部时钟 LSI 以及低速外部时钟 LSE。

但一般都是使用低速外部时钟 LSE作为时钟来源。因为只有这样主电源掉电RTC才不会停止。

LSE 通常都是32.768KHZ ,因为2的15次方刚好是32768,这样方便对这个频率进行分频。例如,2的15次方,二进制向左移一位,变成2的14次方,就是一次分频,即32768/2=16384.

2. RTC结构框图

  STM32F1 RTC拥有这么多功能,是由RTC内部结构决定。要更好的理解STM32F1的RTC,就需要了解它内部的结构。如图32.1.1所示:(大家也可以查看《STM32F10x中文参考手册》-16实时时钟(RTC)章节内容

  系统复位后默认禁止访问后备寄存器和 RTC,防止对后备区域(BKP)的意外写操作。执行以下操作使能对后备寄存器和 RTC 的访问

(1) 设置 RCC_APB1ENR 寄存器的 PWRENBKPEN 位来使能电源和后备接口时钟

(2) 设置电源控制寄存器(PWR_CR)的 DBP 位使能对后备寄存器和 RTC 的访问

  设置后备寄存器为可访问后,在第一次通过 APB1 接口访问 RTC 时, 因为时钟频率的差异,所以必须等待 APB1 与 RTC 外设同步,确保被读取出来的 RTC 寄存器值是正确的。若在同步之后,一直没有关闭 APB1 的 RTC 外设接口,就不需要再次同步了

  如果内核要对 RTC寄存器进行任何的写操作,在内核发出写指令后, RTC模块在 3个RTC CLK 时钟之后,才开始正式的写 RTC 寄存器操作

由于 RTC CLK 的频率比内核主频低得多,所以每次操作后必须要检查 RTC关闭操作标志位 RTOFF,当这个标志被置 1 时,写操作才正式完成。

3.STM32F1 RTC配置步骤

  RTC相关库函数在stm32f10x_rtc.c和stm32f10x_rtc.h文件中)具体配置步骤如下:

(1)使能电源时钟和后备域时钟,开启RTC后备寄存器写访问

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);

PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问

(2)复位备份区域,开启外部低速振荡器

BKP_DeInit();

RCC_LSEConfig(RCC_LSE_ON);

(3)选择 RTC 时钟,并使能

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

RCC_RTCCLKCmd(ENABLE);

(4)设置 RTC 的分频以及配置 RTC 时钟

RTC_EnterConfigMode();// 允许配置

RTC_ExitConfigMode();

void RTC_SetPrescaler(uint32_t PrescalerValue);

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

RTC_ITConfig(RTC_IT_SEC, ENABLE);

void RTC_SetCounter(uint32_t CounterValue);

(5)更新配置,设置 RTC 中断分组

RTC_ExitConfigMode();//退出配置模式,更新配置

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);

BKP_WriteBackupRegister(BKP_DR1, 0XA0A0);

uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);

(6)编写RTC中断服务函数

RTC_IRQHandler

FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);

RTC_ClearITPendingBit(RTC_IT_SEC);

3.硬件电路

本实验使用到硬件资源如下

1)D1指示灯

2)串口1

3)RTC

  RTC属于STM32F1芯片内部的资源,只要通过软件配置好即可使用。

D1指示灯用来提示系统运行状态。串口1将读取的RTC时间日期信息打印出来。

这里需要注意RTC 不能断电,否则时间数据将会丢失,如果想让时间在断电后还可以继续走,那么必须确保开发板上的纽扣电池有电。      

4.编写RTC控制程序

  本实验所要实现的功能是:设置RTC时间日期初值,在RTC秒中断内使用串口打印出RTC日期和时间,D1指示灯闪烁提示系统运行。

程序框架如下:

(1)初始化RTC,设置RTC时间日期初值

(2)开启RTC的秒中断,编写RTC中断函数,

(3)在RTC中断内更新时间并打印输出

(4)编写主函数

main.c

  1. #include "system.h"
  2. #include "led.h"
  3. #include "SysTick.h"
  4. #include "usart.h"
  5. #include "rtc.h"
  6. int main()
  7. {
  8. u8 i=0;
  9. SysTick_Init(72);
  10. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
  11. LED_Init();
  12. USART1_Init(9600);
  13. RTC_Init();
  14. while(1)
  15. {
  16. i++;
  17. if(i%20 ==0)
  18. {
  19. led1=!led1;//LED1闪,用来指示主程序循环是否运行
  20. delay_ms(300);
  21. }
  22. }
  23. }

         rtc.c

  1. #include "rtc.h"
  2. #include "SysTick.h"
  3. #include "system.h"
  4. #include "usart.h"
  5. _calendar calendar;
  6. void RTC_NVIC_Confing()//RTC中断优先级配置函数
  7. {
  8. NVIC_InitTypeDef NVIC_InitStructure;
  9. //设置中断优先级,使能中断通道
  10. NVIC_InitStructure.NVIC_IRQChannel= RTC_IRQn;
  11. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;
  12. NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
  13. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  14. NVIC_Init(&NVIC_InitStructure);
  15. }
  16. void RTC_Get()
  17. {
  18. u32 timedata =0;
  19. timedata=RTC_GetCounter();
  20. calendar.hour=timedata/3600;
  21. calendar.min=(timedata%3600)/60;
  22. calendar.sec=timedata%60;
  23. }
  24. //初回1:初始化失败
  25. //初回0:初始化成功
  26. u8 RTC_Init() //有返回值是因为需要判断初始化是否成功
  27. {
  28. u8 temp =0;
  29. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能电源时钟
  30. RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//使能后备域时钟
  31. PWR_BackupAccessCmd(ENABLE);//打开后备寄存器访问
  32. if(BKP_ReadBackupRegister(BKP_DR1)!=0xA0A0)//后备寄存器有42个,都可以用来存放后备数据,这里选用第1个
  33. {
  34. BKP_DeInit();//复位备份区域,
  35. RCC_LSEConfig(RCC_LSE_ON);//开启外部低速振荡器
  36. while((RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET)&&(temp<250)) //等待外部低速振荡ready
  37. {
  38. temp++;
  39. delay_ms(10);
  40. }
  41. if(temp>=250)
  42. {
  43. return 1;
  44. }
  45. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//配置RTCC的时钟源为LSE
  46. RCC_RTCCLKCmd(ENABLE);
  47. RTC_WaitForLastTask();//等待写操作完成
  48. RTC_WaitForSynchro();//等待时钟同步
  49. RTC_ITConfig(RTC_IT_SEC,ENABLE);//配置中断类型为秒中断并开启
  50. RTC_WaitForLastTask();//等待写操作完成
  51. RTC_EnterConfigMode();// 允许配置
  52. RTC_SetPrescaler(32767);
  53. RTC_WaitForLastTask();//等待写操作完成
  54. RTC_SetCounter(0xf73f);//初始化时间初值为17:34:55,计算方法是全部计算成秒,即17*3600+34*60+55=0xf73f
  55. RTC_ExitConfigMode();
  56. BKP_WriteBackupRegister(BKP_DR1, 0xA0A0);//这样第二次开机时就不会进入上面的初始化了
  57. }
  58. else //第二次开机时走这里
  59. {
  60. RTC_WaitForSynchro();//等待时钟同步
  61. RTC_ITConfig(RTC_IT_SEC,ENABLE);//配置中断类型为秒中断并开启
  62. RTC_WaitForLastTask();//等待写操作完成
  63. }
  64. RTC_NVIC_Confing();
  65. RTC_Get();
  66. return 0;
  67. }
  68. void RTC_IRQHandler(void)
  69. {
  70. if(RTC_GetITStatus(RTC_IT_SEC)!=RESET)//判断秒中断是否产生,如产生执行下面的语句
  71. {
  72. RTC_Get();
  73. printf("RTC Time:%d:%d:%d\r\n",calendar.hour,calendar.min,calendar.sec);
  74. }
  75. RTC_ClearITPendingBit(RTC_IT_SEC);//清除中断状态标志
  76. }

程序烧写到开发板,实验结果如下,实验是成功的。

                      

                  

         

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/774826
推荐阅读
相关标签
  

闽ICP备14008679号