完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护 RTC 的简化框图: RTC 由两个主要部分组成(见上图),第一部分(APB1 接口)用来和 APB1 总线相连。此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总线时钟驱动,用来与 APB1 总线连接。另一部分(RTC 核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是 RTC 的预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个TR_CLK 周期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程计数器RTC_CNT),可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。RTC 还有一个闹钟寄存器 RTC_ALR,用于产生闹钟。系统时间按 TR_CLK 周期累加并与 136年的计算,取32位的最大值: ffffffff(十六进制) / 3600 (十进制,一小时的秒数) / 24 (一天24小时) / 365 (一年按照365天计算) = 136 年 ffffffff(十六进制) = 4294967295(十进制) 回归到本次文章的重点吧,代码讲解,寄存器部分,各位自己去了解吧,开始使用的时候,其实可以直接套模板用着先,有时间了自己在深入了解寄存器就行(只讲初始化部分,代码是原子的): 下面的代码是RTC时钟的初始化部分,以及中断部分: 我想讲解的是,如何去实现时间计算部分,在下面: //RTC时钟中断 //每秒触发一次 void RTC_IRQHandler(void) { if(RTC-》CRL&0x0001)//秒钟中断 { RTC_Get();//更新时间 //printf(“sec:%drn”,calendar.sec); } if(RTC-》CRL&0x0002)//闹钟中断 { RTC-》CRL&=~(0x0002); //清闹钟中断 //printf(“Alarm!n”); } RTC-》CRL&=0X0FFA; //清除溢出,秒钟中断标志 while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成 } //实时时钟配置 //初始化RTC时钟,同时检测时钟是否工作正常 //BKP-》DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 u8 RTC_Init(void) { //检查是不是第一次配置时钟 u8 temp=0; if(BKP-》DR1!=0X5050)//第一次配置 { RCC-》APB1ENR|=1《《28; //使能电源时钟 RCC-》APB1ENR|=1《《27; //使能备份时钟 PWR-》CR|=1《《8; //取消备份区写保护 RCC-》BDCR|=1《《16; //备份区域软复位 RCC-》BDCR&=~(1《《16); //备份区域软复位结束 RCC-》BDCR|=1《《0; //开启外部低速振荡器 while((!(RCC-》BDCR&0X02))&&temp《250)//等待外部时钟就绪 { temp++; delay_ms(10); }; if(temp》=250)return 1;//初始化时钟失败,晶振有问题 RCC-》BDCR|=1《《8; //LSI作为RTC时钟 RCC-》BDCR|=1《《15;//RTC时钟使能 while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成 while(!(RTC-》CRL&(1《《3)));//等待RTC寄存器同步 RTC-》CRH|=0X01; //允许秒中断 while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成 RTC-》CRL|=1《《4; //允许配置 RTC-》PRLH=0X0000; RTC-》PRLL=32767; //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767 RTC_Set(2014,3,8,22,10,55); //设置时间 RTC-》CRL&=~(1《《4); //配置更新 while(!(RTC-》CRL&(1《《5))); //等待RTC寄存器操作完成 BKP-》DR1=0X5050; printf(“FIRST TIMEn”); }else//系统继续计时 { while(!(RTC-》CRL&(1《《3)));//等待RTC寄存器同步 RTC-》CRH|=0X01; //允许秒中断 while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成 printf(“OKn”); } MY_NVIC_Init(0,0,RTC_IRQn,2);//优先级设置 RTC_Get();//更新时间 return 0; //ok } 实现时间计算部分代码: 说一下除以和求余的区别: 除运算得到的是整数倍 除数的整数; 求余预算得到的是拿了整数倍 除数,,剩余的整数; 例如 100 / 3 = 33.。..。..。..3 33是除运算得到的,1是求余的得到的 先说一下实现计算时间的实现思路(主要抓住中断函数就行,中断是每1s中断一次): 1、中断,跳转至我们的中断服务函数,取出计数器计算到的秒数; 2、对秒数进行计算,求出过了多少天; 加入现在的秒数是 8000000s, 那现在就是 8000000 / 3600 / 24 / = 92.59 天 这里计算出来的天数(整数 加1 )要和上一次的天数比较,如果多一天的话,就继续执行,要是后365天了,就要判断下一年是否是闰 年(接下来计算的2月要使用),计算闰年,就考验大家的算法了 将闰年的和平年每个月的天数 保存在数组里面,将计算出的天数和数组比较机也可以得出现在是几月 例如:今年是平年 92.59 - 31(1月)-28(2月)-31(3月)= 2.59天 2.59天 《 30天(4月) 那就可以判断现在是4月 2.59天 取整数 再加1,就是哪天,2.59取整就是2,再加1就是3,那今天就是4月3号 3、时间计算: 1)小时:计算的秒数对一天的秒数求余数得到不够一天的秒数之后,在除以一小时的秒数; 8000000 % (3600 *24) / 3600 = 14 ,那现在的时钟就是下午的2时 2)分钟:计算的秒数对一天的秒数求余数得到不够一天的秒数之后, 再对一小时的秒数求余,得到不够一小时的秒数; 最后在除以一分钟的秒数得到现在是 几分钟 3)秒数: 计算的秒数对一天的秒数求余数得到不够一天的秒数之后, 再对一小时的秒数求余,得到不够一小时的秒数; 最后再一分钟的秒数求余,得到现在是 几秒 4)星期几,这个就自己看吧,也不难,代码应该能看懂的了 //判断是否是闰年函数 //月份 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 //year:年份 //返回值:该年份是不是闰年.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}; //syear,smon,sday,hour,min,sec:年月日时分秒 //返回值:设置结果。0,成功;1,失败。 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《syear;t++) //把所有年份的秒钟相加 { if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数 else seccount+=31536000; //平年的秒钟数 } smon-=1; for(t=0;t《smon;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-》APB1ENR|=1《《28;//使能电源时钟 RCC-》APB1ENR|=1《《27;//使能备份时钟 PWR-》CR|=1《《8; //取消备份区写保护 //上面三步是必须的! RTC-》CRL|=1《《4; //允许配置 RTC-》CNTL=seccount&0xffff; RTC-》CNTH=seccount》》16; RTC-》CRL&=~(1《《4);//配置更新 while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成 RTC_Get();//设置完之后更新一下数据 return 0; } //得到当前的时间,结果保存在calendar结构体里面 //返回值:0,成功;其他:错误代码。 u8 RTC_Get(void) { static u16 daycnt=0; u32 timecount=0; u32 temp=0; u16 temp1=0; timecount=RTC-》CNTH;//得到计数器中的值(秒钟数) timecount《《=16; timecount+=RTC-》CNTL; 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 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)temp-=29;//闰年的秒钟数 else break; } 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年) //year,month,day:公历年月日 //返回值:星期号 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); } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1561 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1501 浏览 1 评论
933 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
665 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1555 浏览 2 评论
1850浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
615浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
506浏览 3评论
510浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
491浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 22:32 , Processed in 0.578333 second(s), Total 45, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号