嵌入式 > 嵌入式开发 > 详情

初始化STM32的RTC

发布时间:2024-05-27 发布时间:
|
RTC嘛 就跟DS1302 差不多吧...当然了可分频又有32位的计数器...报警、秒、溢出中断.....等等。RTC在APB1总线上....

要使用 RTC,一般来说也顺带地使用上后备寄存器—这是因为RTC 是一个简单的秒中断
定时器,年月日时分秒的信息必须要找个地方能掉电保存才有意义.STM32 的备份寄存器(BKP)是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。 此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。 复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作它是用后备电池供电的,只要配置好后,即使系统关电,32768 的
晶振和后备寄存器的数据也会得以维持.而且RTC的计数器是会继续秒递增的.那么要配
置RTC,就必须开放以下东西:
#include "stm32f10x_bkp.h" 这个是后备寄存器
#include "stm32f10x_pwr.h" 电源管理
#include "stm32f10x_rtc.h" RTC库

开始吧.....先是中断

void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/*RTC*/
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//RTC全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

然后设置 RTC

#include "STM32Lib\\stm32f10x.h"
#include "hal.h"


static u8 RTC_Blank=0;
/***********************************
**函数名:RTC_Configuration
**功能:RTC设置
**注意事项:要根据是否是第一次设置,才进入下面的RTC设定
判断是否第一次设置,只需要判断RTC后备寄存器1的值是否为事先写入的0XA5A5,如果不是,则
RTC是第一次上电,需要初始化RTC,并把实际时间转化为RTC计数值,这里没有设置实际时间,只是简单地初始化了RTC
************************************/
void RTC_Configuration(void)
{

/*PWR时钟(电源控制)与BKP时钟(RTC后备寄存器)使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

/*使能RTC和后备寄存器访问*/
PWR_BackupAccessCmd(ENABLE);

/*从指定的后备寄存器(BKP_DR1)中读出数据*/
if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
/* 将外设BKP的全部寄存器重设为缺省值 */
BKP_DeInit();

/*启用 LSE(外部低速晶振)*/
RCC_LSEConfig(RCC_LSE_ON);
/*等待外部晶振震荡 需要等待比较长的时间*/
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

/*使用外部晶振32.768K作为RTC时钟*/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//允许RTC
RCC_RTCCLKCmd(ENABLE);
//等待RTC寄存器同步 原因下文说明
RTC_WaitForSynchro();
//等待最近一次对RTC寄存器的写操作完成
RTC_WaitForLastTask();

//允许RTC的秒中断(还有闹钟中断和溢出中断可设置)
RTC_ITConfig(RTC_IT_SEC, ENABLE);
//又是等待上一次对RTC寄存器的写操作完成
RTC_WaitForLastTask();
//32768晶振预分频值是32767,不过一般来说晶振都不那么准
RTC_SetPrescaler(32776);//如果需要校准晶振,可修改此分频值
RTC_WaitForLastTask();

//写入RTC后备寄存器1 0xa5a5
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
RTC_Blank=1;/*这个标志代表RTC是没有预设的(或者说是没有上纽扣电池) 用串口呀啥的输出来。*/

}
//如果RTC已经设置
else
{
//等待RTC与APB同步
RTC_WaitForSynchro();
RTC_WaitForLastTask();

//使能秒中断
RTC_ITConfig(RTC_IT_SEC, ENABLE);//这句可以放到前面吗?
RTC_WaitForLastTask();//又等....
}

//清除标志
RCC_ClearFlag();
}

为啥要不停的等呢??

RTC核完全独立于RTC APB1接口。 软件通过APB1接口访问RTC的预分频值、计数器值和闹钟值。但是,相关的可读寄存器只在与RTC APB1时钟进行重新同步的RTC时钟的上升沿被更新。RTC标志也是如此的。 这意味着,如果APB1接口曾经被关闭,而读操作又是在刚刚重新开启APB1之后,则在第一次的内部寄存器更新之前,从APB1上读出的RTC寄存器数值可能被破坏了(通常读到0)。

因此,若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置’1’。

注:RTC的 APB1接口不受WFI和WFE等低功耗模式的影响。

/*******************************************************************************
* Function Name : RTC_IRQHandler RTC中断
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
extern volatile bool Sec;//1S标志
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)//RTC发生了秒中断(也有可能是溢出或者闹钟中断)

/*RTC_IT_OW溢出中断/RTC_IT_ALR闹钟中断/RTC_IT_SEC秒中断*/
{
RTC_ClearITPendingBit(RTC_IT_SEC);
Sec=TRUE;

//以免RTC计数溢出,这里限制了RTC计数值的大小.0x0001517f实际就是一天的秒数
if(RTC_GetCounter() >= 0x0001517f)
{
RTC_SetCounter(0x0);

RTC_WaitForLastTask();
}
}
}

#include"STM32Lib\\stm32f10x.h"
#include"hal.h"

volatilebool Sec=FALSE;

int main(void)
{
ChipHalInit();//片内硬件初始化
ChipOutHalInit();//片外硬件初始化

TestRtc();//测试RTC
for(;;)
{
if(Sec==TRUE)
{
Sec=FALSE;
GPIOA->ODR^=GPIO_Pin_8;//闪灯
}
}
}

最简单 最基层的CRT写好了..........其实还有好多很酷的功能 比如是否掉电重启 是否是SeSET 复位 等 应该在CRT前 都检测好........



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
485总线升级成CAN总线