打印
[G32A]

[G32A] 极海G32A1465测评】——定时器万年历

[复制链接]
63|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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 )

非常准确的万年历

非常准确的万年历

使用特权

评论回复
沙发
光影捕手| | 2025-1-17 17:29 | 只看该作者
这种闰月日期计算没有现成的库可以用吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

15

帖子

0

粉丝