?? calendar.c
字號(hào):
#include "calendar.h"
//移植網(wǎng)友的代碼
//超強(qiáng)的日歷,支持農(nóng)歷,24節(jié)氣幾乎所有日歷的功能
//日歷時(shí)間以1970年為元年,用32bit的時(shí)間寄存器可以運(yùn)行到2100年左右
//正點(diǎn)原子@SCUT
//V1.0
//下部分?jǐn)?shù)據(jù)是農(nóng)歷部分要使用的
//月份數(shù)據(jù)表
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}; //月修正數(shù)據(jù)表
u8 const *sky[10]= {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸",};//天干
u8 const *earth[12]={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥",};//地支
u8 const *monthcode[12]={"一","二","三","四","五","六","七","八","九","十","冬","臘",};//農(nóng)歷月份
u8 const *nongliday[4]={"初","十","廿","三",};//農(nóng)歷日期
tm timer;//時(shí)鐘結(jié)構(gòu)體
//實(shí)時(shí)時(shí)鐘配置
//BKP->DR1 bit3 時(shí)鐘是否要重設(shè)?
void rtc_init(void)
{
//檢查是不是第一次配置時(shí)鐘
u8 temp;
temp=FM24C16_ReadOneByte(52);
if(temp&0X02)//系統(tǒng)繼續(xù)計(jì)時(shí)
{
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; //使能電源時(shí)鐘
RCC->APB1ENR|=1<<27; //使能備份時(shí)鐘
PWR->CR|=1<<8; //取消備份區(qū)寫保護(hù)
RCC->BDCR|=1<<16; //備份區(qū)域軟復(fù)位
RCC->BDCR&=~(1<<16); //備份區(qū)域軟復(fù)位
RCC->BDCR|=1<<0; //開啟外部低速振蕩器
while(!(RCC->BDCR&0X02));//等待外部時(shí)鐘就緒
RCC->BDCR|=1<<8; //LSI作為RTC時(shí)鐘
RCC->BDCR|=1<<15;//RTC時(shí)鐘使能
RTC->PRLH=0X0000;
RTC->PRLL=32770; //時(shí)鐘周期設(shè)置(有待觀察,看是否跑慢了?)理論值:32767
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
RTC->CRL|=1<<4; //允許配置
rtc_set(2009,4,19,23,59,55);//設(shè)置時(shí)間
RTC->CRL&=~(1<<4);//配置更新
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
temp|=0x02;//標(biāo)記時(shí)鐘被修改了
FM24C16_WriteOneByte(52,temp);
}
rtc_get();//更新時(shí)間
}
//RTC時(shí)鐘中斷
//每秒觸發(fā)一次
void RTC_IRQHandler(void)
{
u16 RTCCRL;
RTCCRL=RTC->CRL;//讀取FLAG
if(RTCCRL&0x0001)//秒鐘中斷
{
rtc_get();//更新時(shí)間
printf("sec ok\n");
}
if(RTCCRL&0x0002)//鬧鐘中斷
{
RTC->CRL&=~(0x0002);//清鬧鐘中斷
Alarm_Process();
//鬧鐘處理
}
RTC->CRL&=0X0FFA; //清除溢出,秒鐘中斷標(biāo)志
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結(jié)尾,還要能被400整除
else return 0;
}else return 1;
}else return 0;
}
//設(shè)置時(shí)鐘
//把輸入的時(shí)鐘轉(zhuǎn)換為秒鐘
//以1970年1月1日為基準(zhǔn)
//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;//閏年的秒鐘數(shù)
else seccount+=31536000; //平年的秒鐘數(shù)
}
smon-=1;
for(t=0;t<smon;t++) //把前面月份的秒鐘數(shù)相加
{
seccount+=(u32)mon_table[t]*86400;//月份秒鐘數(shù)相加
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//閏年2月份增加一天的秒鐘數(shù)
}
seccount+=(u32)(sday-1)*86400;//把前面日期的秒鐘數(shù)相加
seccount+=(u32)hour*3600;//小時(shí)秒鐘數(shù)
seccount+=(u32)min*60; //分鐘秒鐘數(shù)
seccount+=sec;//最后的秒鐘加上去
//設(shè)置時(shí)鐘
RCC->APB1ENR|=1<<28;//使能電源時(shí)鐘
RCC->APB1ENR|=1<<27;//使能備份時(shí)鐘
PWR->CR|=1<<8; //取消備份區(qū)寫保護(hù)
//上面三步是必須的!
RTC->CRL|=1<<4; //允許配置
RTC->CNTL=seccount&0xffff;
RTC->CNTH=seccount>>16;
RTC->CRL&=~(1<<4);//配置更新
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
return 1;
}
//從當(dāng)前秒鐘值,得到時(shí)間.
//返回值:0,失敗;1,成功
u8 rtc_get(void)
{
u32 timecount=0;
u32 temp=0;
u16 temp1=0;
timecount=RTC->CNTH;//得到計(jì)數(shù)器中的值(秒鐘數(shù))
timecount<<=16;
timecount+=RTC->CNTL;
temp=timecount/86400; //得到天數(shù)(秒鐘數(shù)對(duì)應(yīng)的)
temp1=1970; //從1970年開始
while(temp>=365)
{
if(Is_Leap_Year(temp1))//是閏年
{
if(temp>=366)temp-=366;//閏年的秒鐘數(shù)
else {temp1++;break;}
}
else temp-=365; //平年
temp1++;
}
timer.w_year=temp1;//得到年份
temp1=0;
while(temp>=28)//超過了一個(gè)月
{
if(Is_Leap_Year(timer.w_year)&&temp1==1)//當(dāng)年是不是閏年/2月份
{
if(temp>=29)temp-=29;//閏年的秒鐘數(shù)
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; //得到秒鐘數(shù)
timer.hour=temp/3600; //小時(shí)
timer.min=(temp%3600)/60; //分鐘
timer.sec=(temp%3600)%60; //秒鐘
return 1;
}
///////////////////////////////////////////////////////////////////////
//支持從1900年到2099年的農(nóng)歷查詢
//支持從2000年到2050年的節(jié)氣查詢
//子函數(shù),用于讀取數(shù)據(jù)表中農(nóng)歷月的大月或小月,如果該月為大返回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);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 函數(shù)名稱:GetChinaCalendar
//功能描述:公農(nóng)歷轉(zhuǎn)換(只允許1901-2099年)
// 輸 入: year 公歷年
// month 公歷月
// day 公歷日
// p 儲(chǔ)存農(nóng)歷日期地址
// 輸 出: 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;//年份的高低兩個(gè)字節(jié)
if((yearH!=19)&&(yearH!=20))return(0);//日期不在19xx ~ 20xx 范圍內(nèi),則退出
// 定位數(shù)據(jù)表地址
if(yearH==20) table_addr=(yearL+100-1)*3;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -