一.项目实验的内容
1.从RTC中获取时间,然后利用定时器,定时一段时间去更新时间。
这个更新时间的算法:本人采用的是万年历算法的思想实现的。
2.具体难点:需要判断是否是闰年,闰年与平年的天数不一样。
因为我使用的板子是自己公司做的,RTC电路没有装外部晶振,因此我的代码中 初始日期为 自己设定。
废话不多说,直接上代码。
二.代码实现
①参数定义与头文件引入
#include "at32f435_437_board.h"
#include "at32f435_437_clock.h"
/** @addtogroup AT32F435_periph_examples
* @{
*/
/** @addtogroup 435_TMR_timer_base TMR_timer_base
* @{
*/
void Update_time(uint32_t t);
uint32_t time_s = 0;
//假设当前时间为:2023-12-31-23-59-59 (这里的时间可以读取芯片中RTC获取。)
uint32_t year = 2023;
uint32_t month = 12;
uint32_t day = 31;
uint32_t hour = 23;
uint32_t minute = 59;
uint32_t second = 59;
uint32_t yuefen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
uint32_t yuefen1[12] = {31,29,31,30,31,30,31,31,30,31,30,31};//闰年
crm_clocks_freq_type crm_clocks_freq_struct = {0};//AT32F435时钟结构体,0表示sclk
参数说明,为啥设定2023-12-31-23-59-59,因为想着这个时间比较特殊,涉及到跨年,更容易看出代码有没有问题。
uint32_t time_s = 0 ; 用于定时多长时间,更新一次时间。
②主函数中定时器的配置
int main(void)
{
system_clock_config();
at32_board_init();
uart_print_init(115200);
/* get system clock */
crm_clocks_freq_get(&crm_clocks_freq_struct);
/* enable tmr1 clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
/* tmr1 configuration */
/* time base configuration */
tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.apb2_freq * 2 / 10000) - 1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
/* tmr1 hall interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 1, 0);
/* enable tmr1 */
tmr_counter_enable(TMR1, TRUE);
while(1)
{
Update_time(40);//40秒更新一次
}
}
我们把定时器配置为1秒钟产生一次中断,计数方式是 向上计数。
我设定了40秒钟更新一次时间。
③定时器1中断函数
void TMR1_OVF_TMR10_IRQHandler(void)
{
if(tmr_flag_get(TMR1, TMR_OVF_FLAG) == SET)
{
time_s++;
tmr_flag_clear(TMR1, TMR_OVF_FLAG);
}
}
定时器1中断功能:每次产生中断,令time_s加1,直到time_s 等于 40的时候,更新一次时间。
④万年历算法实现时间更新
void Update_time(uint32_t t)
{
uint32_t days;//天
uint32_t hours;//小时
uint32_t minutes;//分钟
uint32_t seconds;//秒
uint32_t i, q;
uint32_t temp = 0;
days = time_s/ (24 * 3600);//计算天数,一天24*60*60秒
time_s = time_s % (24 * 3600);//当前天的总秒数
hours = time_s / 3600;//计算当前天的小时
time_s = time_s % 3600;//分钟的秒数+秒数
minutes = time_s / 60;//计算当前天的分钟
seconds = time_s % 60;//当前的秒数
if(time_s == t)
{
//计算年份
for (i = days; i > 364; i--)//天数大于一整年的。
{
if (((year % 4 == 0) && (year % 100 != 0)) || year % 400 == 0)//闰年
{
year = year + 1;
i = i - 366 + 1;
}
else {//非闰年
year = year + 1;
i = i - 365 + 1;
}
}
//更新时间
second = second + seconds;
if (second >= 60)
{
second = second - 60;
minute++;
}
minute = minute + minutes;
if (minute >= 60)
{
minute = minute - 60;
hour++;
}
hour = hour + hours;
if (hour >= 24)
{
hour = hour - 24;
day++;
}
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)//闰年情况下 更新天数
{
day = day + i;
for (q = month - 1; q < 12; q++)
{
temp = yuefen1[q];
if (temp < day + 1)
{
month = month + 1;
day = day - yuefen1[q];
}
else break;
}
if (q >= 12 && day > 31)
{
for (q = 0; q < 12; q++)
{
temp = yuefen1[q];
if (temp < day + 1)
{
month = month + 1;
day = day - yuefen1[q];
}
}
}
}
else
{
day = day + i;
for (q = month - 1; q < 12; q++)
{
temp = yuefen[q];
if (temp < day + 1)
{
month = month + 1;
day = day - yuefen[q];
}
else break;
}
if (q >= 12 && day > 31)
{
for (q = 0; q < 12; q++)
{
temp = yuefen[q];
if (temp < day + 1)
{
month = month + 1;
day = day - yuefen[q];
}
}
}
}
if (month > 12)
{
month = month - 12;
year++;
}
printf("%d年 %d月 %d日 %d时 %d分 %d秒",year,month,day,hour,minute,second);
time_s = 0;
}
}
具体的逻辑自己去想一想 也能 想出来。
三、仿真效果。
用printf函数通过串口打印出来,通过串口调试助手可以观察到仿真效果。
完美定时40秒 更新一次时间。