0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RTC实验

汽车电子技术 来源:滑小稽笔记 作者:电子技术园地 2023-03-01 15:46 次阅读

12.1 概述

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

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

poYBAGP_An-AXUzUAAGljwT34VQ575.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

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

OWIE

ALRIE

SECIE

Bit 2:允许溢出中断位

0:屏蔽溢出中断

1:允许溢出中断

Bit 1:允许闹钟中断

0:屏蔽闹钟中断
1:允许闹钟中断

Bit 0:允许秒中断

0:屏蔽秒中断

1:允许秒中断

12.2.2 控制寄存器2:RTC_CRL

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

RTOFF

CNF

RSF

OWF

ALRF

SECF

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

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

PRL[19:16]

Bit 3~Bit 0:RTC预分频装载值高位

12.2.4 预分频装载寄存器2:RTC_PRLL

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

PRL[15:0]

Bit 15~Bit 0:RTC预分频装载值低位

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

pYYBAGP_AoyABJbhAAAR-b703dM921.png

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

12.3 实验例程

功能:读取RTC的日期显示在LCD上面。

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

/*********************************************************************************************************
*********************************************************************************************************/
#ifndef _RTC_H_
#define _RTC_H_

#include "sys.h"
/*********************************************************************************************************
                  数    据    结    构
*********************************************************************************************************/
typedef struct
{
  u8 year;                    //年
  u8 month;                    //月
  u8 date;                    //日
  u8 hour;                    //时
  u8 minute;                    //分
  u8 second;                    //秒
}RTC_Data;
extern RTC_Data RTC_Time;
/*********************************************************************************************************
                  函    数    列    表
*********************************************************************************************************/
void RTC_Init( void ) ;                                          //RTC初始化
void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second ) ;            //设置时间
void RTC_Get_Time( void ) ;                                        //获取时间

#endif

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

#include "rtc.h"
/***************************************************
Name    :RTC_Init
Fuction    :RTC初始化
Parameter  :None
Return    :None
***************************************************/
void RTC_Init()
{
  if( BKP->DR1!=0x5050 )
  {
    RCC->APB1ENR |= 1<<28 ;                                      //使能PWR时钟
    RCC->APB1ENR |= 1<<27 ;                                      //使能BKP时钟,RTC校准在BKP相关寄存器中
    PWR->CR |= 1<<8 ;                                        //取消BKP相关寄存器写保护
    RCC->BDCR |= 1<<16 ;                                      //备份区域软复位
    RCC->BDCR &= ~( 1<<16 ) ;                                    //备份区域软复位结束
    RCC->BDCR |= 1<<0 ;                                        //开启外部低速振荡器
    while( ( RCC->BDCR&0x02 )!=0x02 ) ;                                //等待外部时钟就绪
    RCC->BDCR |= 1<<8 ;                                        //LSI作为RTC时钟
    RCC->BDCR |= 1<<15 ;                                      //RTC时钟使能
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步完成
    RTC->CRH &= ~( 7<<0 ) ;                                      //不允许中断,CRH寄存器低三位有效
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    RTC->CRL |= 1<<4 ;                                        //进入配置模式
    RTC->PRLH = 0 ;
    RTC->PRLL = 32767 ;                                        //设定分频值
    RTC->CRL &= ~( 1<<4 ) ;                                      //退出配置模式
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    BKP->DR1 = 0x5050 ;
  }
  else
  {
    while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步
      while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器操作完成
  }
}
/***************************************************
Name    :Is_Leap_Year
Function  :闰年判定
Parameter  :
      year:年份
Return    :闰年
***************************************************/
u8 Is_Leap_Year( u16 year )
{
  //必须能被4整除
  if( year%4==0 )
  {
    if( year%100==0 )
    {
      if( year%400==0 )
        return 1 ;
      else
        return 0 ;
    }
    else
      return 1 ;
  }
  else
    return 0;
}
/***************************************************
Name    :RTC_Set_Time
Fuction    :设置时间
Parameter  :
      year:年
      month:月
      date:日
      hour:时
      minute:分
      second:秒
Return    :None
***************************************************/
u8 mon_table[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ;
void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second )
{
  u16 t ;
  u32 seccount = 0 ;
  //把所有年份的秒钟相加
  for( t=1970; tAPB1ENR |= 1<<28 ;                                        //使能电源时钟
    RCC->APB1ENR |= 1<<27 ;                                        //使能备份时钟
  PWR->CR |= 1<<8 ;                                          //取消备份区写保护
  RTC->CRL |= 1<<4 ;                                          //允许配置
  RTC->CNTL = seccount&0xFFFF ;
  RTC->CNTH = seccount>>16 ;
  RTC->CRL &= ~( 1<<4 ) ;                                        //配置更新
  while( ( RTC->CRL&0x20 )!=0x20 ) ;                                  //等待RTC寄存器操作完成
  RTC_Get_Time() ;                                          //设置完之后更新一下数据
}
/***************************************************
Name    :RTC_Get_Time
Fuction    :获取时间
Parameter  :None
Return    :None
***************************************************/
RTC_Data RTC_Time;
void RTC_Get_Time()
{
  u16 daycnt=0;
  u32 timecount=0;
  u32 temp=0;
  u16 temp1=0;
  //得到计数器中的值
  timecount = RTC->CNTH ;
  timecount <<= 16 ;
  timecount += RTC->CNTL ;
  //得到天数
   temp = timecount/86400 ;
  //超过一天了
  if( daycnt!=temp )
  {    
    daycnt = temp ;
    temp1 = 1970 ;                                          //从1970年开始
    while( temp>=365 )
    {
      //闰年
      if( Is_Leap_Year( temp1 ) )
      {
        if( temp>=366 )
          temp -= 366 ;                                    //闰年的秒钟数
        else
          break ;
      }
      else
        temp -= 365;                                      //平年
      temp1 ++ ;
    }
    RTC_Time.year = temp1-2000 ;                                  //得到年份
    temp1 = 0 ;
    //超过了一个月
    while( temp>=28 )
    {
      if( Is_Leap_Year( RTC_Time.year+2000 )&&( temp1==1 ) )//当年是不是闰年/2月份
      {
        if( temp>=29 )
          temp -= 29 ;//闰年的秒钟数
        else
          break; 
      }
      else 
      {
        if( temp>=mon_table[ temp1 ] )
          temp -= mon_table[ temp1 ] ;                            //平年
        else
          break ;
      }
      temp1 ++ ;
    }
    RTC_Time.month = temp1+1 ;                                    //得到月份
    RTC_Time.date = temp+1 ;                                    //得到日期
  }
  temp = timecount%86400 ;                                      //得到秒钟数
  RTC_Time.hour = temp/3600 ;                                      //小时
  RTC_Time.minute = ( temp%3600 )/60 ;                                //分钟
  RTC_Time.second = ( temp%3600 )%60 ;                                //秒钟
}+2000;>

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

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "rtc.h"

int main()
{
  u8 Str[ 50 ] ;
  STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  RTC_Init() ;
  RTC_Set_Time( 20, 12, 10, 10, 8, 0 ) ;
  while( 1 )
  {
    RTC_Get_Time() ;
    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 ) ;
    LCD_ShowString( 10, 10, Str ) ;
    delay_ms( 500 ) ;
  }
}



