本帖最后由 yangyurong 于 2025-1-17 17:31 编辑
万年历是从1990年1月1日开始的所有年份的年、月、日、时、分、秒信息。这个和我们台式电脑上面的日历非常类似,打开电脑右下角的日历
可以看到今天是2025年1月17日
具体时间在右下角
本次测评我就会使用G32A1465的任意一个普通的定时器来实现万年历显示 年、月、日、时、分、秒等具体时间功能!不需要额外的外设操作,只需要一个定时器和一个串口,串口用来打印具体的万年历信息,因为我手上目前没有LED显示模块和LCD面板,所以只能使用串口来打印时间。不过这没有关系,只要时间精确,最后打印出来的时间信息可以和wind10电脑右下角的时间进行对比查看时间的准确性。
万年历说明
输出指定月的月份,需要了解每个月份的相关条件:
1.该月有多少天
2.该月的1号是星期几(求距离1990.1.1的总天数)
3.如何将当月日期一一对应星期
解决了这三个问题,就可以打印出指定年份的月的日历了。
一、求某年某月里该月份里面有多少天
因为每个月份可能天数是不相同的,这里有涉及到闰年的问题。
整体来说1,3,5,7,8,10,12,这几个月***是31天。称为大月。
大月就是该月有31天,小月就是有30天,基本是不需要年份就可以判断该月的天数的,唯独一个二月,二月就需要年份的判断。二月是一个小月,按前面来说应该是30天的,但是就是它不同,2月在闰年的时候是29天,在平年的时候是28天。这样的话就需要判断该年是闰年还是平年。就可以知道指定月里有多少天数了。
1.判断某年是闰年和平年
如果某年是闰年的话,该年一共有366天,因为2月是29天。平年的话,就是365天。
闰年是啥:
1.该年份能被4整除且不能被100整除。或 2.该年份能被400整除。
uint8_t LeapYear(uint16_t year)
{
uint16_t y = year;
uint16_t remainder;
remainder = y%4;
if(!remainder)
{
remainder = y%100;
if(remainder) return 1;
else
{
remainder = y%400;
if(remainder) return 0;
}
return 1;
}
return 0;
}
2.求出某年某月有多少天
首先对大月进行判断
1,3,5,7,8,10,12是大月,***是31天
uint8_t BigMonth(uint8_t month)
{
if(month==1 || month==3 || month==5 || month==7 ||
month==8 || month==10 || month==12)
return 1;
return 0;
}
uint8_t LeapYear(uint16_t year)
{
uint16_t y = year;
uint16_t remainder;
remainder = y%4;
if(!remainder)
{
remainder = y%100;
if(remainder) return 1;
else
{
remainder = y%400;
if(remainder) return 0;
}
return 1;
}
return 0;
}
判断某年某月有多少天,具体功能如下:
先设定一个1ms的定时器计时中断,每计时1ms,定时器就会溢出,这样Timer_1s_Count就进行累加,累计1000次刚好就是1s定时,然后清零,这时调用万年历年月日时分秒设置函数
void TimeVariable_Processing(void)
{
uint8_t day;
day = datetime.day;
datetime.second += 1;
if(datetime.second>=60)
{
datetime.second -= 60;
datetime.min++;
if(datetime.min>=60)
{
datetime.min -= 60;
datetime.hour++;
if(datetime.hour>=24)
{
datetime.hour -= 24;
day = (++datetime.day);
if(BigMonth(datetime.month))
{
if(day>=32)
{
datetime.day-=31;
day=0xff;
}
}
else
{
if(datetime.month==2)
{
if(LeapYear(datetime.year))
{
if(day>=30)
{
datetime.day-=29;
day=0xff;
}
}
else if(day>=29)
{
datetime.day-=28;
day=0xff;
}
}
else if(day>=31)
{
datetime.day-=30;
day=0xff;
}
}
if(day==0xff)
{
datetime.month++;
if(datetime.month>=13)
{
datetime.month -= 12;
datetime.year++;
}
}
else datetime.day=day;
}
}
}
}
为了计算出准确的时间信息,我还为此专门设计了一个设定年月日时分秒的函数,通过它可以校验初始时间
void Calendar_TimeVariable_Set(uint16_t Year,uint8_t Month,uint8_t Day,uint8_t Hour,uint8_t Min,uint8_t Second)
{
datetime.year = Year;
datetime.month = Month;
datetime.day = Day;
datetime.hour = Hour;
datetime.min = Min;
datetime.second = Second;
}
就是根据当前windows10电脑自带的网络时间,写入这个函数,然后调用定时器里面的TimeVariable_Processing函数进行时间信息的核心算法处理,实现精确的定时操作!最后将及时得到的时间再与windows10桌面的时间信息进行对比,这样就实现了万年历的所有功能。
4.当判断万年历的日是否大于当月的天数时,需要注意 1、3、5、7、8、10、12 月天数有 31
天,闰年 2 月天数有 29 天,平年 2 月天数有 28 天,其余月份天数 30 天。
5.年份能被 4 整除、但不能被 100 整除,或能被 400 整除的年份为闰年。好了,花不多说,我们直接上干货!!!!!!!!!!!!!!!!!!
打开demo文件夹里的一个定时器工程即可,我们选择G32A1xxx_SDK_V1.1\Examples\G32A1465\CFGTMR\CFGTMR_PeriodicInterrupt
CFGTMR_PeriodicInterrupt这个定时器周期性中断工程
打开keil
main文件修改代码如下
/* Includes */
#include "user_config.h"
#include "board.h"
#include <stdio.h>
#define TICKS_PER_SECOND 1000
typedef struct{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t second;
} TimeStamp;
volatile uint16_t Timer_1s_Count;
void Calendar_TimeVariable_Set(uint16_t Year,uint8_t Month,uint8_t Day,uint8_t Hour,uint8_t Min,uint8_t Second);
uint8_t BigMonth(uint8_t month);
uint8_t LeapYear(uint16_t year);
void TimeVariable_Processing(void);
TimeStamp datetime;
void Calendar_TimeVariable_Set(uint16_t Year,uint8_t Month,uint8_t Day,uint8_t Hour,uint8_t Min,uint8_t Second)
{
datetime.year = Year;
datetime.month = Month;
datetime.day = Day;
datetime.hour = Hour;
datetime.min = Min;
datetime.second = Second;
}
uint8_t BigMonth(uint8_t month)
{
if(month==1 || month==3 || month==5 || month==7 ||
month==8 || month==10 || month==12)
return 1;
return 0;
}
uint8_t LeapYear(uint16_t year)
{
uint16_t y = year;
uint16_t remainder;
remainder = y%4;
if(!remainder)
{
remainder = y%100;
if(remainder) return 1;
else
{
remainder = y%400;
if(remainder) return 0;
}
return 1;
}
return 0;
}
void TimeVariable_Processing(void)
{
uint8_t day;
day = datetime.day;
datetime.second += 1;
if(datetime.second>=60)
{
datetime.second -= 60;
datetime.min++;
if(datetime.min>=60)
{
datetime.min -= 60;
datetime.hour++;
if(datetime.hour>=24)
{
datetime.hour -= 24;
day = (++datetime.day);
if(BigMonth(datetime.month))
{
if(day>=32)
{
datetime.day-=31;
day=0xff;
}
}
else
{
if(datetime.month==2)
{
if(LeapYear(datetime.year))
{
if(day>=30)
{
datetime.day-=29;
day=0xff;
}
}
else if(day>=29)
{
datetime.day-=28;
day=0xff;
}
}
else if(day>=31)
{
datetime.day-=30;
day=0xff;
}
}
if(day==0xff)
{
datetime.month++;
if(datetime.month>=13)
{
datetime.month -= 12;
datetime.year++;
}
}
else datetime.day=day;
}
}
}
}
int main(void)
{
CFGTMR_STATE_T cfgtmr0State;
/* Initialize clock */
CLOCK_SYS_Init(&g_clockConfig);
/* Initialize pins */
PINS_Init(NUM_OF_CONFIGURED_PINS0, g_pinsConfig);
/* Initialize LEDs */
LED_Init();
LED_On(LED_GREEN);
/* Initialize Buttons */
BTN_Init();
/* Initialize UART */
COM_Init();
/* Initialize CFGTMR */
CFGTMR_Init(CFGTMR0_INSTANCE, &g_cfgtmr0InitConfig, &cfgtmr0State);
/* Initialize counter */
CFGTMR_InitCounter(CFGTMR0_INSTANCE, &g_cfgtmr0TimerParamConfig);
/* Start Counter */
CFGTMR_StartCounter(CFGTMR0_INSTANCE);
/**** 设置万年历开始时间 ****/
Calendar_TimeVariable_Set(2025,1,17,24,30,00);
while (1)
{
printf("现在时间为%d年%d月%d日%d时%d分%d秒\n",datetime.year,datetime.month,datetime.day,datetime.hour,datetime.min,datetime.second);
}
}
/*!
* @brief CFGTMR0 Counter overflow and Reload IRQ handler.
*
* @param None
*
* @retval None
*/
void CFGTMR0_Ovf_Reload_IRQHandler(void)
{
static uint32_t cnt = 0;
if (CFGTMR_ReadStatusFlags(CFGTMR0_INSTANCE) & CFGTMR_TIME_OVERFLOW_FLAG)
{
if (++cnt == 1000U)
{
TimeVariable_Processing();
LED_Toggle(LED_GREEN);//绿灯每1秒钟跳转一次
cnt = 0;
}
}
CFGTMR_ClearStatusFlags(CFGTMR0_INSTANCE, (uint32_t)CFGTMR_TIME_OVERFLOW_FLAG);
}
烧录后串口打印
查看现在时间
打开电脑右下边查看现在时间
可以看到两者时间一致,我的万年历就完成了,这是我原创的,
下面附件是我的万年历烧录hex文件,大家可以直接用jlink烧录到板子测试
|
-
1.png
(241.31 KB )
万年历串口时间
-
2.png
(25.44 KB )
桌面时间
-
3.png
(137.49 KB )
万年历定时器算法
-
5.png
(325.5 KB )
非常准确的万年历
|