你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32学习笔记12— RTC实验

[复制链接]
STMCU-管管 发布时间:2020-12-10 13:11
STM32学习笔记12— RTC实验

12.1 概述
实时时钟Real TimeClock(简称RTC),实时时钟芯片是日常生活中应用最为广泛的消费类电子产品之一。它为人们提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。有些时钟芯片为了在主电源掉电时,还可以工作,需要外加电池供电。


现在的ARM体系处理器基本都会内置RTC模块,STM32也不例外。STM32内部RTC结构如下图所示。


11.png


RTC主要有两个部分组成,第一部分的APB1接口用来和APB1总线相连,此单元还包含一组16位寄存器,可通过APB1总线对其进行读写操作。另一部分由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,它可编程产生最长为1秒的RTC时间基准TR_CLK。RTC的预分频模块包含了一个20位的可编程分频器。如果在RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。


RTC模块和时钟配置系统是在后备区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和RTC,以防止对后备区域的意外写操作。所以在要设置时间之前,先要取消备份区域写保护。


12.2 相关寄存器
12.2.1 控制寄存器1:RTC_CRH
12.png
Bit 2:允许溢出中断位
0:屏蔽溢出中断
1:允许溢出中断
Bit 1:允许闹钟中断
0:屏蔽闹钟中断
1:允许闹钟中断
Bit 0:允许秒中断
0:屏蔽秒中断
1:允许秒中断

12.2.2 控制寄存器2:RTC_CRL
13.png
Bit 5:RTC操作关闭
0:写操作未完成
1:操作已完成
Bit 4:配置标志
0:退出配置模式
1:进入配置模式
Bit 3:RTC同步标志


RTC_CNT寄存器和RTC_DIV寄存器由软件更新或清0时,此位由硬件置1。在APB1复位后,或APB1时钟停止后,此位必须由软件清0。要进行任何的读操作之前,用户程序必须等待这位被硬件置1


0:寄存器尚未被同步
1:寄存器已经被同步
Bit 2:溢出标志
当32位可编程计数器溢出时,此位由硬件置1。此位只能由软件清0
0:无溢出
1:32位可编程计数器溢出
Bit 1:闹钟标志


当32位可编程计数器达到RTC_ALR寄存器所设置的预定值,此位由硬件置1。此位只能由软件清0。


0:无闹钟
1:有闹钟
Bit 0:秒标志


当32位可编程预分频器溢出时,此位由硬件置1,同时RTC计数器加1。此位只能由软件清除。


0:秒标志条件不成立
1:秒标志条件成立

12.2.3 预分频装载寄存器1:RTC_PRLH
14.png
Bit 3~Bit 0:RTC预分频装载值高位

12.2.4 预分频装载寄存器2:RTC_PRLL
15.png
Bit 15~Bit 0:RTC预分频装载值低位


注:RTC时钟频率根据预分频寄存器的值有如下计算公式。


其中RTCCLK代表的RTC的输入时钟,一般默认32.768kHz。


12.3 实验例程
功能:读取RTC的日期显示在LCD上面。



(1)创建rtc.h文件输入以下代码。

  1. /*********************************************************************************************************
  2.                 RTC    驱    动    文    件
  3. *********************************************************************************************************/
  4. #ifndef _RTC_H_
  5. #define _RTC_H_

  6. #include "sys.h"
  7. /*********************************************************************************************************
  8.                   数    据    结    构
  9. *********************************************************************************************************/
  10. typedef struct
  11. {
  12.   u8 year;                    //年
  13.   u8 month;                    //月
  14.   u8 date;                    //日
  15.   u8 hour;                    //时
  16.   u8 minute;                    //分
  17.   u8 second;                    //秒
  18. }RTC_Data;
  19. extern RTC_Data RTC_Time;
  20. /*********************************************************************************************************
  21.                   函    数    列    表
  22. *********************************************************************************************************/
  23. void RTC_Init( void ) ;                                          //RTC初始化
  24. void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second ) ;            //设置时间
  25. void RTC_Get_Time( void ) ;                                        //获取时间

  26. #endif
复制代码

