大家好,欢迎来到IT知识分享网。
目录
一、什么是RTC
RTC:
RTC能够持续记录当前的时间,包括年、月、日、时、分、秒等,自动计算闰年,能区分每个月的天数甚至可能包括星期几和时区信息
RTC框图:
二、如何配置RTC
1、标准实时时钟部分(万年历部分)
1.1 时钟源分类
1.2 RTC时钟源的选择
①LSE(32.768KHZ):外部低速时钟 分频=同步*异步=256*128
//通常使用 外部低速时钟有独立备份电源可以让RTC独立运行
如何配置外部低速时钟源提供给RTC?
选择外部低速时钟(备份时钟)就找到RCC备份域控制寄存器相应的位
RCC备份域控制寄存器:
使能外部低速振荡器 0位
等待外部低速振荡器就绪 1位
选择外部低速时钟 8:9位
②LSI(32KHZ):内部低速时钟 分频=同步*异步=250*128
选择内部低速时钟(备份时钟)就找到RCC备份域控制寄存器、RCC控制和状态寄存器相应的位
RCC控制和状态寄存器:
使能内低速振荡器 0位
等待内部低速振荡器就绪 1位
RCC备份域控制寄存器:
选择内部低速时钟 8:9位
1.3 精密校正
不做高精度需求是不需要此寄存器
1.4 异步7位预分频器
128分频
1.5 粗略校正
不需要
1.6 同步15位分频
默认256分频 //1HZ 1次/s
1.7 日历寄存器
设置日期时间
获取日期时间
1.8 RTC的初始化与配置
总结:
①将电源控制寄存器(PWR->CR)的DBP位写1 –>解除RTC控制器和RTC备份寄存器的保护
配置这个寄存器之前,要使能电源控制器时钟 RCC->APB1
②往RTC_WPR 中写 0xca、再写 0x53—>取消所有RTC寄存器的写保护
往RTC_WPR寄存器中随便写一个数据就会再次激活写保护
总结:
1、使能电源控制器(PWR)
2、使能备份域的访问
3、选择RTC时钟源
4、使能RTC时钟
设置日历寄存器的要求
总结:
要想改变日历寄存器的时间的值或者分频值,需要让日历进入初始化模式
(日历停止工作)
更改完以后,要想日历继续工作,需要退出初始化模式(自由模式)
0、取消写保护
1、进入初始化模式—> RTC->ISR 寄存器的INIT位写1
2、检测是否允许更新(改变)日历值位—>轮询RTC->ISR 寄存器的INITF位是否置1
3、分频—>同步、异步
4、设置日期和时间寄存器
5、退出初始化模式—> RTC->ISR 寄存器的INIT位写0
6、激活写保护
读取日历时间和日期
要想读时间和日期,要等待时间和日期同步(加载到影子寄存器)
如何等待时间和日期同步到影子寄存器
ISR寄存器中RSF位要先清零,然后等待置1,读时间或者日期值.
注意:在使用RTC寄存器之前需要进行取消写保护
1.9 程序设计
初始配置RTC:
初始化配置函数
{
//使能电源控制器的时钟
/*解除RTC控制器和备份域控制器寄存器的写保护*/
/*配置时钟源*/
//使能外部低速时钟
//等待外部低速时钟使能
//选择外部低速时钟作为RTC时钟
//使能RTC
/*解除RTC寄存器的写保护*/
//配置RTC相关寄存器
//CR
/*激活RTC寄存器的写保护*/
//设置初始时间
}
设置时间
设置时间和日期函数
{
//解除RTC寄存器的写保护
//进入日历初始化模式
//等待进入初始化模式完成
/*把十进制日期值转换成BCD码形式*/
//设置日期到DR寄存器
/*把十进制时间值转换成BCD码形式*/
//设置时间到TR寄存器
//退出日历初始化模式
//激活RTC寄存器的写保护
}
十进制Dec转BCD码:
BCD=(Dec/10)<<4 | (Dec%10)
获取时间
获取日期和时间函数
{
//解除RTC寄存器的写保护
将同步标志位清零
等待同步标志位置1
读日期寄存器的值
/*把BCD码形式转换成十进制日期值*/
将同步标志位清零
等待同步标志位置1
读时间寄存器的值
/*把BCD码形式转换成十进制时间值*/
//激活RTC寄存器的写保护
}
BCD码转十进制Dec:
Dec=(BCD>>4)*10+(BCD&0x0f)
2、闹钟部分
2.1 闹钟的初始化与配置
总结:
1、禁止闹钟
2、轮询RTC_ISR的ALRAWF(闹钟A)\ALRBWF(闹钟B)位是否置1
3、配置闹钟寄存器
4、使能闹钟
5、配置EXT控制器
6、使能闹钟中断
7、配置NVIC控制器
2.2 程序设计
设置RTC闹钟初始化函数
{
/*解除RTC寄存器写保护*/
/*闹钟初始化*/
//禁止闹钟运行
//等待更新闹钟
/*配置闹钟*/
//设置掩码
//获取日期BCD码
//使能闹钟
//激活RTC寄存器写保护
/*EXTI控制器配置*/
//系统配置控制器使能(APB2)
//检测边沿
//使能外部中断
/*NVIC控制器配置*/
//闹钟A中断使能
}
闹钟中断服务函数
闹钟中断服务函数
{
//判断EXTI触发的中断信号
{
//清除EXTI中断标志位—>触发条件:闹钟标志位出现上升沿
//清除闹钟中断标志位(此位是中断标志位)—>触发条件:到达预设的数值时便会触发
中断
//执行紧急事件
}
}
不清除EXTI中断标志位则会一直执行闹钟中断服务函数;而不清除闹钟中断标志位,则不会再次进入执行闹钟中断服务函数。为什么?首先时间/日期寄存器( RTC_TR 和 RTC_DR)与闹钟寄存器 (RTC_ALRMAR) 匹配 时,RTC的闹钟标志位由0到1(上升沿跳变),而EXTI会实时监控ISR的变化,当检测到ISR由0到1(上升沿跳变)时就会触发NVIC。进入中断后清除EXTI中断标志位(以便下次再次进入),不清除闹钟标志位还是1,这时候当下一次时间匹配时,EXTI检测不到ISR由0到1(上升沿跳变)就无法再次触发NVIC。
3、周期性自动唤醒部分
3.1 唤醒的初始化与配置
总结:
- 禁止唤醒
- 轮询RTC_ISR的WUTW是否置1
- 配置时钟
- 配置重装载值
- 使能唤醒
- 配置EXTI控制器
- 使能唤醒中断
- 清除唤醒中断标志位
- 配置NVIC控制器
3.2 程序设计
唤醒初始化函数
{
/*解除RTC寄存器写保护*/
//禁止唤醒定时器
//等待允许更新唤醒定时器
/*时钟源配置*/
//配置唤醒自动重载值
//使能唤醒定时器
/*激活RTC寄存器写保护*/
/*EXTI控制器配置*/
/*NVIC控制器配置*/
//唤醒定时器中断使能
//清除中断标志位
}
唤醒中断服务函数
{
//判断EXTI触发的中断信号
{
//清除EXTI中断标志位–>触发条件:唤醒标志位出现上升沿
//清除唤醒标志位–>触发条件:计完数后便会触发
//紧急事件
}
}
总结:
不清除EXTI中断标志位则会一直执行唤醒中断服务函数;而不清除唤醒中断标志位,则不会再次进入执行唤醒中断服务函数。为什么?首先唤醒重载值递减到0时,RTC的唤醒标志位由0到1(上升沿跳变),而EXTI会实时监控ISR的变化,当检测到ISR由0到1(上升沿跳变)时就会触发NVIC。进入中断后清除EXTI中断标志位(以便下次再次进入),如果不清除闹钟标志位还是1,这时候下一次计完数时,EXTI检测不到ISR由0到1(上升沿跳变)就无法再次触发NVIC。
注意:使能唤醒中断后,需要清除一下中断标志位,因为在唤醒初始化中当使能唤醒定时器后,计数完成,中断标志位置1。若不清除一下中断标志位,则无法触发EXTI中断。
三、具体使用RTC
需求1:利用RTC设计日历
RTC初始化函数:
/* 函数名: rtc_init 函数功能:RTC初始化 返回值:void 形参:void 函数说明: */ void rtc_init(RTC_t date_time) { /*解除RTC和相关寄存器保护*/ RCC->APB1ENR |= (1 << 28);//使能电源控制器时钟 PWR->CR |= (1 << 8);//解除RTC控制器控制 /*时钟源配置*/ RCC->BDCR |= (1 << 0);//使能外部低速振荡器 0位 while(!(RCC->BDCR & (1 << 1)));//等待外部低速振荡器就绪 1位 RCC->BDCR |= (1 << 8);//选择外部低速时钟 8:9位 RCC->BDCR |= (1 << 15);//使能RTC时钟 15位 /*解除RTC寄存器的写保护*/ RTC->WPR = 0xCA; RTC->WPR = 0x53; /*配置相关寄存器*/ //CR RTC->CR &= ~(1 << 6);//24小时制 RTC->CR &= ~(1 << 5);//影子寄存器 /*激活RTC寄存器的写保护*/ RTC->WPR = 0xff; /*设置初始时间*/ if(RTC->BKP0R != 0xff) { set_date_time(date_time); RTC->BKP0R = 0xff; } }
设置初始时间的相关内容:
RTC备份寄存器和备份电源
没有备份电源,有RTC备份寄存器:只能做到复位后,时间继续走;断电后重新上电后时间会重置
如何做到复位后时间继续走?
正常情况下,在不使用RTC备份寄存器时,复位后时间将会被重置;而在使用备份寄存器后,
在RTC初始化函数里首次执行设置初始时间的地方做个标志(相当于”到此一游”),如果下次复位后,运行到此标记时,则不会重新设置初始时间。说白了,就是利用这个标志绕过初始化重新设置时间。
如何做到断电后时间不会被重置?
需要备份电源(纽扣电池)向RTC供电
总结:
备份电源作用是:
芯片断电可以让RTC继续工作,同时备份寄存器不复位
RTC备份寄存器的作用:
防止芯片复位后,CUP重置初始时间(执行RTC初始化函数–>重新设定原来的时间)
设置时间和日期:
/* 函数名: set_date_time 函数功能:设置日期和时间 返回值:void 形参:void 函数说明: */ void set_date_time(RTC_t date_time) { //解除RTC寄存器的写保护 RTC->WPR = 0xCA; RTC->WPR = 0x53; //进入日历初始化模式 RTC->ISR |= (1 << 7); //等待进入初始化模式完成 while(!(RTC->ISR & (1 << 6))); //把十进制日期值转换成BCD码形式 //设置日期到DR寄存器 RTC->DR = in_dec_out_bcd(date_time.year-2000)<<16 | in_dec_out_bcd(date_time.week)<<13 | in_dec_out_bcd(date_time.mon)<<8 | in_dec_out_bcd(date_time.day); //把十进制时间值转换成BCD码形式 //设置时间到TR寄存器 RTC->TR = in_dec_out_bcd(date_time.hour)<<16 | in_dec_out_bcd(date_time.min )<<8 | in_dec_out_bcd(date_time.sec ); //退出日历初始化模式 RTC->ISR &= ~(1 << 7); //激活RTC寄存器的写保护 RTC->WPR = 0xff; }
十进制日期值转换成BCD码形式函数:
/* 函数名: in_dec_out_bcd 函数功能:十进制日期值转换成BCD码形式 返回值:void 形参:u8 dec 函数说明: */ u8 in_dec_out_bcd(u8 dec) { return (dec/10)<<4 | (dec%10); }
获取日期和时间函数:
/* 函数名: get_date_time 函数功能:获取日期和时间 返回值:void 形参:void 函数说明: */ RTC_t get_date_or_time(void) { u32 d_temp; u32 t_temp; RTC_t get_date_time; //解除RTC寄存器的写保护 RTC->WPR = 0xCA; RTC->WPR = 0x53; //将同步标志位清零 RTC->ISR &= ~(1 << 5); //等待同步标志位置1 while(!(RTC->ISR & (1 << 5))); //读日期寄存器的值 d_temp = RTC->DR; //把BCD码形式转换成十进制日期值 get_date_time.year = in_bcd_out_dec(d_temp>>16)+2000; get_date_time.week = in_bcd_out_dec((d_temp>>13) & 0x07); get_date_time.mon = in_bcd_out_dec(d_temp>>8& 0x1f); get_date_time.day = in_bcd_out_dec(d_temp); //将同步标志位清零 RTC->ISR &= ~(1 << 5); //等待同步标志位置1 while(!(RTC->ISR & (1 << 5))); //读时间寄存器的值 t_temp = RTC->TR; //把BCD码形式转换成十进制时间值 get_date_time.hour = in_bcd_out_dec(t_temp>>16); get_date_time.min = in_bcd_out_dec(t_temp>>8); get_date_time.sec = in_bcd_out_dec(t_temp); //激活RTC寄存器的写保护 RTC->WPR = 0xff; return get_date_time; }
需求2:利用RTC设计闹钟
设置RTC闹钟初始化函数:
/* 函数名: alr_init 函数功能:设置RTC闹钟初始化 返回值:void 形参:void 函数说明: */ RTC_t alr = {2024,9,26,4,19,41,5}; void alr_init(RTC_t alr) { //解除RTC寄存器写保护 RTC->WPR = 0xca; RTC->WPR = 0x53; /*设置闹钟*/ //禁止闹钟运行 RTC->CR &= ~(1<<8); while(!(RTC->ISR & (1 << 0)));//等待更新闹钟A //日期、时分秒比较 //RTC->ALRMAR |= ;//日期掩码 //RTC->ALRMAR |= ;//小时掩码 //RTC->ALRMAR |= ;//分钟掩码 RTC->ALRMAR &= ~(1 << 7);//秒掩码 RTC->ALRMAR &= ~(1 << 30);//日期个位 RTC->ALRMAR &= ~(1 << 22);//24小时 //获取日期BCD码 RTC->ALRMAR = in_dec_out_bcd(alr.day)<<24 | in_dec_out_bcd(alr.hour)<<16| in_dec_out_bcd(alr.min)<<8 | in_dec_out_bcd(alr.sec); //设置掩码 RTC->ALRMAR |= (1 << 31) | (1 << 23) | (1 << 15); //设置闹钟 RTC->CR |= (1 << 8);//使能闹钟A //激活RTC寄存器写保护 RTC->WPR = 0xff; /*EXTI控制器配置*/ //系统配置控制器使能(APB2) RCC->APB2ENR |= 1 << 14; //检测边沿 上升沿:EXTI->RTSR |= 1<<x 下降沿:EXTI->FTSR |= 1<<x EXTI->RTSR |= 1 << 17; //使能外部中断 EXTI->IMR |= 1<<x EXTI->IMR |= 1 << 17; /*NVIC控制器配置*/ RTC->CR |= (1 << 12);//闹钟A中断使能 u32 pri = NVIC_EncodePriority (5, 1, 1);//计算优先级编码值,设置抢占和响应的级别值 NVIC_SetPriority(RTC_Alarm_IRQn, pri);//设置具体某个中断源的优先级 NVIC_EnableIRQ(RTC_Alarm_IRQn);//中断信号响应通道使能 }
RTC闹钟中断服务函数:
/* 函数名:RTC_Alarm_IRQHandler 函数功能:RTC中断服务函数 返回值:void 形参:void 函数说明: */ void RTC_Alarm_IRQHandler(void) { //判断EXTI17触发的中断信号 if(EXTI->PR & (1 << 17)) { //清除标志位 EXTI->PR |= 1 << 17; //清除闹钟标志位 RTC->ISR &= ~(1 << 8); //紧急事件 printf("响铃l!\r\n"); } }
需求3:周期性自动唤醒获取数据
唤醒初始化函数:
/* 函数名: wuck_init 函数功能:唤醒初始化 返回值:void 形参:void 函数说明: */ void wuck_init(u16 ms) { //解除RTC寄存器写保护 RTC->WPR = 0xca; RTC->WPR = 0x53; //禁止唤醒定时器 RTC->CR &= ~(1 << 10); while(!(RTC->ISR & (1 << 2)));//允许更新唤醒定时器 /*时钟源配置*/ RCC->BDCR |= (1 << 0);//使能外部低速振荡器 0位 RCC->BDCR |= (1 << 8);//选择外部低速时钟 8:9位 RCC->BDCR |= (1 << 15);//使能RTC时钟 15位 RTC->WUTR = ms;//唤醒自动重载值 //使能唤醒定时器 RTC->CR |= (1 << 10); //激活RTC寄存器写保护 RTC->WPR = 0xff; /*EXTI控制器配置*/ //系统配置控制器使能(APB2) RCC->APB2ENR |= 1 << 14; //检测边沿 EXTI->RTSR |= 1 << 22; //使能外部中断 EXTI->IMR |= 1 << 22; /*NVIC控制器配置*/ RTC->CR |= (1 << 14);//唤醒定时器中断使能 RTC->ISR &= ~(1 << 10);//清除中断标志位 u32 pri = NVIC_EncodePriority (5, 2, 1);//计算优先级编码值,设置抢占和响应的级别值 NVIC_SetPriority(RTC_WKUP_IRQn, pri);//设置具体某个中断源的优先级 NVIC_EnableIRQ(RTC_WKUP_IRQn);//中断信号响应通道使能 }
唤醒中断服务函数:
/* 函数名:RTC_WKUP_IRQHandler 函数功能:RTC唤醒中断服务函数 返回值:void 形参:void 函数说明: */ void RTC_WKUP_IRQHandler(void) { //判断EXTI22触发的中断信号 if(EXTI->PR & (1 << 22)) { //清除标志位 EXTI->PR |= 1 << 22; //清除闹钟标志位 RTC->ISR &= ~(1 << 10); //紧急事件 printf("启动!\r\n"); } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/116023.html