基于51單片機(jī)的DS12C887電子鐘萬(wàn)年歷( proteus仿真+程序+講解視頻)
仿真圖proteus 7.8及以上
程序編譯器:keil 4/keil 5
編程語(yǔ)言:C語(yǔ)言
設(shè)計(jì)編號(hào):S0028
講解視頻
基于51單片機(jī)的DS12C887萬(wàn)年歷帶農(nóng)歷溫度顯示仿真設(shè)計(jì)
主要功能:
結(jié)合實(shí)際情況,基于51單片機(jī)設(shè)計(jì)一個(gè)電子鐘萬(wàn)年歷。該系統(tǒng)應(yīng)滿足的功能要求為:
DS12C887時(shí)鐘芯片,LED顯示、獨(dú)立鍵盤(pán)、農(nóng)歷顯示、溫度顯示。
具體功能:
1、采用DS12C887記錄日歷和時(shí)間。
2、 通過(guò)數(shù)碼管顯示,可以顯示新歷年月日時(shí)分秒,農(nóng)歷和星期,帶有溫度顯示。
3、可以按照實(shí)際,通過(guò)按鍵設(shè)置日期、時(shí)間。
以下為本設(shè)計(jì)資料展示圖:
仿真圖
主圖
開(kāi)始仿真
開(kāi)始顯示程序設(shè)置的初始時(shí)間,三組數(shù)碼管分別顯示年月日,時(shí)鐘分鐘秒、農(nóng)歷日期和溫度??梢酝ㄟ^(guò)按鍵調(diào)整時(shí)間。
設(shè)置鍵按下第一下設(shè)置分鐘,第二下設(shè)置時(shí)鐘,第三下設(shè)置星期,第四下設(shè)置日期,第五下設(shè)置月份,第六下設(shè)置年份,第七下退出設(shè)置。通過(guò)按鍵DOWN和按鍵UP調(diào)整數(shù)值加減。如果已經(jīng)調(diào)整好日期時(shí)間,按OUT按鍵可以退出設(shè)置。
程序:
ds12c887初始化和調(diào)用
#include "main.h"
#include "ds12c887.h"
void DS12C887_write(uchar add,uchar dat) //寫(xiě)
{
DS12C887_CS=0;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_WR=1;
DS12C887_DATA=add;
DS12C887_AS=0;
DS12C887_WR=0;
DS12C887_DATA=dat;
DS12C887_WR=1;
DS12C887_AS=1;
DS12C887_CS=1;
}
uchar DS12C887_read(uchar add) //讀
{
uchar ds_date;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_WR=1;
DS12C887_CS=0;
DS12C887_DATA=add;
DS12C887_AS=0;
DS12C887_DS=0;
DS12C887_DATA=0xff;
ds_date=DS12C887_DATA;
DS12C887_DS=1;
DS12C887_AS=1;
DS12C887_CS=1;
return ds_date;
}
void DS12C887_Gettime() //獲取DS12C887時(shí)間
{
time_year =DS12C887_read(0x09); //年
time_month =DS12C887_read(0x08); //月
time_day = DS12C887_read(0x07); //日
time_week =DS12C887_read(0x06); //周
time_hour =DS12C887_read(0x04); //是
time_min = DS12C887_read(0x02); //分
time_sec = DS12C887_read(0x00); //秒
}
void DS12C887_Settime() ///設(shè)置初始時(shí)間
{
DS12C887_write(0x09,0x16); //年22 0x16->22
DS12C887_write(0x08,0x0C); //月12 0x0C->12
DS12C887_write(0x07,0x0C); //日11 0x0B->11
DS12C887_write(0x06,0x01); //周1
DS12C887_write(0x04,0x17); //時(shí)23
DS12C887_write(0x02,0x3B); //分59
DS12C887_write(0x00,0x32); //秒50
}
void DS12C887_init() //DS12C887初始化
{
DS12C887_write(0x0a,0x20); //DS12CR887寄存器A功能設(shè)置,開(kāi)啟時(shí)鐘振蕩器
DS12C887_write(0x0b,0x06); //寄存器B功能設(shè)置,不開(kāi)啟鬧鐘中斷使能,數(shù)據(jù)模式為二進(jìn)制,24小時(shí)模式。
}
陰歷計(jì)算
/*
函數(shù)功能:輸入BCD陽(yáng)歷數(shù)據(jù),輸出BCD陰歷數(shù)據(jù)(只允許1901-2099年)
調(diào)用函數(shù)示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:計(jì)算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均為BCD數(shù)據(jù),c_sun為世紀(jì)標(biāo)志位,c_sun=0為21世
紀(jì),c_sun=1為19世紀(jì)
調(diào)用函數(shù)后,原有數(shù)據(jù)不變,讀c_moon,year_moon,month_moon,day_moon得出陰歷BCD數(shù)據(jù)
*/
/*子函數(shù),用于讀取數(shù)據(jù)表中農(nóng)歷月的大月或小月,如果該月為大返回1,為小返回0*/
// /* static*/ unsigned char /*bit*/ get_moon_day(uchar month_p,uint table_addr)
// {
// uchar temp;
// switch (month_p){
// case 1:{temp=year_code[table_addr]&0x08;
// if (temp==0)return(0);else return(1);}
// case 2:{temp=year_code[table_addr]&0x04;
// if (temp==0)return(0);else return(1);}
// case 3:{temp=year_code[table_addr]&0x02;
// if (temp==0)return(0);else return(1);}
// case 4:{temp=year_code[table_addr]&0x01;
// if (temp==0)return(0);else return(1);}
// case 5:{temp=year_code[table_addr+1]&0x80;
// if (temp==0) return(0);else return(1);}
// case 6:{temp=year_code[table_addr+1]&0x40;
// if (temp==0)return(0);else return(1);}
// case 7:{temp=year_code[table_addr+1]&0x20;
// if (temp==0)return(0);else return(1);}
// case 8:{temp=year_code[table_addr+1]&0x10;
// if (temp==0)return(0);else return(1);}
// case 9:{temp=year_code[table_addr+1]&0x08;
// if (temp==0)return(0);else return(1);}
// case 10:{temp=year_code[table_addr+1]&0x04;
// if (temp==0)return(0);else return(1);}
// case 11:{temp=year_code[table_addr+1]&0x02;
// if (temp==0)return(0);else return(1);}
// case 12:{temp=year_code[table_addr+1]&0x01;
// if (temp==0)return(0);else return(1);}
// case 13:{temp=year_code[table_addr+2]&0x80;
// if (temp==0)return(0);else return(1);}
// }
// return(0);
// }
/*月份數(shù)據(jù)表-----------------------------------------------------------------------------*/
static unsigned char code day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
static unsigned short code day_code2[3]={0x111,0x130,0x14e};
/*子函數(shù),用于讀取數(shù)據(jù)表中農(nóng)歷月的大月或小月,如果該月為大返回1,為小返回0------------------*/
static unsigned char get_moon_day(unsigned char 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ù)功能:輸入BCD陽(yáng)歷數(shù)據(jù),輸出BCD陰歷數(shù)據(jù)(只允許1901-2099年)
調(diào)用函數(shù)示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:計(jì)算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均為BCD數(shù)據(jù),c_sun為世紀(jì)標(biāo)志位,c_sun=0為21世
紀(jì),c_sun=1為19世紀(jì)
調(diào)用函數(shù)后,原有數(shù)據(jù)不變,讀c_moon,year_moon,month_moon,day_moon得出陰歷BCD數(shù)據(jù)
*/
void Conversion(bit c,uchar year,uchar month,uchar day)
{ //c=0 為21世紀(jì),c=1 為19世紀(jì) 輸入輸出數(shù)據(jù)均為BCD數(shù)據(jù)
// uchar c_moon,year_moon,month_moon,day_moon;
uchar temp1,temp2,temp3,month_p;
uint temp4,table_addr;
bit flag2,flag_y;
// temp1=year/16; //BCD->hex 先把數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制 這段要屏蔽掉,不然數(shù)碼管顯示亂碼
// temp2=year%16;
// year=temp1*10+temp2;
// temp1=month/16;
// temp2=month%16;
// month=temp1*10+temp2;
// temp1=day/16;
// temp2=day%16;
// day=temp1*10+temp2;
//定位數(shù)據(jù)表地址
if(c==0)
{
table_addr=(year+0x64-1)*0x3;
}
else
{
table_addr=(year-1)*0x3;
}
//定位數(shù)據(jù)表地址完成
//取當(dāng)年春節(jié)所在的公歷月份
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
//取當(dāng)年春節(jié)所在的公歷月份完成
//取當(dāng)年春節(jié)所在的公歷日
temp2=year_code[table_addr+2]&0x1f;
//取當(dāng)年春節(jié)所在的公歷日完成
// 計(jì)算當(dāng)年春年離當(dāng)年元旦的天數(shù),春節(jié)只會(huì)在公歷1月或2月
if(temp1==0x1)
{
temp3=temp2-1;
}
else
{
temp3=temp2+0x1f-1;
}
// 計(jì)算當(dāng)年春年離當(dāng)年元旦的天數(shù)完成
//計(jì)算公歷日離當(dāng)年元旦的天數(shù),為了減少運(yùn)算,用了兩個(gè)表
//day_code1[9],day_code2[3]
//如果公歷月在九月或前,天數(shù)會(huì)少于0xff,用表day_code1[9],
//在九月后,天數(shù)大于0xff,用表day_code2[3]
//如輸入公歷日為8月10日,則公歷日離元旦天數(shù)為day_code1[8-1]+10-1
//如輸入公歷日為11月10日,則公歷日離元旦天數(shù)為day_code2[11-10]+10-1
if (month<10)
{
temp4=day_code1[month-1]+day-1;
}
else
{
temp4=day_code2[month-10]+day-1;
}
if ((month>0x2)&&(year%0x4==0))
{
//如果公歷月大于2月并且該年的2月為閏月,天數(shù)加1
temp4+=1;
}
//計(jì)算公歷日離當(dāng)年元旦的天數(shù)完成
//判斷公歷日在春節(jié)前還是春節(jié)后
if (temp4>=temp3){ //公歷日在春節(jié)后或就是春節(jié)當(dāng)日使用下面代碼進(jìn)行運(yùn)算
temp4-=temp3;
month=0x1;
month_p=0x1; //month_p為月份指向,公歷日在春節(jié)前或就是春節(jié)當(dāng)日month_p指向首月
flag2=get_moon_day(month_p,table_addr);
//檢查該農(nóng)歷月為大小還是小月,大月返回1,小月返回0
flag_y=0;
if(flag2==0)temp1=0x1d; //小月29天
else temp1=0x1e; //大小30天
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4); //從數(shù)據(jù)表中取該年的閏月月份,如為0則該年無(wú)閏月
while(temp4>=temp1){
temp4-=temp1;
month_p+=1;
if(month==temp2){
flag_y=~flag_y;
if(flag_y==0)month+=1;
}
else month+=1;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp4+1;
}
else{ //公歷日在春節(jié)前使用下面代碼進(jìn)行運(yùn)算
temp3-=temp4;
if (year==0x0){year=0x63;c=1;}
else year-=1;
table_addr-=0x3;
month=0xc;
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
if (temp2==0)month_p=0xc;
else month_p=0xd; //
/*
month_p為月份指向,如果當(dāng)年有閏月,一年有十三個(gè)月,月指向13,
無(wú)閏月指向12
*/
flag_y=0;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
while(temp3>temp1){
temp3-=temp1;
month_p-=1;
if(flag_y==0)month-=1;
if(month==temp2)flag_y=~flag_y;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp1-temp3+1;
}
// c_moon=c; //HEX->BCD ,運(yùn)算結(jié)束后,把數(shù)據(jù)轉(zhuǎn)換為BCD數(shù)據(jù)
// temp1=year/10;
// temp1=_crol_(temp1,4);
// temp2=year%10;
// year_moon=temp1|temp2;
// temp1=month/10;
// temp1=_crol_(temp1,4);
// temp2=month%10;
// month_moon=temp1|temp2;
// temp1=day/10;
// temp1=_crol_(temp1,4);
// temp2=day%10;
// day_moon=temp1|temp2;
c_moon=c;
year_moon=year;
month_moon=month;
day_moon=day;
}
資料清單:
下載地址見(jiàn)文章開(kāi)頭