RTC初始化配置
系统复位后,可通过 PWR 电源控制寄存器 (PWR_CR) 的 DBP 位保护 RTC 寄存器以防止
非正常的写访问。必须将 DBP 位置 1 才能使能 RTC 寄存器的写访问。
上电复位后,所有 RTC 寄存器均受到写保护。通过向写保护寄存器 (RTC_WPR) 写入一个
密钥来使能对 RTC 寄存器的写操作。
要解锁所有 RTC 寄存器(RTC_ISR[13:8]、 RTC_TAFCR 和 RTC_BKPxR 除外)的写保护,
需要执行以下步骤:
1. 将“0xCA”写入 RTC_WPR 寄存器。
2. 将“0x53”写入 RTC_WPR 寄存器。
写入一个错误的关键字会再次激活写保护。
保护机制不受系统复位影响。
总结:
①将电源控制寄存器(PWR->CR)的DBP位写1 //解除RTC控制器和备份寄存器的保护
配置这个寄存器之前,要使能电源控制器时钟 RCC->APB1
②往RTC_WPR 中写 0xca 再写 0x53
取消所有寄存器的写保护
往RTC_WPR寄存器中随便写一个数据就会再次激活写保护
设置日历寄存器要求
要编程包括时间格式和预分频器配置在内的初始时间和日期日历值,需按照以下顺序操作:
1. 将 RTC_ISR 寄存器中的 INIT 位置 1 以进入初始化模式。在此模式下,日历计数器将停
止工作并且其值可更新。
2、轮询查INITF 判断是否日历真的进入初始化模式 日历是否停止运行
3、设置时间和日期
4、退出初始化模式
总结:
要想改变日历寄存器的时间的值或者分频值,需要让日历进入初始化模式(日历停止工作)
更改完以后,要想日历继续工作,需要退出初始化模式(自由模式)
进入初始化模式
RTC->ISR 寄存器的INIT位写1
检测是否允许更新(改变)日历值位 INITF
设置日期和时间寄存器
退出初始化模式
RTC->ISR 寄存器的INIT位写0
设置时间和日期程序
{
//进入日历初始化模式
//等待进入初始化模式完成
//设置日期和时间
//退出日历初始化模式
}
读取日历时间和日期
要想读时间和日期,要等待时间和日期同步(加载到影子寄存器),、
如何等待时间和日期同步到影子寄存器
ISR寄存器中RSF位要先清零,然后等待置1,读时间或者日期值.
获取时间和日期
{
清零同步标志位;
等待同步标志位置1;
读取时间寄存器
清零同步标志位;
等待同步标志位置1;
读取日期寄存器;
}
寄存器
CR:
6位 0 设置时间格式 24小时
5位 0 //更新影子设置
ISR:
7位 进入初始化模式 先写1 配置完时间后在复位为0
6位 7位写1后,到用此位等到位1后才可以去编程时间
5位 同步标志,读日历寄存器的时候要看此位是否为1才可以读
PRER
使用默认值 15 256 分频
RTC 写保护寄存器 (RTC_WPR)
0xCA
0x53
TR
DR
BCD码
①什么是BCD码
19------0x19
0x19----19
②如何将用户的时间(十进制)设置到寄存器中
设置时间:把用户设置的十进制时间,转换成相应的BCD码,写入到寄存器中
③如何将寄存器的时间(BCD)给用户(十进制)
获取时间:把寄存器中的BCD码,转换成十进制形式,给到用户
//十进制转BDC码 //设置时间用
参数 : 十进制
返回值:BCD码结果
13 0x13
u8 in_dec_out_bcd(u8 dec)
{
return ((dec / 10) << 4) | (dec % 10);
}
//BCD码转十进制 //读时间使用
参数 :BCD码
返回值:十进制
0x13 13
u8 in_bcd_out_dec(u8 bcd)
{
return (bcd >> 4) * 10 + (bcd & 0x0f);
}
设置日期和时间
让日历进入初始化模式
等待等待可以改变日期和时间寄存器
将设置的十进制数据转换成BCD码
设置TR 和 DR
退出初始化模式
获取日期和时间
ISR寄存器中RSF位0
等待同步完成(等待ISR寄存器中RSF位自动变为1)
读出日期寄存器的值(BCD码)
将读出的BCD码转换成十进制形式
ISR寄存器中RSF位0
等待同步完成(等待ISR寄存器中RSF位自动变为1)
读出时间寄存器的值(BCD码)
将读出的BCD码转换成十进制形式
打印,显示
备份电源作用是:
芯片断电可以让RTC继续工作,同时备份寄存器不复位
备份寄存器的作用:
防止芯片重新上电后,CUP重置初始时间
#include "rtc.h"/***********************************************
*函数名 :RTC_init
*函数功能 :RTC初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void RTC_init(RTC_t time)
{/*解除对RTC控制器以及寄存器的写保护*///使能电源控制器时钟RCC->APB1ENR |= (1<<28);//电源控制寄存器PWR_CR DBP位写1 解除RTC控制器写保护PWR->CR |= (1<<8);//使能RTC控制器时钟 RCC备份域控制寄存器RCC->BDCR |= (1<<0); //使能外部低速时钟while(!(RCC->BDCR & (1<<1)));//等待时钟就绪RCC->BDCR |= (1<<8);//选择LSE时钟RCC->BDCR |= (1<<15);//使能RTC时钟//写入密钥解除RTC寄存器写保护RTC->WPR=0xCA;RTC->WPR=0x53;/*配置CR寄存器*/RTC->CR &=~(1<<6);//设置24小时格式RTC->CR &=~ (1<<5);//取影子寄存器里的值//操作完寄存器就要进行一次激活写保护RTC->WPR=0xff;/*设置初始时间*/// if(RTC->BKP0R !=500) //设置备份域寄存器
// {
// /*设置初始时间*/
// set_time(time);
// RTC->BKP0R = 500;
// }set_time(time);//调用设置时间函数}/***********************************************
*函数名 :in_dec_out_bcd
*函数功能 :将十进制数据转换成BCD码形式
*函数参数 :u8 dec
*函数返回值:u8
*函数描述 :设置时间时候使用
************************************************/
u8 in_dec_out_bcd(u8 dec)
{return ((dec/10)<<4) | (dec%10);
}/***********************************************
*函数名 :set_time
*函数功能 :设置时间函数
*函数参数 :RTC_t time
*函数返回值:无
*函数描述 :
************************************************/
void set_time(RTC_t time)
{u32 temp_tr=0;u32 temp_dr=0;//解除寄存器保护RTC->WPR=0xCA;RTC->WPR=0x53;//进入日历寄存器进入初始化模式 ISRRTC->ISR |= (1<<7);//等待初始化结束 也就是允许更新日历寄存器while(!(RTC->ISR & (1<<6)));//设置时间和日历(10进制转bcd码)temp_tr=(in_dec_out_bcd(time.h))<<16 | (in_dec_out_bcd(time.m))<<8 | (in_dec_out_bcd(time.s));temp_dr=(in_dec_out_bcd(time.year-2000))<<16 | (in_dec_out_bcd(time.week))<<13 | (in_dec_out_bcd(time.mon))<<8 |(in_dec_out_bcd(time.day));//设置TR和DRRTC->TR = temp_tr;RTC->DR = temp_dr;//退出日历初始化模式RTC->ISR &=~(1<<7);//激活写保护(操作完寄存器就要进行一次激活写保护)RTC->WPR=0xff; }/***********************************************
*函数名 :in_bcd_out_dec
*函数功能 :将BCD码形式数据转换成十进制
*函数参数 :u8 bcd
*函数返回值:u8
*函数描述 :获取时间使用
************************************************/
u8 in_bcd_out_dec(u8 bcd)
{return (bcd>>4)*10 + (bcd & 0x0f);
}/***********************************************
*函数名 :get_time
*函数功能 :获取时间函数
*函数参数 :无
*函数返回值:RTC_t
*函数描述 :
************************************************/
RTC_t get_time(void)
{RTC_t t;u32 temp_tr=0;u32 temp_dr=0;//解除寄存器保护RTC->WPR=0xCA;RTC->WPR=0x53; //ISR寄存器中的RSF位0(同步清零)RTC->ISR &=~(1<<5);//等待同步完成while(!(RTC->ISR & (1<<5)));//读出时间寄存器的值(bcd码)temp_tr=RTC->TR;//ISR寄存器中的RSF位0(同步清零)RTC->ISR &=~(1<<5); //等待同步完成while(!(RTC->ISR & (1<<5))); //读出日期寄存器的值(bcd码)temp_dr=RTC->DR;//获取时间数据 将读出的BCD码转10进制t.h=in_bcd_out_dec(temp_tr>>16);t.m=in_bcd_out_dec(temp_tr>>8);t.s=in_bcd_out_dec(temp_tr);//获取时间数据 将读出的BCD码转10进制t.year=in_bcd_out_dec(temp_dr>>16)+2000;t.week=in_bcd_out_dec((temp_dr>>13)&0x07);t.mon=in_bcd_out_dec((temp_dr>>8)&0x1f);t.day=in_bcd_out_dec(temp_dr);// t.year = in_bcd_out_dec(temp_dr >> 16) + 2000;
// t.week = in_bcd_out_dec((temp_dr & 0xe000) >> 13);
// t.mon = in_bcd_out_dec((temp_dr & 0x1f00) >> 8);
// t.day = in_bcd_out_dec(temp_dr>> 0);//激活写保护RTC->WPR=0xff; return t;}
设置好设置时间函数、获取时间函数后 通过定时中断可以实现1s打印一次时间