找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 23055|回复: 5
打印 上一主题 下一主题
收起左侧

[零基础学习STM32]第十讲:RTC实时时钟实验—显示日期和时间

[复制链接]
跳转到指定楼层
楼主
ID:278743 发表于 2018-3-22 11:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、概述
1、实时时钟定
      实时时钟(RTC)是一个独立的BCD定时器/计数器。RTC提供一个日历时钟和两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。
      两个32位寄存器包含二进码十进位格式(BCD)的秒、分钟、小时(12或24小时制)、星期几、日期、月份和年份。此外,还可以提供二进制格式的亚秒值。
     系统可以自动将月份的天数补偿位28、29(闰年),30和31天。并且还可以进行夏令时的补偿。
     其他32位寄存器还包括可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。
     上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。
     无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。
2、实时时钟主要特性
      RTC的主要特性如下:
  • 包含亚秒、秒、分钟、小时(12/24小时制)、星期几、日期、月份和年份的日期。
  • 软件可编程的夏令时补偿。
  • 两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
  • 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
  • 参考时钟检测:可使用更加精确的第二时钟源(50Hz或60Hz)来提高日历的精确度。
  • 利用亚秒级移位特性与外部时钟实现精确同步。
  • 可屏蔽中断/事件:
         —  闹钟A
         —  闹钟B
         —  唤醒中断
         —  时间戳
         —  入侵检测
  • 数字校准电路(周期性计数器调整)。
        —  精度为5ppm。
        —  精度为0.95ppm, 在数秒钟的校准窗口中获得。
  • 用于时间保存的时间戳功能(1个事件)。
  • 入侵检测:
       —  2个带可配置过滤器和内部上拉的入侵事件。
  • 20个备份寄存器(80字节)。发生入侵检测事件时,将复位备份寄存器。
  • 复用功能输出(RTC_OUT),可选择以下两个输出之一:

      — RTC_CALIB:512Hz或1Hz时钟输出(LSE频率为32.768kHZ)。可通过将RTC_CR寄存器中的COE【23】位置1来使能此输出。该输出可连接到器件RTC_AF1功能。
      — RTC_ALARM(闹钟A、闹钟B或唤醒)。可通过配置RTC_CR寄存器的OSEL【1:0】位选择此输出。该输出可连接到器件RTC_AF1功能。
  • RTC复用功能输入:

     — RTC_TS:时间戳事件检测。该输入可连接到器件RTC_AF1和RTC_AF2功能。
     — RTC_TAMP1:TAMPER1 事件检测。该输入可连接到器件RTC_AF1和RTC_AF2功能。
     — RTC_TAMP2:TAMPER2 事件检测。
     — RTC_REFIN:参考时钟输入(通常为市电,50Hz或60Hz)。
二、硬件电路
1、时钟源
      iCore3异构双核心工控板采用32.768K无源晶体为系统提供RTC实时时钟,其电路连接图如下所示。32.768KHz外部无源晶体连接 OSC32_IN和OSC32_OUT两引脚之间,为获得稳定的频率必须加两个电容构成外部震荡电路。
                   图10_0 外部振荡电路
2、备用电源
     RTC实时时钟在iCore3电路中具有备用电源,时刻保证时钟通电。
         图10_1 备用电池电路
三、实验原理
       STM32的实时时钟(RTC)是一个独立的定时器,有一组连续计数的计时器,通过软件来对其进行相关的配置,可以提供时钟功能,通过修改计数器的值可以调整时钟,最终通过串口在终端显示时间。
四、源代码
1、主函数
  1. /*
  2. * Name                : main
  3. * Description         : ---
  4. * Author              : ysloveivy.
  5. *
  6. * History
  7. * --------------------
  8. * Rev                 : 0.00
  9. * Date                : 11/23/2015
  10. *
  11. * create.
  12. * --------------------
  13. */
  14. int main(void)
  15. {
  16.         int i;
  17.         RTC_TimeTypeDef rtc_time;
  18.         RTC_DateTypeDef rtc_date;
  19.         int second_bak = 0;
  20.         led.initialize();
  21.         LED_RED_ON;
  22.         rtc.initialize();
  23.         usart4.initialize(115200);
  24.         usart4.printf("\x0c");                       //清屏        
  25.         usart4.printf("\033[1;32;40m");           //设置字体终端为绿色
  26.         usart4.printf("\r\n\r\nhello! I am iCore3!\r\n\r\n\r\n");
  27.         while(1){
  28.         for(i = 0;i < 1000000;i++);
  29.         //读取RTC日期和时间
  30.         RTC_GetTime(RTC_Format_BIN,&rtc_time);
  31.         RTC_GetDate(RTC_Format_BIN,&rtc_date);
  32.         //当秒数据与备份不一致时,向终端打印时间/日期
  33.         if(second_bak != rtc_time.RTC_Seconds){
  34.         usart4.printf("  %02d:%02d:%02d  ",rtc_time.RTC_Hours,rtc_time.RTC_Minutes,rtc_time.RTC_Seconds);
  35.         usart4.printf("20%02d-%02d-%02d  \r",rtc_date.RTC_Year,rtc_date.RTC_Month,rtc_date.RTC_Date);\
  36.         second_bak = rtc_time.RTC_Seconds;         //秒数据备份
  37.                 }
  38.         }
  39. }
