<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
十二、开发板RTC时钟的调整程序设计
1、现在时钟运行情况
现在开发板上运行的时钟系统情况是这样:(1)能够持续不断地计时,即使断电也能够维持正确的时间格式。(2)不能显示日期。
其实现理论是这样:(1)每次运行时读取备份域寄存器的内容,若为指定的值0xAA,说明曾经初始化过,则继续运行就可以了。若不是,初始化RTC,并设置初始时间。(2)由于一天过去后,23:59:59后会溢出,所有每次运行都检查是否超过0x00015180(对应24小时),若超过0x00015180,则循环减去0x00015180,直到小于0x00015180为止。(3)同时在开发板运行过程中,在秒中断时也检查该数值,若超过0x00015180,则减去0x00015180,保持数值小于24小时。
2、新设计时钟系统的目标
(1)能够显示日期,以XXXX—XX—XX的格式显示。
(2)能够显示时间,以XX:XX:XX的格式显示。
(3)能够设置日期和时间。
3、设计实现的思路
(1)采用两个命令:date time。如果不带参数,则显示当前时间。如果带参数,则调整当前日期和时间。
(2)设置时,要对参数字符串的格式进行简单的验证。
4、程序实现的步骤
(1)在开发板复位时,首先检查备份域标志,若没有设置,则为RTC时钟设置时钟源、设置初始计数值,并设置备份域标志。
(2)如果标志已设置,则将APB1时钟与RTC时钟同步就行了。(根据RTC要求,这样可读寄存器里的数值才是正确的)。
(3)现在不需要秒中断了,可以取消。
(3)在命令终端输入time时,将调用下面的函数:
void UartCmdTime(u8 argc,void **argv){
u8 s[10]; //输出时间字符串
u32 RTCCount; //用于获取RTC的当前计数
TimeStruct CurrentTime; //时间结构定义
typedef struct {
u16 Year;u8 Month;u8 Date;u8 Week;u8 Hour;u8 Minute;u8 Second;}TimeStruct;
u8* ParaPtr= ( u8* ) ( argv[1] ); //类型强制转换。
if ( ParaPtr !='\0' ){ //如果有输入参数
if ( ParaPtr[2]==':' && ParaPtr[5] == ':'){ //简单检查参数格式
RTCCount= RTC_GetCounter(); //获取RTC的当前计数
Time_CountToTime(RTCCount,&CurrentTime);//首先获取系统的时间
Time_GetTimeFromStr( ParaPtr,&CurrentTime ); //改变时间结构中年月日
Time_Adjust( &CurrentTime );//调用设置时间函数。实际调用Time_TimeToCount将日期时间转换为计数值并写入RTC计数寄存器。
Uart_PutString ( "Time set finished !\r\n" ); }
return; }
RTCCount= RTC_GetCounter(); //获取RTC的当前计数
Time_ CountToTime (RTCCount,&CurrentTime); //转换为具体时间
//利用库函数将时间转换为格式化字符串
sprintf((char*)s,"%02d:%02d:%02d",CurrentTime.Hour,CurrentTime.Minute,CurrentTime.Second);
Uart_PutString(s); /*在屏幕上显示*/
Uart_PutString("\r\n"); //换行,回到命令提示符}
这里先准备好函数Time_TimeToCount()和Time_CountToTime()的框架,编译通过,然后再进行程序的设计,整个程序的重点和难点就在这两个函数。
5、从计数值取得时间,Time_CountToTime()函数的设计
计数规律:每秒加1,32位的计数器是137年溢出一次,所以要设定一个参照时间。从该时间开始往后计数。我这里采用<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1980-01-01、00:00:00为开始计数时间,我记得linux好像是从1970年开始的。
每天的秒数为24*60*60=86400=0x16580;每四年的天数为366+3*365=1461=0x5B5(因为能被4整除的年份2月有29号);
如我得到一个计数值 Xcount,拿它除以0x16580便得到从1980年1月1日以来经过的天数Xday,其余数便是这一天已经走过的秒数Xsec。
从Xsec秒数除以3600便得到小时数,其余数为Xsec,再除以60便得到分钟数,再得到的余数就是秒数。
关键是如何从天数得到年月日和星期的值,星期值应该这样求取,假定1980-1-1日是星期X,则天数除以7的余数就是相对X往后移的天数,这个数值+X再对7取模,就是真正的星期数。
如何取得年数呢?拿天数Xyear除以每四年的天数1461,就得到经过4年的个数X4,,其余数为4年内的天数,若小于366,则为第一年。实际年数为1980+4*X4。若大于等于366,则减去366后再除以365就是后三年中经过的年数X3。实际年数为1980+4*X4+1+X3。(由于2000年正好能被400整除,所有这一年2月有29日,所以就不同考虑逢百年不闰的问题了,2100年还早着呢。)。
月份用造表的方法解决:
闰年表{0,31,60,91,121,152,182,213,244,274,305,335,366};
非闰年表{0,31,59,90,120,151,181,212,243,273,304,334,365};
根据一年内剩余的天数查表,返回月份。
总天数减去该月对应的天数再加上1,就是对应的日期。
6、从时间计算出计数值,Time_TimeToCount ()函数的设计
年数减去1980得到经过的年数Xyear,年数除以4得到4年的个数X4y,如果余数YU<1则该年为闰年。用闰年表取出该月的天数Xyue,总天数Xday=1461*X4y+Xyue+日期-1。
如果余数YU大于1,则使用非闰年表取出月天数,总天数=1461*X4y+366+(YU-1)*365+Xyue+日期-1。
总天数*96400+小时*3600+分钟*60+实际秒数=总的计数值。
文章评论(0条评论)
登录后参与讨论