学习笔记:RTC时钟
1.什么是RTC
(1) RTC是个独立的定时器。RTC拥有一个连续计数的计数器。
(2)注意:RTC模块和时钟配置系统(RCC_BDCR寄存器)工作在后备区域,系统断电或者复位不会影响RTC的设置和事件,所以可以利用此特性来制作万年历。系统复位后,自动禁止访问后备寄存器和RTC,防止意外操作。
##2. RTC时钟源
(1)HSE时钟除以128
(2)LSE振荡器时钟:外部低速时钟(一般为32.767khz)
(3)LSI振荡器时钟:一般为(40khz)
3.RTC中断
(1)秒中断
(2)闹钟中断
(3)溢出中断
4.RTC计数器
32位可编程计数器,4,294,967,296位。
5.RTC工作原理
a.分频区
b.计数比较区
c.各环节作用
RTC_PRL:在里面写入分频数据,将RTC_CLK分频
RTC_DIV:没经过一个周期,DIV减一。
TR_CLK:RTC_CLK经过RTC_PRL分频后的时钟周期
RTC_CNT:受到TR_CLK控制的32位计数器
RTC_ALR:可软件写入数据,当RTC_CNT与ALR数据相同时,触发闹钟中断。
注意
RTC内核独立与APB1接口,通过软件访问RTC相关寄存器时,只有在APB1时钟进行重新同步的RTC时钟的上升沿被更新。软件配置必须先等待寄存器同步标志位被1才可以读。
6.BKP
引用自STM32中文参考手册:
备份寄存器(BKP)
小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和
STM32F103xx微控制器。
中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和
STM32F103xx微控制器。
大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控
制器。
互联型产品是指STM32F105xx和STM32F107xx微控制器。
除非特别说明,本章描述的模块适用于整个STM32F10xxx微控制器系列。
5.1 BKP简介
备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域
里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或
电源复位时,他们也不会被复位。
此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。
复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操
作。执行以下操作可以使能对备份寄存器和RTC的访问。
● 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
● 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。
7.配置RTC寄存器
1.查询RTOFF位,直到变1
2.置CNF为1,开始配置
3.开始操作
4.退出配置模式(清除标志位)
5.等待写操作完成
8.实例:用RTC配置一个闹钟
一):分析
1.RTC初始化
(1).初始化BKP时钟:
BKP时钟,pwr时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
(2).初始化RTC时钟
根据开发板选择相应时钟,一般的可选择lse时钟或者lsi时钟,在选择LSE时钟时,要先启动LSE时钟在RTC选择LSE时钟
example 引用LSI时钟(大约40khz)
BKP_DeInit();
RCC_LSICmd(ENABLE);//使能LSI
delay_ms(100);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//RTC时钟选择LSI
RCC_RTCCLKCmd(ENABLE);
(3)开启相应中断
a.开起中断要操作相应的RTC寄存器,所以要先等待上一次写完成
RTC_WaitForLastTask();
RTC_WaitForSynchro();
FOR EXAMPLE:开启秒中断和闹钟中断
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC,ENABLE);//秒中断
RTC_WaitForLastTask();
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_ALR,ENABLE);//闹钟中断
RTC_WaitForLastTask();
(4)配置分频值
RTC_SetPrescaler(40000);//1hz
(5)配置计数器的初始值
本例封装了一个函数来配置初始值
RTC_WaitForLastTask();
RTC_SETTIME(value);//³õʼ»¯¼ÆÊýÆ÷Öµ
RTC_ExitConfigMode();
******/
void RTC_SETTIME(u32 CounterValue)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(CounterValue);
RTC_WaitForLastTask();
}
(6)init函数结束,但是还要配置中断函数
a. 中断分组
static void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTCÈ«¾ÖÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //ÏÈÕ¼ÓÅÏȼ¶1λ,´ÓÓÅÏȼ¶3λ
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //ÏÈÕ¼ÓÅÏȼ¶0λ,´ÓÓÅÏȼ¶4λ
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄܸÃͨµÀÖжÏ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝNVIC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèNVIC¼Ä´æÆ÷
}
b.中断服务函数
(注意:中断服务函数是定义好的不可更改名称)
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC)!=RESET)//秒中断
{
RTC_GETTIME();
}
if(RTC_GetITStatus(RTC_IT_ALR)==SET)//闹钟中断
{
RTC_ClearITPendingBit(RTC_IT_ALR);
ALARM();
}
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_WaitForLastTask();
}
c.闹钟函数:ALARM();
自己定义的函数,放在了beep.c中,作用就是让闹钟到时间后蜂鸣器嚎叫
void ALARM(void)
{
beep_con(1);
delay_ms(1000);
beep_con(0);
}
(7)闹钟配置
因为要写一个闹钟,所以要先配置相应寄存器
void RTC_SERALRM(u32 CounterValue)//ÄÖÖÓ
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetAlarm(CounterValue);
RTC_WaitForLastTask();
}
闹钟配置和时间初始化差不多,都要开启PWR和BKP时钟,然后设置值(u32型)然后等待写结束
(8)获取时间函数
我们要将时间显示在lcd屏幕上,做一个数据可视化处理,所以要将计数器中的值读出,并显示,因此定义了一个结构体
typedef struct
{
vu8 hour;
vu8 min;
vu8 sec;
}_calendar_obj;
extern _calendar_obj calendar;
然后通过获取计数器值经过计算赋予结构体值显示在LCD屏幕上
void RTC_GETTIME(void)
{
u32 time=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
time=RTC_GetCounter();//获取计数器值
calendar.hour=time/3600;
calendar.min=(time%3600)/60;
calendar.sec=(time%3600)%60;
}
(9)主函数
#include "stm32f10x.h"
#include "lcd.h"
#include "key.h"
#include "stdio.h"
#include "beep.h"
#include "delay.h"
#include "rtc.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
void xianshisec(u8 val)
{
uint8_t temp[20];
sprintf(temp,"sec=%d",val);
LCD_DisplayStringLine(Line0,temp);
}
void xianshimin(u8 val)
{
uint8_t temp[20];
sprintf(temp,"min=%d",val);
LCD_DisplayStringLine(Line1,temp);
}
void xianshihour(u8 val)
{
uint8_t temp[20];
sprintf(temp,"hour=%d",val);
LCD_DisplayStringLine(Line2,temp);
}
//Main Body
int main(void)
{
float num=0;
int keya=0;
u8 t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
beep_init();
delay_init();
RTC_INIT(0x00000000);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
key_inite();
LCD_Clear(White);
LCD_SetBackColor(White);
Delay_Ms(1000);
LCD_SetTextColor(Black);
Delay_Ms(1000);
RTC_SERALRM(0x00000005);
while(1)
{
if(t!=calendar.sec)
{
t=calendar.sec;
xianshisec(calendar.sec);
xianshimin(calendar.min);
xianshihour(calendar.hour);
}
delay_ms(10);
}
return 0;
}
//
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}