复制代码
2、RTC初始化
  1. /*
  2. * Name               : initialize
  3. * Description        : ---
  4. * Author             : ysloveivy.
  5. *
  6. * History
  7. * -------------------
  8. * Rev                : 0.00
  9. * Date               : 11/23/2015
  10. *
  11. * create.
  12. * -------------------
  13. */
  14. static int initialize(void)
  15. {
  16.         //判断读到的备份寄存器的值与写入的值是否一样
  17.         if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2){
  18.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);   
  19.                   //使能PWR时钟
  20.                 PWR_BackupAccessCmd(ENABLE);
  21. RCC_BackupResetCmd(ENABLE);
  22.                 RCC_BackupResetCmd(DISABLE);
  23.                 RCC_LSEConfig(RCC_LSE_ON);                                       //LSE 开启   
  24. while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) ==RESET);            //检查指定的RCC标志位设置与否,等待低速晶振就绪
  25.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);            //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
  26.                 RCC_RTCCLKCmd(ENABLE);                                           //使能RTC时钟
  27. RTC_WaitForSynchro();                                            
  28.                                                                                              //等待APB1和RTC等时钟同步
  29.                 rtc_set_time(13,57,12,RTC_H12_PM);                               //设置时间
  30.                 rtc_set_date(15,11,28,6);                                        //设置日期
  31.                 RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);                    //向备份寄存器中写入数值
  32.         }
  33.         return 0;
  34. }
  35. /*
  36. * Name               : initialize
  37. * Description        : ---
  38. * Author             : ysloveivy.
  39. *
  40. * History
  41. * -------------------
  42. * Rev                : 0.00
  43. * Date               : 11/23/2015
  44. *
  45. * create.
  46. * -------------------
  47. */
  48. static int rtc_set_time(unsigned char hour,unsigned char min,unsigned char sec,unsigned char ampm)
  49. {
  50.         //设置时间
  51.         RTC_TimeTypeDef RTC_TimeTypeInitStructure;
  52.         RTC_TimeTypeInitStructure.RTC_Hours=hour;
  53.         RTC_TimeTypeInitStructure.RTC_Minutes=min;
  54.         RTC_TimeTypeInitStructure.RTC_Seconds=sec;
  55.         RTC_TimeTypeInitStructure.RTC_H12=ampm;
  56.         RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
  57.         return 0;
  58. }
复制代码
3、RTC配置介绍
  1. static int initialize(void)
  2. {
  3.         //判断读到的备份寄存器的值与写入的值是否一样
  4.         if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2){
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);   
  6.                   //使能PWR时钟
  7.                 PWR_BackupAccessCmd(ENABLE);
  8. RCC_BackupResetCmd(ENABLE);
  9.                 RCC_BackupResetCmd(DISABLE);
  10.                 RCC_LSEConfig(RCC_LSE_ON);                                       //LSE 开启   
  11. while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) ==RESET);         //检查指定的RCC标志位设置与否,等待低速晶振就绪
  12.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);           //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
  13.                 RCC_RTCCLKCmd(ENABLE);                                           //使能RTC时钟
  14. RTC_WaitForSynchro();                                            
  15. //等待APB1和RTC等时钟同步
  16.                 rtc_set_time(13,57,12,RTC_H12_PM);                               //设置时间
  17.                 rtc_set_date(15,11,28,6);                                        //设置日期
  18.                 RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);                    //向备份寄存器中写入数值
  19.         }
  20.         return 0;
  21. }
  22. static int rtc_set_date(unsigned char year,unsigned char month,unsigned char date,unsigned char week)
  23. {
  24.         //设置日期
  25.         RTC_DateTypeDef RTC_DateTypeInitStructure;
  26.         RTC_DateTypeInitStructure.RTC_Date=date;
  27.         RTC_DateTypeInitStructure.RTC_Month=month;
  28.         RTC_DateTypeInitStructure.RTC_WeekDay=week;
  29.         RTC_DateTypeInitStructure.RTC_Year=year;
  30.         RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
  31.         return 0;
  32. }
