STM32的RTC学习笔记

一个人想着一个人 提交于 2020-01-14 14:36:47

STM32的RTC学习笔记

Mcu:STM32F103RBT6

1、RTC简介

RTC(Real Time Clock)实时时钟,是STM32片内的一个外设,这个外设使用起来跟普通定时器有一点区别,他是独立的一个定时器,并且能产生两个中断,秒中断和闹钟中断,他的时钟源可以由外部或内部驱动,由使用者选择,一些教程说RTC使用内部低速时钟(LSI)的时钟频率不准,可能跑久了以后就会出现误差。

2、RTC配置流程

1、使能RTC外设时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//RTC时钟使能(电源)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);//RTC时钟使能(备份)

2、使能备份寄存器访问

PWR_BackupAccessCmd(ENABLE);//使能备份寄存器访问

开启后才能对备份寄存器进行访问,后期可以讲数据写进备份寄存器里,以防掉电数据丢失。

3、初始化备份寄存器

BKP_DeInit();//初始化备份配置

4、时钟源选择与使能

RCC_LSICmd(ENABLE);//使能内部低速时钟

while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 );//内部低速时钟是否已开启

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//配置RTC时钟为内部低速时钟
RCC_RTCCLKCmd(ENABLE);//使能RTC时钟

因为开发板原因,我用的是内部低速时钟,时钟频率为40K,先使能低速时钟源,等待使能完毕,然后再配置它为RTC的时钟源。

5、写RTC寄存器

RTC_WaitForSynchro();//等待寄存器校准
RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数)

RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数)
Rtc_Nvic_Config();

RTC_SetPrescaler(39999);//设置预分频系数
RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数)

RTC_SetCounter(hour*3600+min*60+sec);//设置当前时间,单位为秒 
RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数) 

<RTC_WaitForSynchro>等待寄存器校准函数是用于等待RTC的计数寄存器,闹钟寄存器和预分频寄存器进行同步;
<RTC_WaitForLastTask>函数则用于,每次向RTC写入数据时候,都要等待数据写入完成后再来进行下面操作;
配置RTC中断我是用于中断判断是否计数值溢出,计数值溢出则已经计了86400个数(一天86400秒),后清0;
预分频系数配置为1Hz,则计数器每一秒计一个数,而预分频系数值为n(输入的值)+1,所以40kHz要分配成1Hz要填入数值为39999;
设置当前时间也是设置当前的计数值,我只设置时间,没有日期。

6、中断优先级

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

因为没有使用其他中断,所以中断优先级随意。

7、中断服务函数

uint16_t data = 31;(自己定义的全局变量)

void RTC_IRQHandler(void)
{
    if(RTC_GetITStatus(RTC_IT_SEC) == 1)
    {
        RTC_ClearITPendingBit(RTC_IT_SEC);//清楚中断标志位
        RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数)
        if(RTC_GetCounter() == 86399)
        {
            data++;//每过一天,日期加1,一天为86400秒
            RTC_SetCounter(0); //计数值一到64000就清零,为午夜12点
            RTC_WaitForLastTask();//等待RTC寄存器写入完成(每次向RTC寄存器写入后都要调用这个函数)
        }  
    }       
}

7、LCD屏显示函数

void RtcTime_Display(void)
{
    uint32_t Time_temp = 0;
    static uint8_t Run_Ping = 0;//闰年为1,平年为0
    static uint16_t hour = 0,min = 0,sec = 0,mon = 12,year = 20;
    uint8_t Rtc_arr[20],Counter_arr[20],Rtc_date[20];
    Time_temp = RTC_GetCounter();
	
	//判断一年是闰年还是平年:
    if(((year%4==0)&&(year%100!=0))||(year%400==0))Run_Ping = 1;
    else Run_Ping = 0;
	
	//判断一个月有30天还是31天:
    if(((mon==1)||(mon==3)||(mon==5)||(mon==7)||(mon==8)||(mon==10)||(mon==12))&&(data>31))
    {   
        data = 1;
        mon++;  
    }
    if(((mon==4)||(mon==6)||(mon==9)||(mon==11))&&(data>30))
    {   
        data = 1;
        mon++;  
    }

	//特殊月份2月做特殊处理:
    if((mon==2)&&(Run_Ping==1)&&(data>29))
    {
        data = 1;
        mon++;
    }
    else if((mon==2)&&(Run_Ping==0)&&(data>28))
    {
        data = 1;
        mon++;
    }
	//准备跨年:
    if(mon>12)
    {   
        mon = 1;
        year++;
    }
	
	//时分秒:
    hour = Time_temp/3600;
    min = Time_temp%3600/60;
    sec = Time_temp%3600%60;

	//计数值打印:RTC_GetCounter
    sprintf((char *)Counter_arr,"counter = %5d",Time_temp);
    LCD_DisplayStringLine(Line6,Counter_arr); 

	//打印日期,顺便打印润平年:
    if(Run_Ping==1)
    {
        sprintf((char *)Rtc_date," 20%2d-%2d-%2d   Run",year,mon,data);
        LCD_DisplayStringLine(Line3,Rtc_date);
    }
    else
    {
        sprintf((char *)Rtc_date," 20%2d-%2d-%2d   Ping",year,mon,data);
        LCD_DisplayStringLine(Line3,Rtc_date);    
    }
	//打印时间:
    sprintf((char *)Rtc_arr," %2d:%2d:%2d",hour,min,sec);
    LCD_DisplayStringLine(Line4,Rtc_arr);     
}

心得:

1、RTC在配置上跟普通定时器不一样,但是用法一样,用RTC做一个时钟和用一个通用定时器做一个时钟基本的逻辑是一样的,但在F429这种更高级一点的MCU里添加了月份星期的寄存器,使用起来可能更方便;
2、一定要初始化备份寄存器的配置,不然在后面的寄存器校准就会死循环卡死,因为它在一直等待校准完成,或者可以写一个延时退出;
3、每次向RTC的寄存器写入后都要等待写入完成,若不等待,有可能写入不进去,比如设置当前时间,就不是自己设置的当前时间开始跑了。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!