声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 电子产品
    +关注

    关注

    6

    文章

    1142

    浏览量

    58182
  • 实时时钟
    +关注

    关注

    4

    文章

    239

    浏览量

    65682
  • RTC
    RTC
    +关注

    关注

    2

    文章

    527

    浏览量

    66293
收藏 人收藏

    评论

    相关推荐

    RTC实验效果

    单片机RTC
    jf_06209345
    发布于 :2022年04月03日 16:24:41

    77 第22.1讲 RTC实验-6U内部RTC详解 - 第1节

    控制器程序RTC
    充八万
    发布于 :2023年08月17日 09:33:28

    77 第22.1讲 RTC实验-6U内部RTC详解 - 第2节 #硬声创作季

    控制器程序RTC
    充八万
    发布于 :2023年08月17日 09:34:19

    77 第22.1讲 RTC实验-6U内部RTC详解 - 第3节

    控制器程序RTC
    充八万
    发布于 :2023年08月17日 09:35:09

    77 第22.1讲 RTC实验-6U内部RTC详解 - 第5节 #硬声创作季

    控制器程序RTC
    充八万
    发布于 :2023年08月17日 09:36:49

    STM32 RTC实验问题

    想使用内部晶振作为时钟源。但是rtc没工作。代码看的原子的写的代码如下:if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)//从指定的后备寄存器中读出数据
    发表于 05-04 22:01

    【连载】【星光闪电STM32F407开发板】第十二章 RTC实验

    第十二章 RTC实验12.1 实验目的本实验旨在掌握STM32的实时时钟RTC的使用,利用其测量日期时间,数据手册请参看第16章。12.2
    发表于 11-11 16:01

    为什么我进行RTC实验时LCD显示的秒钟快了10倍?

    在进行RTC实验时,我拔掉板后的电池,然后再用提供的例程烧尽去,结果发现LCD显示的秒钟快了10倍,这是为什么呢?高手们可否解释一下……
    发表于 04-04 06:35

    RTC实验屏幕只有红色的字

    刚把光盘上的第十一个实验烧写上去,发现屏幕只有红色的字,蓝色的时间没有,LED 不亮,这是板的问题,还是程序的问题了
    发表于 04-23 01:50

    RTC实验lCD显示重影

    请教原子大哥,我按照你的rtc实验,把LSE 改为LSI 了,分频改为39999; 其他都没有变化,但是LCD显示的时候这一秒和上一秒显示的时候重影这么厉害啊,基本上看不清楚了,是什么原因呢
    发表于 05-09 06:35

    RTC实验程序disp-week找不到在哪?

    RTC实验程序disp-week找不到在哪?用软件查询没有
    发表于 08-28 06:36

    如何通过串口超级终端修改RTC时间

    注意一定要下载RTC实验的例程,然后打开串口助手发送如下指令。RTC_Set(2019,12,14,21,10,30)就可以完成对RTC 的设置
    发表于 01-12 07:55

    RTC实验

    以前寫論文收集的一些資料,學習單片機、C語言的好資料!!!!
    发表于 07-08 15:08 11次下载

    STM32入门学习笔记之RTC实验(上)

    实时时钟Real TimeClock(简称RTC),实时时钟芯片是日常生活中应用最为广泛的消费类电子产品之一。它为人们提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。有些时钟芯片为了在主电源掉电时,还可以工作,需要外加电池供电。
    的头像 发表于 02-16 11:22 1376次阅读
    STM32入门学习笔记之<b class='flag-5'>RTC</b><b class='flag-5'>实验</b>(上)

    STM32入门学习笔记之RTC实验(下)

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