• (stm32f103学习总结)—RTC独立定时器—实时时钟实验


    一、STM32F1 RTC介绍

    1.1 RTC简介

      STM32 的实时时钟( RTC)是一个独立的定时器。 STM32 的 RTC 模 块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的 功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置是在后备区域,无论器件状态如何(运行模式、 低功耗模式或处于复位状态),只要保证后备区域供电正常,RTC便不会 停止工作,所以通常会在后备区域供电端加一个纽扣电池,即使主电源 停止供电,后备电源也会启动供电,从而保证RTC时钟不停的运行,只有 当主电源和后备纽扣电池都没有电的时,RTC才停止工作。 从 RTC 的定时器特性来说,它是一个 32 位的计数器,只能向上计 数。它的时钟来源有三种,分别为高速外部时钟的 128 分频( HSE/128 )、 低速内部时钟 LSI 以及低速外部时钟 LSE。

    1.2电源

    电池备份区域
    使用电池或其他电源连接到VBAT脚上,当VDD断电时,可以保存备份寄存器的内容和维持RTC的
    功能。
    VBAT脚也为RTC、LSE振荡器和PC13至PC15供电,这保证当主要电源被切断时RTC能继续工作。切换到VBAT供电由复位模块中的掉电复位功能控制。
    如果应用中没有使用外部电池,VBAT必须连接到VDD引脚上。
     

    1.3备份寄存器(BKP)简介

      备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。
    此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。
    复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。
      ● 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
      ● 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。
     

    1.4实时时钟(RTC) 

    RTC简介
      实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
      RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。
      系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问:(BKP中也提到过)
      ● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
      ● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。 
     

    二、功能描述

    1、概述

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

    2、复位过程

      除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
      RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。

    3、读RTC寄存器

    RTC核完全独立于RTC APB1接口。
    软件通过APB1接口访问RTC的预分频值、计数器值和闹钟值。但是,相关的可读寄存器只在与RTC与 APB1时钟进行重新同步的RTC时钟的上升沿被更新RTC标志也是如此的。这意味着,如果APB1接口曾经被关闭,而读操作又是在刚刚重新开启APB1之后,则在第一次的内部寄存器更新之前,从APB1上读出的RTC寄存器数值可能被破坏了(通常读到0)。下述几种情况下能够发生这种情形:
    ● 发生系统复位或电源复位
    ● 系统刚从待机模式唤醒(参见第4.3节:低功耗模式)。
    ● 系统刚从停机模式唤醒(参见第4.3节:低功耗模式)。
    所有以上情况中,APB1接口被禁止时(复位、无时钟或断电)RTC核仍保持运行状态。
    因此,若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置’1’。
    注:RTC的 APB1接口不受WFI和WFE等低功耗模式的影响。

    4、写RTC寄存器

    必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器。

    另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器。


    三、STM32F1 RTC配置步骤

    • 使能PWR和BKP时钟。调用函数:RCC_APB1PeriphClockCmd();
    • 使能后备寄存器访问。调用函数:PWR_BackupAccessCmd();
    • 配置RTC时钟源,使能RTC时钟。调用函数:RCC_RTCCLKConfig();RCC_RTCCLKCmd();
    • 如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);
    • 设置RTC预分频系数。调用函数:RTC_SetPrescaler();
    • 设置时间。调用函数:RTC_SetCounter();
    • 开启相关中断(如果需要)。调用函数:RTC_ITConfig();
    • 编写中断服务函数。调用函数:RTC_IRQHandler();
    • 部分操作要等待写操作完成和同步。调用函数:RTC_WaitForLastTask();RTC_WaitForSynchro();

    四、程序举例

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

    程序框架如下 :

    1)初始化RTC,设置RTC时间日期初值 (2)开启RTC的秒中断,编写RTC中断函数, (3)在RTC中断内更新时间并打印输出 (4)编写主函数

     1 #ifndef _rtc_H
     2 #define _rtc_H
     3 
     4 #include "system.h"
     5 
     6 
     7 u8 RTCx_Init(void);
     8 void RTC_GET(void);
     9 
    10 typedef struct
    11 {
    12     u8 hour;
    13     u8 min;
    14     u8 sec;
    15 }_calender;
    16 
    17 extern _calender  calender;
    18 
    19 
    20 
    21 #endif

      分析RTC_Init()函数:RTC初始化函数。

      初始化时按照之前的RTC一般步骤进行配置,这里需要注意的是,为了区分是否是第一次执行RTC_Init()函数,必须判断后配寄存器中是否写如果某个值(向BKP_DR1寄存器写入0xA0A0,写入其他的数字也可以)如果写入不用再初始化。

      为什么要区分是否执行过RTC_Init?

      如果由于 断电/ 复位/唤醒等待 等因素,程序中断但RTC时钟以及后备寄存器区域还在执行;等恢复供电重新启动程序时,这不能再对RTC时钟进行初始化,否则一直初始化,那么RTC作为时钟就没什么实际作用。

    1 if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0//(从指定的后备寄存器中读出数据)判断是否初始化过
    2 {                 
    3           //第一次进行初始化(RTC_Init)
    4   BKP_WriteBackupRegister(BKP_DR1, 0XA0A0);    //向指定的后备寄存器中写入用户程序数据
    5 }
    6 else//(已经初始化过)系统继续计时
    7 {
    8    //不是第一次进行初始化(RTC_Init)
    9 }

     代码44:使用外部低速晶振(LSE)时需要检查指定的RCC相应的标志位是否设置,等待低速晶振就绪。

     1 #include "rtc.h"
     2 #include "systick.h"
     3 #include "ustrt.h"
     4 
     5 
     6 _calender  calender;
     7 
     8 
     9 void RTC_NVIC_Config() //设置RTC中断优先级
    10 {
    11     NVIC_InitTypeDef    NVIC_InitStruct;
    12     
    13     NVIC_InitStruct.NVIC_IRQChannel=RTC_IRQn;
    14     NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
    15     NVIC_InitStruct.NVIC_IRQChannelSubPriority=3;
    16     NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE ;
    17     NVIC_Init(&NVIC_InitStruct);
    18     
    19 }    
    20 
    21 void RTC_GET() //获取 RTC 计数器的值并进行处理
    22 {
    23     u32 timedata;
    24     timedata=RTC_GetCounter();
    25     calender.hour=timedata/3600;
    26     calender.min=timedata%3600/60;
    27     calender.sec=timedata%3600%60;
    28 }
    29 
    30 //返回0:初始化失败
    31 //返回1:初始化成功
    32 u8 RTCx_Init()
    33 {
    34     u8 time;
    35     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    36     RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
    37     PWR_BackupAccessCmd(ENABLE);
    38     
    39     
    40     if(BKP_ReadBackupRegister(BKP_DR1)!=0xA0a0) //从指定的后备寄存器读数据)检查是不是第一次配置时钟
    41     {                       
    42         BKP_DeInit();    //将后备寄存器初始化
    43         RCC_LSEConfig(RCC_LSE_ON);     //将RCC_LSE时钟开启
    44         while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET && time<250) //检测LSE时钟是否开启
    45         {
    46             time++;
    47             delay_ms(10);
    48         }
    49         if(time>=250)
    50         {
    51             return 1;
    52         }
    53         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);     //配置RTC的时钟为LSE
    54         RCC_RTCCLKCmd(ENABLE);    //RTC时钟输入开启
    55         RTC_WaitForLastTask();    //等待直到RTC寄存器上的上一次写操作完成。
    56         RTC_WaitForSynchro();    //等待,直到RTC寄存器(RTC_CNT、RTC_ALR和RTC_PRL)与RTC APB时钟同步。
    57         RTC_ITConfig(RTC_IT_SEC, ENABLE);
    58         RTC_WaitForLastTask();  //等待直到RTC寄存器上的上一次写操作完成。
    59         RTC_EnterConfigMode();    // 允许配置
    60         RTC_SetPrescaler(32767); //设置 RTC 预分频的值
    61         RTC_WaitForLastTask();   //等待直到RTC寄存器上的上一次写操作完成。
    62         RTC_SetCounter(0x1111);     //设置 RTC 计数器的值 初始化时间17:34:55
    63         RTC_ExitConfigMode();    //退出 RTC 配置模式
    64         BKP_WriteBackupRegister(BKP_DR1,0xA0a0);    //向指定的后备寄存器中写入用户程序数据
    65         
    66     }
    67     else //(系统之前已经进行过相应初始化)系统继续计时
    68     {
    69         RTC_WaitForLastTask();    //等待直到RTC寄存器上的上一次写操作完成。
    70         RTC_WaitForSynchro();    //等待,直到RTC寄存器(RTC_CNT、RTC_ALR和RTC_PRL)与RTC APB时钟同步。
    71         RTC_ITConfig(RTC_IT_SEC, ENABLE);    //使能或者失能指定的 RTC 中断
    72     }
    73     
    74     RTC_NVIC_Config(); //RCT中断优先级别设置    
    75     RTC_GET(); //获取 RTC 计数器的值
    76     return 0;
    77 }
    78 
    79 void RTC_IRQHandler(void) //RTC中断函数
    80 {
    81     if(RTC_GetITStatus(RTC_IT_SEC)!=0) //检查指定的 RTC 中断发生与否(秒中断)
    82     {
    83         RTC_GET();
    84         printf("RTC_Time:%d:%d:%d
    ",calender.hour,calender.min,calender.sec);
    85     }
    86     RTC_ClearITPendingBit(RTC_IT_SEC); //清除 RTC 的中断待处理位
    87 }

     

     
     1 #include "system.h"
     2 #include "led.h"
     3 #include "systick.h"
     4 #include "ustrt.h"
     5 #include "rtc.h"
     6 
     7 int main()
     8 {
     9     u8 i=0;
    10 
    11     
    12     SysTick_Init(72);
    13     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    14     LED_Init();
    15     ustrt_Init(9600);
    16     RTCx_Init();
    17     
    18     while(1)
    19     {
    20     
    21         i++;
    22         if(i%20==0)
    23         {
    24             led1=!led1;
    25         }
    26         delay_ms(10);    
    27     }
    28 }

     

     
     
  • 相关阅读:
    sklearn1.1.5.弹性网
    Win10 1903过TP的双机调试
    sklearn1.1.3.Lasso
    sklearn的持续更新1.1 广义线性回归模型1.1.1.
    X32进程注入x64DLL到x64进程
    java——接口作为成员变量类型
    java——API——Scanner类
    java——类作为成员变量类型
    java——接口作为方法的参数和返回值
    java——API——匿名对象
  • 原文地址:https://www.cnblogs.com/zhj868/p/12712575.html
Copyright © 2020-2023  润新知