⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calendar.c

📁 基于stm32的MP3播放器
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "calendar.h"
//移植网友的代码
//超强的日历,支持农历,24节气几乎所有日历的功能
//日历时间以1970年为元年,用32bit的时间寄存器可以运行到2100年左右						   	    					  
//正点原子@SCUT
//V1.0

//下部分数据是农历部分要使用的
//月份数据表
u8  const day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
unsigned short const day_code2[3]={0x111,0x130,0x14e};
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
u8 const *sky[10]=  {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸",};//天干
u8 const *earth[12]={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥",};//地支
u8 const *monthcode[12]={"一","二","三","四","五","六","七","八","九","十","冬","腊",};//农历月份
u8 const *nongliday[4]={"初","十","廿","三",};//农历日期  

tm timer;//时钟结构体 	  
//实时时钟配置
//BKP->DR1 bit3 时钟是否要重设?
void rtc_init(void)
{	
	//检查是不是第一次配置时钟
	u8 temp;
	temp=FM24C16_ReadOneByte(52);
	if(temp&0X02)//系统继续计时
	{	
		printf("TIME Init OK!\n");							    					  
		//NVIC_RTCConfiguration();//RTC中断使能   
    	//while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步  
    	//RTC->CRH|=0X01;  		  //允许秒中断
    	//while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成	 
	}else //第一次配置(未开启秒中断!!)	
	{	
		printf("TIME need INIT!\n");								  
		//NVIC_RTCConfiguration(); //RTC中断使能	 
	  	RCC->APB1ENR|=1<<28;     //使能电源时钟	    
		RCC->APB1ENR|=1<<27;     //使能备份时钟
			
		PWR->CR|=1<<8;           //取消备份区写保护
		RCC->BDCR|=1<<16;        //备份区域软复位	   
		RCC->BDCR&=~(1<<16);     //备份区域软复位
				 
	    RCC->BDCR|=1<<0;         //开启外部低速振荡器 
	    while(!(RCC->BDCR&0X02));//等待外部时钟就绪	 
		RCC->BDCR|=1<<8; //LSI作为RTC时钟 	    
		RCC->BDCR|=1<<15;//RTC时钟使能	    

		RTC->PRLH=0X0000;
		RTC->PRLL=32770;          //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767										 
	  	while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
											   
		RTC->CRL|=1<<4;   //允许配置	  
		rtc_set(2009,4,19,23,59,55);//设置时间	  
		RTC->CRL&=~(1<<4);//配置更新
		while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成	
		temp|=0x02;//标记时钟被修改了
	 	FM24C16_WriteOneByte(52,temp);  
	}
	rtc_get();//更新时间 
}
//RTC时钟中断
//每秒触发一次   
void RTC_IRQHandler(void)
{
	u16 RTCCRL;	  
	RTCCRL=RTC->CRL;//读取FLAG
	if(RTCCRL&0x0001)//秒钟中断
	{
		rtc_get();//更新时间 
		printf("sec ok\n");	
	}
	if(RTCCRL&0x0002)//闹钟中断
	{
		RTC->CRL&=~(0x0002);//清闹钟中断
		Alarm_Process();
		//闹钟处理
	} 				  								 
    RTC->CRL&=0X0FFA;         //清除溢出,秒钟中断标志
	while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成		   							 	   	 
}
//月份   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;	
}

//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份

//平年的月份日期表
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 0;	   
	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->APB1ENR|=1<<28;//使能电源时钟
    RCC->APB1ENR|=1<<27;//使能备份时钟
	PWR->CR|=1<<8;    //取消备份区写保护
	//上面三步是必须的!
	RTC->CRL|=1<<4;   //允许配置 
	RTC->CNTL=seccount&0xffff;
	RTC->CNTH=seccount>>16;
	RTC->CRL&=~(1<<4);//配置更新
	while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成  	
	return 1;	    
}
//从当前秒钟值,得到时间.
//返回值:0,失败;1,成功
u8 rtc_get(void)
{
	u32 timecount=0; 
	u32 temp=0;
	u16 temp1=0;   
	timecount=RTC->CNTH;//得到计数器中的值(秒钟数)
	timecount<<=16;
	timecount+=RTC->CNTL;			 

	temp=timecount/86400;   //得到天数(秒钟数对应的)
	temp1=1970;	//从1970年开始
	while(temp>=365)
	{				 
		if(Is_Leap_Year(temp1))//是闰年
		{
			if(temp>=366)temp-=366;//闰年的秒钟数
			else {temp1++;break;}  
		}
		else temp-=365;	  //平年 
		temp1++;  
	}   
	timer.w_year=temp1;//得到年份
	temp1=0;
	while(temp>=28)//超过了一个月
	{
		if(Is_Leap_Year(timer.w_year)&&temp1==1)//当年是不是闰年/2月份
		{
			if(temp>=29)temp-=29;//闰年的秒钟数
			else break; 
		}
		else 
		{
			if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
			else break;
		}
		temp1++;  
	}
	timer.w_month=temp1+1;//得到月份
	timer.w_date=temp+1;  //得到日期		 

	temp=timecount%86400;     //得到秒钟数   	   
	timer.hour=temp/3600;     //小时
	timer.min=(temp%3600)/60; //分钟	
	timer.sec=(temp%3600)%60; //秒钟
	return 1;
}