(2)创建rtc.c文件并输入以下代码。

  1. #include "rtc.h"
  2. /***************************************************
  3. Name    :RTC_Init
  4. Fuction    :RTC初始化
  5. Parameter  :None
  6. Return    :None
  7. ***************************************************/
  8. void RTC_Init()
  9. {
  10.   if( BKP->DR1!=0x5050 )
  11.   {
  12.     RCC->APB1ENR |= 1<<28 ;                                      //使能PWR时钟
  13.     RCC->APB1ENR |= 1<<27 ;                                      //使能BKP时钟,RTC校准在BKP相关寄存器中
  14.     PWR->CR |= 1<<8 ;                                        //取消BKP相关寄存器写保护
  15.     RCC->BDCR |= 1<<16 ;                                      //备份区域软复位
  16.     RCC->BDCR &= ~( 1<<16 ) ;                                    //备份区域软复位结束
  17.     RCC->BDCR |= 1<<0 ;                                        //开启外部低速振荡器
  18.     while( ( RCC->BDCR&0x02 )!=0x02 ) ;                                //等待外部时钟就绪
  19.     RCC->BDCR |= 1<<8 ;                                        //LSI作为RTC时钟
  20.     RCC->BDCR |= 1<<15 ;                                      //RTC时钟使能
  21.     while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
  22.     while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步完成
  23.     RTC->CRH &= ~( 7<<0 ) ;                                      //不允许中断,CRH寄存器低三位有效
  24.     while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
  25.     RTC->CRL |= 1<<4 ;                                        //进入配置模式
  26.     RTC->PRLH = 0 ;
  27.     RTC->PRLL = 32767 ;                                        //设定分频值
  28.     RTC->CRL &= ~( 1<<4 ) ;                                      //退出配置模式
  29.     while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
  30.     BKP->DR1 = 0x5050 ;
  31.   }
  32.   else
  33.   {
  34.     while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步
  35.       while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器操作完成
  36.   }
  37. }
  38. /***************************************************
  39. Name    :Is_Leap_Year
  40. Function  :闰年判定
  41. Parameter  :
  42.       year:年份
  43. Return    :闰年
  44. ***************************************************/
  45. u8 Is_Leap_Year( u16 year )
  46. {
  47.   //必须能被4整除
  48.   if( year%4==0 )
  49.   {
  50.     if( year%100==0 )
  51.     {
  52.       if( year%400==0 )
  53.         return 1 ;
  54.       else
  55.         return 0 ;
  56.     }
  57.     else
  58.       return 1 ;
  59.   }
  60.   else
  61.     return 0;
  62. }
  63. /***************************************************
  64. Name    :RTC_Set_Time
  65. Fuction    :设置时间
  66. Parameter  :
  67.       year:年
  68.       month:月
  69.       date:日
  70.       hour:时
  71.       minute:分
  72.       second:秒
  73. Return    :None
  74. ***************************************************/
  75. u8 mon_table[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ;
  76. void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second )
  77. {
  78.   u16 t ;
  79.   u32 seccount = 0 ;
  80.   //把所有年份的秒钟相加
  81.   for( t=1970; t<year+2000; t++ )
  82.   {
  83.     if( Is_Leap_Year( t ) )
  84.       seccount += 31622400 ;                                    //闰年的秒钟数
  85.     else
  86.       seccount += 31536000 ;                                    //平年的秒钟数
  87.   }
  88.   month -= 1 ;
  89.   for( t=0; t<month; t++ )     //把前面月份的秒钟数相加
  90.   {
  91.     seccount += ( u32 )mon_table[ t ]*86400 ;                            //月份秒钟数相加
  92.     if( Is_Leap_Year( year+2000 )&&( t==1 ) )
  93.       seccount += 86400 ;                                      //闰年2月份增加一天的秒钟数     
  94.   }
  95.   seccount += ( date-1 )*86400 ;                                    //把前面日期的秒钟数相加
  96.   seccount += hour*3600 ;                                        //小时秒钟数
  97.     seccount += minute*60 ;                                        //分钟秒钟数
  98.   seccount += second ;                                        //最后的秒钟加上去
  99.   //设置时钟
  100.     RCC->APB1ENR |= 1<<28 ;                                        //使能电源时钟
  101.     RCC->APB1ENR |= 1<<27 ;                                        //使能备份时钟
  102.   PWR->CR |= 1<<8 ;                                          //取消备份区写保护
  103.   RTC->CRL |= 1<<4 ;                                          //允许配置
  104.   RTC->CNTL = seccount&0xFFFF ;
  105.   RTC->CNTH = seccount>>16 ;
  106.   RTC->CRL &= ~( 1<<4 ) ;                                        //配置更新
  107.   while( ( RTC->CRL&0x20 )!=0x20 ) ;                                  //等待RTC寄存器操作完成
  108.   RTC_Get_Time() ;                                          //设置完之后更新一下数据
  109. }
  110. /***************************************************
  111. Name    :RTC_Get_Time
  112. Fuction    :获取时间
  113. Parameter  :None
  114. Return    :None
  115. ***************************************************/
  116. RTC_Data RTC_Time;
  117. void RTC_Get_Time()
  118. {
  119.   u16 daycnt=0;
  120.   u32 timecount=0;
  121.   u32 temp=0;
  122.   u16 temp1=0;
  123.   //得到计数器中的值
  124.   timecount = RTC->CNTH ;
  125.   timecount <<= 16 ;
  126.   timecount += RTC->CNTL ;
  127.   //得到天数
  128.    temp = timecount/86400 ;
  129.   //超过一天了
  130.   if( daycnt!=temp )
  131.   {   
  132.     daycnt = temp ;
  133.     temp1 = 1970 ;                                          //从1970年开始
  134.     while( temp>=365 )
  135.     {
  136.       //闰年
  137.       if( Is_Leap_Year( temp1 ) )
  138.       {
  139.         if( temp>=366 )
  140.           temp -= 366 ;                                    //闰年的秒钟数
  141.         else
  142.           break ;
  143.       }
  144.       else
  145.         temp -= 365;                                      //平年
  146.       temp1 ++ ;
  147.     }
  148.     RTC_Time.year = temp1-2000 ;                                  //得到年份
  149.     temp1 = 0 ;
  150.     //超过了一个月
  151.     while( temp>=28 )
  152.     {
  153.       if( Is_Leap_Year( RTC_Time.year+2000 )&&( temp1==1 ) )//当年是不是闰年/2月份
  154.       {
  155.         if( temp>=29 )
  156.           temp -= 29 ;//闰年的秒钟数
  157.         else
  158.           break;
  159.       }
  160.       else
  161.       {
  162.         if( temp>=mon_table[ temp1 ] )
  163.           temp -= mon_table[ temp1 ] ;                            //平年
  164.         else
  165.           break ;
  166.       }
  167.       temp1 ++ ;
  168.     }
  169.     RTC_Time.month = temp1+1 ;                                    //得到月份
  170.     RTC_Time.date = temp+1 ;                                    //得到日期
  171.   }
  172.   temp = timecount%86400 ;                                      //得到秒钟数
  173.   RTC_Time.hour = temp/3600 ;                                      //小时
  174.   RTC_Time.minute = ( temp%3600 )/60 ;                                //分钟
  175.   RTC_Time.second = ( temp%3600 )%60 ;                                //秒钟
  176. }
复制代码
(3)创建1.c文件并输入以下代码。
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart1.h"
  4. #include "lcd.h"
  5. #include "rtc.h"

  6. int main()
  7. {
  8.   u8 Str[ 50 ] ;
  9.   STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  10.   SysTick_Init( 72 ) ;                                        //SysTick初始化
  11.   USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  12.   LCD_Init() ;                                            //LCD初始化
  13.   RTC_Init() ;
  14.   RTC_Set_Time( 20, 12, 10, 10, 8, 0 ) ;
  15.   while( 1 )
  16.   {
  17.     RTC_Get_Time() ;
  18.     sprintf( ( char * )Str, "20%02d-%02d-%02d %02d:%02d:%02d", RTC_Time.year, RTC_Time.month, RTC_Time.date, RTC_Time.hour, RTC_Time.minute, RTC_Time.second ) ;
  19.     LCD_ShowString( 10, 10, Str ) ;
  20.     delay_ms( 500 ) ;
  21.   }
  22. }
复制代码


1 收藏 评论0 发布时间:2020-12-10 13:11

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版