完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
配置RCT基本步骤
1.使能PWR和BKP外设时钟 2.使能后备寄存器访问 3.判断从指定的后备寄存器中读出数据: 如果读出数据与写入的数据相同,说明已经配置过了不需要重新配置,只要等待最近一次对RTC寄存器的写操作完成和使能RTC秒中断即可,如果读出数据与写入数据不相同,则需要重新配置。修改写入时间时一定要记得把两个0x5051修改成其他任意十六位数据。这样才可以重新修改写入时间。 4.复位备份区域 5.设置外部低速晶振(LSE),使用外设低速晶振 6.检查指定的RCC标志位设置与否,等待低速晶振就绪,这一步尤为重要, 如果晶振出现问题整个系统是不会正常运行的。如果是硬件问题不容查出来。 7.设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 8.使能RTC时钟 9.等待最近一次对RTC寄存器的写操作完成 10.等待RTC寄存器同步 (注意9、10两步很重要,每次操作RTC寄存器时都要重复一次9、10两步) 11.使能RTC秒中断 12.等待最近一次对RTC寄存器的写操作完成 13.允许配置 14.设置RTC预分频的值: 计算方式32768/(32767+1) = 1Hz 周期刚好是1秒。 15.等待最近一次对RTC寄存器的写操作完成 16.设置时间 17.退出配置模式,防止误操作 18.向指定的后备寄存器中写入用户程序数据 19.RCT中断分组设置 20.更新时间 最近在学习STM32单片机,刚好学到RTC时钟配置,使用正点原子战舰版开发平台调试的程序。好记性不如烂笔头,在博客上写一下防止以后再用的时候找不到了,也趁此机会跟广大网友分享一下,如果有侵权或者不足的地方请在评论区留言。请大家多多关照。 /************************************RTC.c文件***************************/ #include "sys.h" #include "delay.h" #include "usart.h" #include "rtc.h" _calendar_obj calendar;//时钟结构体 u32 timecount=0; 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寄存器 } //实时时钟配置 //初始化RTC时钟,同时检测时钟是否工作正常 //BKP->DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 u8 RTC_Init(void) { //检查是不是第一次配置时钟 u8 temp=0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎 { BKP_DeInit(); //复位备份区域 RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250) //检查指定的RCC标志位设置与否,等待低速晶振就绪 { temp++; delay_ms(10); } if(temp>=250)return 1; //初始化时钟失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_WaitForSynchro(); //等待RTC寄存器同步 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_EnterConfigMode(); // 允许配置 RTC_SetPrescaler(32767); //设置RTC预分频的值,计算方式32768/(32767+1) = 1Hz 周期刚好是1秒。 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_Set(2020,2,16,22,16,00); //设置时间 RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5051); //向指定的后备寄存器中写入用户程序数据 } else //系统继续计时 { RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 } RTC_NVIC_Config(); //RCT中断分组设置 RTC_Get(); //更新时间 return 0; //ok } //RTC时钟中断 //每秒触发一次 //extern u16 tcnt; void RTC_IRQHandler(void) { if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断 { RTC_Get();//更新时间 } if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断 { RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 RTC_Get(); //更新时间 printf("Alarm Time:%d-%d-%d %d:%d:%dn",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间 } RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断 RTC_WaitForLastTask(); } //判断是否是闰年函数 //月份 1 2 3 4 5 6 7 8 9 10 11 12 //闰年 31 29 31 30 31 30 31 31 30 31 30 31 //非闰年 31 28 31 30 31 30 31 31 30 31 30 31 //输入:年份 //输出:该年份是不是闰年.1,是.0,不是 u8 Is_Leap_Year(u16 year) { if(year%4==0) //必须能被4整除 { if(year%100==0) { if(year%400==0)return 1;//如果以00结尾,还要能被400整除 else return 0; }else return 1; }else return 0; } //设置时钟 //把输入的时钟转换为秒钟 //以1970年1月1日为基准 //1970~2099年为合法年份 //返回值:0,成功;其他:错误代码. //月份数据表 u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表 //平年的月份日期表 const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}; u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec) { u16 t; u32 seccount=0; if(syear<1970||syear>2099)return 1; for(t=1970;t if(Is_Leap_Year(t))seccount+=31622400; //闰年的秒钟数 else seccount+=31536000; //平年的秒钟数 } smon-=1; for(t=0;t seccount+=(u32)mon_table[t]*86400; //月份秒钟数相加 if(Is_Leap_Year(syear)&&t==1)seccount+=86400; //闰年2月份增加一天的秒钟数 } seccount+=(u32)(sday-1)*86400; //把前面日期的秒钟数相加 seccount+=(u32)hour*3600; //小时秒钟数 seccount+=(u32)min*60; //分钟秒钟数 seccount+=sec; //最后的秒钟加上去 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 RTC_SetCounter(seccount); //设置RTC计数器的值 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 return 0; } //初始化闹钟 //以1970年1月1日为基准 //1970~2099年为合法年份 //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒 //返回值:0,成功;其他:错误代码. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec) { u16 t; u32 seccount=0; if(syear<1970||syear>2099)return 1; for(t=1970;t if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数 else seccount+=31536000; //平年的秒钟数 } smon-=1; for(t=0;t seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 } seccount+=(u32)(sday-1)*86400; //把前面日期的秒钟数相加 seccount+=(u32)hour*3600; //小时秒钟数 seccount+=(u32)min*60; //分钟秒钟数 seccount+=sec; //最后的秒钟加上去 //设置时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 //上面三步是必须的! RTC_SetAlarm(seccount); RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 return 0; } //得到当前的时间 //返回值:0,成功;其他:错误代码. u8 RTC_Get(void) { static u16 daycnt=0; u32 temp=0; u16 temp1=0; timecount=RTC_GetCounter(); temp=timecount/86400; //得到天数(秒钟数对应的) if(daycnt!=temp) //超过一天了 { daycnt=temp; temp1=1970; //从1970年开始 while(temp>=365) //计算出来的天数大于等于一年的天数 { if(Is_Leap_Year(temp1))//是闰年 { if(temp>=366) { temp-=366;//闰年的秒钟数 } else { temp1++; break; } } else temp-=365; //平年 temp1++; } calendar.w_year=temp1;//得到年份 temp1=0; while(temp>=28)//超过了一个月 { if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份 { if(temp>=29) //如果天数超过29天 { temp-=29; //闰年的秒钟数 } else break; //小于29天,不到闰年3月,直接跳出。 } else { if(temp>=mon_table[temp1]) { temp-=mon_table[temp1];//平年 } else break; } temp1++; } calendar.w_month=temp1+1; //得到月份 calendar.w_date=temp+1; //得到日期 } temp=timecount%86400; //得到秒钟数 calendar.hour=temp/3600; //小时 calendar.min=(temp%3600)/60; //分钟 calendar.sec=(temp%3600)%60; //秒钟 calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期 return 0; } //获得现在是星期几 //功能描述:输入公历日期得到星期(只允许1901-2099年) //输入参数:公历年月日 //返回值:星期号 u8 RTC_Get_Week(u16 year,u8 month,u8 day) { u16 temp2; u8 yearH,yearL; yearH=year/100; yearL=year%100; // 如果为21世纪,年份数加100 if (yearH>19)yearL+=100; // 所过闰年数只算1900年之后的 temp2=yearL+yearL/4; temp2=temp2%7; temp2=temp2+day+table_week[month-1]; if (yearL%4==0&&month<3)temp2--; return(temp2%7); } /************************************RTC.h文件***************************/ #ifndef __RTC_H #define __RTC_H #include "sys.h" //时间结构体 typedef struct { vu8 hour; vu8 min; vu8 sec; //公历日月年周 vu16 w_year; vu8 w_month; vu8 w_date; vu8 week; }_calendar_obj; extern _calendar_obj calendar; //日历结构体 extern u8 const mon_table[12]; //月份日期数据表 void Disp_Time(u8 x,u8 y,u8 size);//在制定位置开始显示时间 void Disp_Week(u8 x,u8 y,u8 size,u8 lang);//在指定位置显示星期 u8 RTC_Init(void); //初始化RTC,返回0,失败;1,成功; u8 Is_Leap_Year(u16 year);//平年,闰年判断 u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec); u8 RTC_Get(void); //更新时间 u8 RTC_Get_Week(u16 year,u8 month,u8 day); u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//设置时间 #endif |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1670 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1576 浏览 1 评论
1008 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
698 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1622 浏览 2 评论
1890浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
671浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
533浏览 3评论
554浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
522浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-2 12:14 , Processed in 0.767733 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号