///////////////////////////////////////////////////////////////////////
//支持从1900年到2099年的农历查询
//支持从2000年到2050年的节气查询
//子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0
u8 GetMoonDay(u8 month_p,unsigned short table_addr)
{
	switch (month_p)
	{
		case 1:
			if((year_code[table_addr]&0x08)==0)	return(0);
			else 								return(1); 
		case 2:
			if((year_code[table_addr]&0x04)==0)	return(0);
			else 								return(1);
		case 3:
			if((year_code[table_addr]&0x02)==0)	return(0);
			else 								return(1);
		case 4:
			if((year_code[table_addr]&0x01)==0)	return(0);
			else 								return(1);
		case 5:
			if((year_code[table_addr+1]&0x80)==0)	return(0);
			else 									return(1);
		case 6:
			if((year_code[table_addr+1]&0x40)==0)	return(0);
			else 									return(1);
		case 7:
			if((year_code[table_addr+1]&0x20)==0)	return(0);
			else 									return(1);
		case 8:
			if((year_code[table_addr+1]&0x10)==0)	return(0);
			else 									return(1);
		case 9:
			if((year_code[table_addr+1]&0x08)==0)	return(0);
			else 									return(1);
		case 10:
			if((year_code[table_addr+1]&0x04)==0)	return(0);
			else 									return(1);
		case 11:
			if((year_code[table_addr+1]&0x02)==0)	return(0);
			else 									return(1);
		case 12:
			if((year_code[table_addr+1]&0x01)==0)	return(0);
			else 									return(1);
		case 13:
			if((year_code[table_addr+2]&0x80)==0)	return(0);
			else 									return(1);
	}
	return(0);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////// 
// 函数名称:GetChinaCalendar
//功能描述:公农历转换(只允许1901-2099年)
// 输 入:  year        公历年
//          month       公历月
//          day         公历日
//          p           储存农历日期地址
// 输 出:  1           成功
//          0           失败																			 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
u8 GetChinaCalendar(u16  year,u8 month,u8 day,u8 *p)
{ 
	u8 temp1,temp2,temp3,month_p,yearH,yearL;	
	u8 flag_y;
	unsigned short temp4,table_addr;

	yearH=year/100;	yearL=year%100;//年份的高低两个字节 
	if((yearH!=19)&&(yearH!=20))return(0);//日期不在19xx ~ 20xx 范围内,则退出
	
	// 定位数据表地址  
	if(yearH==20)	table_addr=(yearL+100-1)*3;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -