基于STM32单片机秒中断源和闹钟中断源的解决方案

控制/MCU

1813人已加入

描述

“RTC”是Real Time Clock 的简称,意为实时时钟。STM32提供了一个秒中断源和一个闹钟中断源。

RTC的技术器是一个32位的计数器,使用32.768khz的外部晶振。

2038年问题

在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作。所有使用UNIX时间表示时间的程序都将受其影响,因为它们以自1970年1月1日经过的秒数(忽略闰秒)来表示时间。这种时间表示法在类Unix(Unix-like)操作系统上是一个标准,并会影响以其C编程语言开发给其他大部份操作系统使用的软件。

计数器

在大部份的32位操作系统上,此“time_t”数据模式使用一个有正负号的32位元整数(signedint32)存储计算的秒数。也就是说最大可以计数的秒数为 2^31次方 可以算得:

2^31/3600/24/365 ≈ 68年

所以依照此“time_t”标准,在此格式能被表示的最后时间是2038年1月19日03:14:07,星期二(UTC)。超过此一瞬间,时间将会被掩盖(wrap around)且在内部被表示为一个负数,并造成程序无法工作,因为它们无法将此时间识别为2038年,而可能会依个别实作而跳回1970年或1901年。

对于PC机来说,时间开始于1980年1月1日,并以无正负符号的32位整数的形式按秒递增,这与UNIX时间非常类似。可以算得:

2^32/3600/24/365 ≈ 136年

到2116年,这个整数将溢出。

Windows NT使用64位整数来计时。但是,它使用100纳秒作为增量单位,且时间开始于1601年1月1日,所以NT将遇到2184年问题。

苹果公司声明,Mac在29,940年之前不会出现时间问题!

由于RTC是一个32位计数器,同样其计时时间是有限的。库函数中使用到了C标准时间库,时间库中的计时起始时间是1900年,可以知道时间库中不是用 有符号位的32位整数来表示时间的,否则在1968年就已经溢出了。如果用32位无符号整数计时,其溢出时间为2036年左右,所以会遇到这个问题。

直接操作寄存器中,可以自由设定这个时间戳起始的年份,RTC的32位寄存器存储的只是距离这个起始年份的总秒数,所以不会遇到这个问题。而且可以用无符号32位的二进制表示时间,这意味着此类系统的时间戳可以表示更多的秒数。但是由于其使用32位寄存器表示秒数,最大只能计时到136年后。

本例实现使用STM32每秒输出一次当前的时间,并设置一个闹钟,到时间时输出提醒信息。

直接操作寄存器

RTC实时时钟的操作原则是 在每次读写前都要保证上一次读写完成。

代码较多,使用到的寄存器请参见手册 (system.h 和stm32f10x_it.h等相关代码参照STM32 直接操作寄存器开发环境配置)

User/main.c

#include#include“system.h”#include“usart.h”#include“rtc.h”#defineLED1PAout(4)#defineLED2PAout(5)voidGpio_Init(void);externconstu8*Week_Table[7];intmain(void){Rcc_Init(9);//系统时钟设置Usart1_Init(72,9600);Nvic_Init(0,0,RTC_IRQChannel,0);//设置中断Gpio_Init();Rtc_Init();//Rtc_TIME_AutoSet();//将当前编译时间作为RTC开始时间Rtc_TIME_Set(2012,7,7,20,50,0);//设定开始时间参数说明:年,月,日,时,分,秒Rtc_ALARM_Set(2012,7,7,20,50,30);//设定闹钟事件时间LED1=1;while(1);}voidGpio_Init(void){RCC-》APB2ENR|=1《《2;//使能PORTA时钟GPIOA-》CRL&=0x0000FFFF;//PA0~3设置为浮空输入,PA4~7设置为推挽输出GPIOA-》CRL|=0x33334444;//USART1串口I/O设置GPIOA-》CRH&=0xFFFFF00F;//设置USART1的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入GPIOA-》CRH|=0x000008B0;}

User/stm32f103x_it.c

#include“stm32f10x_it.h”#include“system.h”#include“stdio.h”#include“rtc.h”#defineLED1PAout(4)#defineLED2PAout(5)#defineLED3PAout(6)#defineLED4PAout(7)//externvoidWwdg_Feed(void);//externu16Read_Bkp(u8reg);externvoidRtc_Get(void);externconstu8*Week_Table[7];voidRTC_IRQHandler(void){if(RTC-》CRL&0x0001)//秒钟中断{LED4=!LED4;Rtc_Get();printf(“\r\nTime:%d-%d-%d,%d:%d:%d,Todayis%s\r\n”,timer.year,timer.month,timer.date,timer.hour,timer.minute,timer.second,Week_Table[timer.week]);}if(RTC-》CRL&0x0002)//闹钟中断{LED3=1;printf(“\r\nIt‘stimetodosth.\r\n”);RTC-》CRL&=~(0x0002);//清除闹钟中断}RTC-》CRL&=0x0FFA;//清除溢出,秒钟中断while(!(RTC-》CRL&(1《《5)));//等待RTC寄存器操作完成}

Library/src/rtc.c

#include#include“rtc.h”#include“stdio.h”tmtimer;//定义时钟结构体,主函数直接可以调用此结构体读出时间//平年

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分