复制代码
4、结构体介绍
  1. /**
  2.   * @brief  RTC Init structures definition  
  3.   */
  4. typedef struct
  5. {
  6.   uint32_t RTC_HourFormat;        指定RTC小时格式,
  7. 这个参数可以是@ref rtc_hour_format的值。
  8.   uint32_t RTC_AsynchPrediv;      指定RTC异步预分值,
  9. 此参数必须设置为低于0x7F的值。
  10.   uint32_t RTC_SynchPrediv;       指定RTC同步预分值,
  11. 此参数必须设置为低于0x7FFF的值。
  12. }RTC_InitTypeDef;
  13. /**
  14.   * @brief  RTC Time structure definition  
  15.   */
  16. typedef struct
  17. {
  18.   uint8_t RTC_Hours;        指定RTC时间小时,此参数必须设置为0-12范围内的值。如果选择RTC_HourFormat_12,则为0-23。该RTC_HourFormat_24被选中。
  19.   uint8_t RTC_Minutes;             指定RTC时间分钟,
  20. 此参数必须设置为0-59范围内值。
  21.   uint8_t RTC_Seconds;             指定RTC时间秒,
  22. 此参数必须设置为0-59范围内的值。
  23.   uint8_t RTC_H12;                  指定RTC AM/PM时间,
  24. 这个参数可以是@ref rtc_am_pm_definition的值。
  25. }RTC_TimeTypeDef;
  26. /**
  27.   * @brief  RTC Date structure definition  
  28.   */
  29. typedef struct
  30. {
  31.   uint8_t RTC_WeekDay;           指定RTC日期工作日,这个参数可以是@refrtc_weekday_definition的值。
  32.   uint8_t RTC_Month;             指定RTC日期月(BCD格式),这个参数可以是@ref rtc_month_date_definition的值。
  33.   uint8_t RTC_Date;               指定RTC日期,此参数必须设置为1-31范围内的值。
  34.   uint8_t RTC_Year;               指定RTC日期年,此参数必须设置为0-99范围内的值。
  35. }RTC_DateTypeDef;
  36. /**
  37.   * @brief  RTC Alarm structure definition  
  38.   */
  39. typedef struct
  40. {
  41.   RTC_TimeTypeDef RTC_AlarmTime;     指定RTC警报时间成员。
  42.   uint32_t RTC_AlarmMask;             指定RTC报警面具,这个参数可以是@ref rtc_alarmmask_definition 的值。
  43.   uint32_t RTC_AlarmDateWeekDaySel;  指定RTC警报是在日期或工作日,
  44. 这个参数可以是@ref rtc_alarmdateweekday_definition的值。
  45.   uint8_t RTC_AlarmDateWeekDay;      指定RTC报警日期/工作日。
  46. 如果选择了警报日期,则该参数。
  47. 必须设置为1-31范围内的值。
  48. 如果选择了闹钟工作日,这个。
  49. 参数可以是@ref rtc_weekday_definition的值。
  50. }RTC_AlarmTypeDef;
复制代码

五、实验现象

      在终端屏幕上可以看到显示的时间和日期(如下图所示)。

                图10_3 实验现象图

六、代码包下载

     网盘:https://pan.baidu.com/s/1jHuZcnc



iCore3_10_RTC.rar

2.66 MB, 下载次数: 119, 下载积分: 黑币 -5

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:275094 发表于 2018-12-7 09:43 | 只看该作者
学习了
回复

使用道具 举报

板凳
ID:161151 发表于 2018-12-7 11:20 | 只看该作者
有可以用按键设置时间的例程吗?
回复

使用道具 举报

地板
ID:170847 发表于 2019-4-18 09:40 | 只看该作者
学习了
回复

使用道具 举报

5#
ID:286761 发表于 2020-3-3 16:27 | 只看该作者
太好了,正在学习这类内容。
回复

使用道具 举报

6#
ID:696424 发表于 2020-4-28 12:22 | 只看该作者
有仿真吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表