学习笔记:基于STM32F103ZET6万年历的编写

本文介绍了在STM32F103ZET6开发板上配置RTC实时时钟的过程,包括时钟中断设置、时间转换函数以及闰年的处理。同时,展示了如何利用LCD显示屏显示时间,并提供了按键更改时间的功能。此外,还包含了一个判断闰年的辅助函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录:

一、硬件的选择与连接

1、STM32F103ZET6开发板

2、TTFLCD显示屏

二、展示实验操作结果

三、RTC时钟配置

 1、时钟中断配置(可直接参考‘正点原子实验’)

 2、设置时钟
把输入的时钟转换为秒钟
以1970年1月1日为基准
1970~2099年为合法年份
返回值:0,成功;其他:错误代码.

u8 const table_week[12]= {0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
//平年的月份日期表
const u8 mon_table[12]= {31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
    u16 t;
    u32 seccount=0;
    if(syear<1970||syear>2099)return 1;
    for(t=1970; t<syear; t++)	//把所有年份的秒钟相加
    {
        if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
        else seccount+=31536000;			  //平年的秒钟数
    }
    smon-=1;
    for(t=0; t<smon; t++)	 //把前面月份的秒钟数相加
    {
        seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
        if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
    }
    seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;	 //分钟秒钟数
    seccount+=sec;//最后的秒钟加上去

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟
    PWR_BackupAccessCmd(ENABLE);	//使能RTC和后备寄存器访问
    RTC_SetCounter(seccount);	//设置RTC计数器的值

    RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    return 0;
}

3、利用RTC时钟配置更改时间

 RTC_Set(2023,6,30,13,0,0);  设置时间

u8 RTC_Init(void)
{
    //检查是不是第一次配置时钟
    u8 temp=0;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟
    PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问
    if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    {
        BKP_DeInit();	//复位备份区域
        RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE),使用外设低速晶振
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
        {
            temp++;
            delay_ms(10);
        }
        if(temp>=250)return 1;//初始化时钟失败,晶振有问题
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
        RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟
        RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
        RTC_WaitForSynchro();		//等待RTC寄存器同步
        RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
        RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
        RTC_EnterConfigMode();/// 允许配置
        RTC_SetPrescaler(32767); //设置RTC预分频的值
        RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
        RTC_Set(2021,1,1,0,0,0);  //设置时间
        RTC_ExitConfigMode(); //退出配置模式
        BKP_WriteBackupRegister(BKP_DR1, 0X5051);	//向指定的后备寄存器中写入用户程序数据
    }
    else//系统继续计时
    {

        RTC_WaitForSynchro();	//等待最近一次对RTC寄存器的写操作完成
        RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
        RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    }
    RTC_NVIC_Config();//RCT中断分组设置
    RTC_Get();//更新时间
    return 0; //ok

}

四、采用LCD显示屏显示

//	 显示时间
//	 设置字体为蓝色
	   
	POINT_COLOR = BLUE;
	LCD_ShowString( 60, 130, 200, 16, 16, "    -  -  " );
	LCD_ShowString( 60, 162, 200, 16, 16, "  :  :  " );
	calendar_temp = calendar;

五、按键更改时间

