https://static.assets-stash.eet-china.com/album/old-resources/2009/11/24/b725abfb-9aee-43ba-9c3b-3b95620e84eb.rar" target=_blank>实质:RTC是一个独立的计数器,其相应的寄存器是在备份区所以掉电也不会丢数据。设置好RTC后就用秒中断来读取器寄存器的值。再换算为年月日就行了。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
STM32的RTC实际是一个独立的定时器。
下面将介绍如何使用RTC。
我们将头一次牵扯到振源的问题。
首先介绍一下STM32使用的各种振源。
有三种
HSE: 外置晶振
HSI: 内置RC振荡
LSE: 外置RTC振荡(32768居多)
APB1 和 APB2 是经过PLL以后的振荡源。
STM32启动,首先使用的HSI振荡,在确认HSE振荡可用的情况下,才可以转而使用HSE,
当HSE出现问题,STM32可自动切换回HSI振荡,维持工作。
LSE振荡则是专门供RTC使用。
LSE晶振需要特别注意。
STM32非常奇怪,要求使用 6p负载的晶振,
市面买到的时钟晶振,绝大多是是12.5pF的
算是一个不小的bug,
大家做相关开发的时候,要留神。
要买6pF的晶振,配10pF的谐振电容。
由此,马七怀念一下AVR单片机。不用谐振电容都跑的飞,当然是Mega系列。
下面介绍RTC驱动过程。
第一件事情,喂时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR, ENABLE);
注意,喂的是什么?不是RTC,是电源管理和BKP备份器的时钟。用于备份模式下。
即系统掉电了,BKP和RTC还能继续工作,RTC继续计时。
那么RTC的时钟呢?前面提到,RTC的时钟,一般用LSE。
第二件事情,初始化RTC
// RTC config
void RTC_configuration()
{
//Open the BKP
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
//RTC use the LSE Clock
RCC_LSEConfig(RCC_LSE_ON); //RCC打开了LSE时钟
//Wait LSE Ready
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET); //等待LSE就绪,一般来说,如果谐振不对,就会死在这里。实
际代码请慎重
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //RTC使用时钟,可以使用LSE,也可以使用HSI,也可以使用HSE/128
RCC_RTCCLKCmd(ENABLE); //RTC的时钟开启
RTC_WaitForSynchro(); //RTC等待同步,
RTC_WaitForLastTask(); //这个代码在RTC中常常出现,类似于等待就绪的含义
// Interrupt Each Second
RTC_ITConfig(RTC_IT_SEC, ENABLE); //RTC开中断,RTC中断有三种,秒中断,闹钟中断,溢出中断,很明显他们的作用。秒中断用于即时操作,闹钟中断用于关闭或者唤醒,溢出中断的话,用于复位RTC
RTC_WaitForLastTask();//
RTC_SetPrescaler(32767); //RTC预分频,32768HZ,分为一秒一个振荡,RTC period = RTCCLK/RTC_PR = (32.768
KHz)/(32767+1)
RTC_WaitForLastTask(); //等待同步
}
这样,RTC就启动了。
第三步读秒
通过 RTC_GetCounter() 这个函数。读到计数器的值。
既然 一秒增一个。
很容易就可以从 计数器的值,算出确切的时间值。
对于这种时间分量复杂的,我习惯用结构体定义
typedef struct
{
unsigned char Sec;
unsigned char Min;
unsigned char Hour;
unsigned char Day;
unsigned char Month;
unsigned char Year;
}Time_Struct;
// translate seconds to YY::MM:<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /> D::HH::MM::SS
Time_Struct read_RTC_time()
{
unsigned long Time_Value;
Time_Struct TimeStruct;
Time_Value = RTC_GetCounter();
TimeStruct.Year = Time_Value/(12*30*24*3600);
TimeStruct.Month = Time_Value/(30*24*3600) - TimeStruct.Year*12;
TimeStruct.Day = Time_Value/(24*3600) - TimeStruct.Year*12*30 - TimeStruct.Month*30;
TimeStruct.Hour = Time_Value/3600 - TimeStruct.Year*12*30*24 - TimeStruct.Month*30*24 - TimeStruct.Day*24;
TimeStruct.Min = Time_Value/60 - TimeStruct.Year*12*30*24*60 - TimeStruct.Month*30*24*60 -
TimeStruct.Day*24*60 - TimeStruct.Hour*60;
TimeStruct.Sec = Time_Value - TimeStruct.Year*12*30*24*60*60 - TimeStruct.Month*30*24*60*60 -
TimeStruct.Day*24*60*60 - TimeStruct.Hour*60*60 -TimeStruct.Min*60;
return TimeStruct;
}
当然,也可以在任意时候设置这个时间,手工修改Counter即可。相关函数在工程文件rtc.c当中。
文章评论(0条评论)
登录后参与讨论