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

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

一、概述

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

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

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

2345_image_file_copy_164.jpg

二、 特性

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

两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。

● 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。

● 参考时钟检测:可使用更加精确的第二时钟源(50 Hz 或 60 Hz)来提高日历的精确度。

● 利用亚秒级移位特性与外部时钟实现精确同步。

● 可屏蔽中断/事件:

— 闹钟 A

— 闹钟 B

— 唤醒中断

— 时间戳

— 入侵检测

● 数字校准电路(周期性计数器调整)

— 精度为 5 ppm

— 精度为 0.95 ppm,在数秒钟的校准窗口中获得

● 用于事件保存的时间戳功能( 1 个事件)

● 入侵检测:

— 2 个带可配置过滤器和内部上拉的入侵事件

● 20 个备份寄存器( 80 字节)。发生入侵检测时间时,可以复位备份寄存器。

三、RTC的时钟

  LSE:外部低速时钟

2345_image_file_copy_165.jpg

初始化配置

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

2345_image_file_copy_166.jpg

日历配置

2345_image_file_copy_167.jpg

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

复位RTC

2345_image_file_copy_168.jpg

同步RTC

2345_image_file_copy_169.jpg

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

RTC初始化步骤

1、选择时钟源

2345_image_file_copy_170.jpg

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

2345_image_file_copy_171.jpg

这一步的代码

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

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

2345_image_file_copy_172.jpg

2345_image_file_copy_173.jpg

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

2345_image_file_copy_174.jpg

2、使能PWR时钟

使能PWR的电源接口时钟,

2345_image_file_copy_175.jpg

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

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

2345_image_file_copy_176.jpg

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

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

2345_image_file_copy_177.jpg

4、初始化RTC结构体

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

rtc.c

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

5、设置时间

2345_image_file_copy_178.jpg

  RTC_TimeTypeInitStructure.RTC_Hours=hour;
  RTC_TimeTypeInitStructure.RTC_Minutes=min;
  RTC_TimeTypeInitStructure.RTC_Seconds=sec;
  RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;

6、时钟日期

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

2345_image_file_copy_179.jpg

设置日期

  RTC_DateTypeInitStructure.RTC_Date=date;
  RTC_DateTypeInitStructure.RTC_Month=month;
  RTC_DateTypeInitStructure.RTC_WeekDay=week;
  RTC_DateTypeInitStructure.RTC_Year=year;

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

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

完整代码

rtc.c