//		 键处理函数
//		 返回按键值
//		 mode:0,不支持连续按;1,支持连续按;
//		 0,没有任何按键按下
//		 1,KEY0按下
//		 2,KEY1按下
//		 3,KEY3按下 WK_UP
//		   
		key = KEY_Scan( 0 );
		// KEY0 进入修改模式,依次顺序循环   
		if ( 1 == key )
		{
			index++;
			index = index % 7;
			// 进入修改   
			if ( 1 == index )
			{
				calendar_temp = calendar;
			}
			// 退出修改   
			else if(0 == index)
			{
				calendar = calendar_temp;
				RTC_Set( calendar_temp.w_year, calendar_temp.w_month, calendar_temp.w_date, calendar_temp.hour, calendar_temp.min, calendar_temp.sec );
			}
		}
		// KEY1 选中值+1   
		else if ( 2 == key )
		{
			if ( 1 == index )
			{
				calendar_temp.w_year++;
			} else if ( 2 == index )
			{
				calendar_temp.w_month++;
				calendar_temp.w_month = calendar_temp.w_month > 12 ? 1 : calendar_temp.w_month;
			} 

// KEY_UP 选中值-1 
		else if ( 3 == key )
		{
			if ( 1 == index )
			{
				calendar_temp.w_year--;
				calendar_temp.w_year = calendar_temp.w_year > 0 ? calendar_temp.w_year : 0;
			} else if ( 2 == index )
			{
				calendar_temp.w_month--;
				calendar_temp.w_month = calendar_temp.w_month > 0 ? calendar_temp.w_month : 12;
			} else if ( 3 == index )
			{
				if ( Is_Leap_Year( calendar_temp.w_year ) )
				{
					calendar_temp.w_date--;
					calendar_temp.w_date = calendar_temp.w_date > 0 ? calendar_temp.w_date : (calendar_temp.w_month == 2 ? (mon_table[calendar_temp.w_month - 1] + 1) : mon_table[calendar_temp.w_month - 1]);
				} else {
					calendar_temp.w_date--;
					calendar_temp.w_date = calendar_temp.w_date > 0 ? calendar_temp.w_date : mon_table[calendar_temp.w_month - 1];
				}
			} else if ( 4 == index )
			{
				calendar_temp.hour = calendar_temp.hour == 0 ? 23 : calendar_temp.hour - 1;
			} else if ( 5 == index )
			{
				calendar_temp.min = calendar_temp.min == 0 ? 59 : calendar_temp.min - 1;
			} else if ( 6 == index )
			{
				calendar_temp.sec = calendar_temp.sec == 0 ? 59 : calendar_temp.sec - 1;
			}
		}
		delay_ms( 10 );
	}

六、判断是否是闰年函数

//判断是否是闰年函数
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{
    if(year%4==0) //必须能被4整除
    {
        if(year%100==0)
        {
            if(year%400==0)return 1;//如果以00结尾,还要能被400整除
            else return 0;
        } else return 1;
    } else return 0;
}

七、显示时间

void show_index_time( u8 index, _calendar_obj calendar_temp )
{
	POINT_COLOR = BLUE;
	if ( 1 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 60, 130, calendar_temp.w_year, 4, 16 );
	POINT_COLOR = BLUE;
	if ( 2 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 100, 130, calendar_temp.w_month, 2, 16 );
	POINT_COLOR = BLUE;
	if ( 3 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 124, 130, calendar_temp.w_date, 2, 16 );
	POINT_COLOR = BLUE;
	if ( 4 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 60, 162, calendar_temp.hour, 2, 16 );
	POINT_COLOR = BLUE;
	if ( 5 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 84, 162, calendar_temp.min, 2, 16 );
	POINT_COLOR = BLUE;
	if ( 6 == index )
		POINT_COLOR = RED;
	LCD_ShowNum( 108, 162, calendar_temp.sec, 2, 16 );
	POINT_COLOR = RED;

	POINT_COLOR = BLUE;
	switch ( RTC_Get_Week( calendar_temp.w_year, calendar_temp.w_month, calendar_temp.w_date ) )
	{
		case 0:
			LCD_ShowString( 60, 180, 200, 16, 16, "Sunday   " );
			break;
		case 1:
			LCD_ShowString( 60, 180, 200, 16, 16, "Monday   " );
			break;
		case 2:
			LCD_ShowString( 60, 180, 200, 16, 16, "Tuesday  " );
			break;
		case 3:
			LCD_ShowString( 60, 180, 200, 16, 16, "Wednesday" );
			break;
		case 4:
			LCD_ShowString( 60, 180, 200, 16, 16, "Thursday " );
			break;
		case 5:
			LCD_ShowString( 60, 180, 200, 16, 16, "Friday   " );
			break;
		case 6:
			LCD_ShowString( 60, 180, 200, 16, 16, "Saturday " );
			break;
	}
}

仅是个人学习笔记,记录分享。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值