#include "rtc.h" 
#include "beep.h"
#include "lcd.h"  
#include "stdio.h"
u32 rct_AlarmA_flag;
RTC_TimeTypeDef RTC_TimeTypeInitStructure;
RTC_DateTypeDef RTC_DateTypeInitStructure;
RTC_AlarmTypeDef RTC_AlarmStruct;
//RTC时间设置函数
//hour,min,sec:时,分,秒设定值
//ampm:@RTC_AM_PM_Definitions:RTC_H12_AM/RTC_H12_PM
//返回值:SUCEE(1),成功;ERROR(0),进入初始化模式失败 
void rtc_SetTimeData(u8 hour,u8 min,u8 sec,u8 year,
  u8 month,u8 date,u8 week)
{
  RTC_TimeTypeInitStructure.RTC_Hours=hour;
  RTC_TimeTypeInitStructure.RTC_Minutes=min;
  RTC_TimeTypeInitStructure.RTC_Seconds=sec;
  RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
  RTC_DateTypeInitStructure.RTC_Date=date;
  RTC_DateTypeInitStructure.RTC_Month=month;
  RTC_DateTypeInitStructure.RTC_WeekDay=week;
  RTC_DateTypeInitStructure.RTC_Year=year;
 RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
}
void RTC_GetTimeDate(void)
{
   static u8 temp=0;
   RTC_GetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
   RTC_GetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
  if(temp !=RTC_TimeTypeInitStructure.RTC_Seconds)
  {
    temp=RTC_TimeTypeInitStructure.RTC_Seconds;
    printf("%d:%d:%d\r\n",RTC_TimeTypeInitStructure.RTC_Hours,RTC_TimeTypeInitStructure.RTC_Minutes,RTC_TimeTypeInitStructure.RTC_Seconds);
  }
}
void RTC_Set_AlarmA(u8 week,u8 hour,u8 min,u8 sec)
{
  NVIC_InitTypeDef NVIC_InitStruct;
  EXTI_InitTypeDef EXTI_InitStruct;
  RTC_AlarmCmd(RTC_Alarm_A, DISABLE);//关闭闹钟A
  RTC_TimeTypeInitStructure.RTC_Hours=hour;
  RTC_TimeTypeInitStructure.RTC_Minutes=min;
  RTC_TimeTypeInitStructure.RTC_Seconds=sec;
  RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  RTC_AlarmStruct.RTC_AlarmDateWeekDay=week;
  RTC_AlarmStruct.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;
  RTC_AlarmStruct.RTC_AlarmMask=RTC_AlarmMask_None; 
  RTC_AlarmStruct.RTC_AlarmTime=RTC_TimeTypeInitStructure;
  RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A,&RTC_AlarmStruct);
  EXTI_InitStruct.EXTI_Line = EXTI_Line17;//中断线号0
  EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断线使能
  EXTI_InitStruct.EXTI_Mode   = EXTI_Mode_Interrupt;//中断模式
  EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
  EXTI_Init(&EXTI_InitStruct);
  NVIC_InitStruct.NVIC_IRQChannel =  RTC_Alarm_IRQn ;//中断源
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能中断
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;//响应优先级
  NVIC_Init(&NVIC_InitStruct);
  RTC_ITConfig( RTC_IT_ALRA, ENABLE);//S使能闹钟A中断
  RTC_AlarmCmd(RTC_Alarm_A, ENABLE);//开启闹钟A
}
void RTC_Alarm_IRQHandler (void)
{
  if(RTC_GetFlagStatus(RTC_FLAG_ALRAF))
  {
    rct_AlarmA_flag=1;
    RTC_ClearITPendingBit(RTC_IT_ALRA);
    EXTI_ClearITPendingBit( EXTI_Line17);
  }
  else if(RTC_GetFlagStatus(RTC_FLAG_ALRBF ))
  {
    RTC_ClearITPendingBit(RTC_IT_ALRB);
    EXTI_ClearITPendingBit( EXTI_Line17);
  }
}
void RTC_Set_AlarmB(u8 week,u8 hour,u8 min,u8 sec)
{
  NVIC_InitTypeDef NVIC_InitStruct;
  EXTI_InitTypeDef EXTI_InitStruct;
  RTC_AlarmCmd(RTC_Alarm_B, DISABLE);//关闭闹钟B
  RTC_TimeTypeInitStructure.RTC_Hours=hour;
  RTC_TimeTypeInitStructure.RTC_Minutes=min;
  RTC_TimeTypeInitStructure.RTC_Seconds=sec;
  RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  RTC_AlarmStruct.RTC_AlarmDateWeekDay=week;
  RTC_AlarmStruct.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;
  RTC_AlarmStruct.RTC_AlarmMask=RTC_AlarmMask_None; 
  RTC_AlarmStruct.RTC_AlarmTime=RTC_TimeTypeInitStructure;
  RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B,&RTC_AlarmStruct);
  EXTI_InitStruct.EXTI_Line = EXTI_Line17;//中断线号0
  EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断线使能
  EXTI_InitStruct.EXTI_Mode   = EXTI_Mode_Interrupt;//中断模式
  EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
  EXTI_Init(&EXTI_InitStruct);
  NVIC_InitStruct.NVIC_IRQChannel =  RTC_Alarm_IRQn ;//中断源
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能中断
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;//响应优先级
  NVIC_Init(&NVIC_InitStruct);
  RTC_ITConfig( RTC_IT_ALRB, ENABLE);//S使能闹钟A中断
  RTC_AlarmCmd(RTC_Alarm_B, ENABLE);//开启闹钟A
}
void Rtc_Lcd_Display(void)
{
  char hour[10];
  char min[10];
  char sec[10];
   RTC_GetTimeDate();
  sprintf(hour,"%.2d",RTC_TimeTypeInitStructure.RTC_Hours);
  sprintf(min,"%.2d",RTC_TimeTypeInitStructure.RTC_Minutes);
  sprintf(sec,"%.2d",RTC_TimeTypeInitStructure.RTC_Seconds);
  LCD_Show_Str_ChineseorChar(50,70,(u8 *)hour,BLACK,WHITE);
  LCD_Show_Str_ChineseorChar(80,70,(u8 *)min,BLACK,WHITE);
  LCD_Show_Str_ChineseorChar(110,70,(u8 *)sec,BLACK,WHITE);
}
void rtc_init()
{
  RTC_InitTypeDef RTC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开电源
  PWR_BackupAccessCmd(ENABLE ); //使能后备寄存器访问
  if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0X11)
  {
    RCC_LSEConfig(RCC_LSE_ON);//LSE开启
    while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));//等待lse稳定
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//设置LSE为RTC时钟
    RCC_RTCCLKCmd(ENABLE);
    rtc_SetTimeData(11,22,54,22,4,26,2);
    RTC_WriteBackupRegister(RTC_BKP_DR0,0X11);
  }
   RTC_Set_AlarmA(2,11,38,20);
   RTC_Set_AlarmB(2,16,21,0);
}

rtc.h

#ifndef __RTC_DECLS
#define __RTC_DECLS
#include "stm32f4xx.h" 
#include "io_bit.h"
 extern u32 rct_AlarmA_flag;
void beep_init(void);
void rtc_init(void);
void RTC_GetTimeDate(void);
void Rtc_Lcd_Display(void);
#endif
相关文章
|
7月前
|
监控 前端开发
STM32F103标准外设库——RCC时钟(六)
STM32F103标准外设库——RCC时钟(六)
382 0
STM32F103标准外设库——RCC时钟(六)
小巴陪你搞技术-STM32驱动1602时钟
小巴陪你搞技术-STM32驱动1602时钟
|
5月前
|
前端开发 安全
stm32f407探索者开发板(十一)——SystemInit时钟系统初始化剖析
stm32f407探索者开发板(十一)——SystemInit时钟系统初始化剖析
184 0
|
5月前
stm32f407探索者开发板(十)——时钟系统精讲
stm32f407探索者开发板(十)——时钟系统精讲
203 0
|
6月前
|
芯片
【STM32】详解RTC实时时钟的概念和配置&示例代码
【STM32】详解RTC实时时钟的概念和配置&示例代码
|
7月前
STM32CubeMX配置时钟无法使用高速外部时钟HSE
STM32CubeMX配置时钟无法使用高速外部时钟HSE
286 0
|
7月前
|
存储 Unix C语言
STM32--RTC实时时钟
STM32--RTC实时时钟
169 0
STM32CubeMX时钟树(72MHZ主频配置)
STM32CubeMX时钟树(72MHZ主频配置)
483 0
|
7月前
|
芯片
嵌入式系统中STM32时钟系统详解
嵌入式系统中STM32时钟系统详解
100 0