基于51單片機的DS12C887電子鐘萬年歷( proteus仿真+程序+講解視頻)
仿真圖proteus 7.8及以上
程序編譯器:keil 4/keil 5
編程語言:C語言
設計編號:S0028
講解視頻
基于51單片機的DS12C887萬年歷帶農歷溫度顯示仿真設計
主要功能:
結合實際情況,基于51單片機設計一個電子鐘萬年歷。該系統(tǒng)應滿足的功能要求為:
DS12C887時鐘芯片,LED顯示、獨立鍵盤、農歷顯示、溫度顯示。
具體功能:
1、采用DS12C887記錄日歷和時間。
2、 通過數碼管顯示,可以顯示新歷年月日時分秒,農歷和星期,帶有溫度顯示。
3、可以按照實際,通過按鍵設置日期、時間。
以下為本設計資料展示圖:
仿真圖
主圖
開始仿真
開始顯示程序設置的初始時間,三組數碼管分別顯示年月日,時鐘分鐘秒、農歷日期和溫度。可以通過按鍵調整時間。
設置鍵按下第一下設置分鐘,第二下設置時鐘,第三下設置星期,第四下設置日期,第五下設置月份,第六下設置年份,第七下退出設置。通過按鍵DOWN和按鍵UP調整數值加減。如果已經調整好日期時間,按OUT按鍵可以退出設置。
程序:
ds12c887初始化和調用
#include "main.h"
#include "ds12c887.h"
void DS12C887_write(uchar add,uchar dat) //寫
{
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時間
{
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() ///設置初始時間
{
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); //時23
DS12C887_write(0x02,0x3B); //分59
DS12C887_write(0x00,0x32); //秒50
}
void DS12C887_init() //DS12C887初始化
{
DS12C887_write(0x0a,0x20); //DS12CR887寄存器A功能設置,開啟時鐘振蕩器
DS12C887_write(0x0b,0x06); //寄存器B功能設置,不開啟鬧鐘中斷使能,數據模式為二進制,24小時模式。
}
陰歷計算
/*
函數功能:輸入BCD陽歷數據,輸出BCD陰歷數據(只允許1901-2099年)
調用函數示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:計算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均為BCD數據,c_sun為世紀標志位,c_sun=0為21世
紀,c_sun=1為19世紀
調用函數后,原有數據不變,讀c_moon,year_moon,month_moon,day_moon得出陰歷BCD數據
*/
/*子函數,用于讀取數據表中農歷月的大月或小月,如果該月為大返回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);
// }
/*月份數據表-----------------------------------------------------------------------------*/
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};
/*子函數,用于讀取數據表中農歷月的大月或小月,如果該月為大返回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);
}
/*
函數功能:輸入BCD陽歷數據,輸出BCD陰歷數據(只允許1901-2099年)
調用函數示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:計算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均為BCD數據,c_sun為世紀標志位,c_sun=0為21世
紀,c_sun=1為19世紀
調用函數后,原有數據不變,讀c_moon,year_moon,month_moon,day_moon得出陰歷BCD數據
*/
void Conversion(bit c,uchar year,uchar month,uchar day)
{ //c=0 為21世紀,c=1 為19世紀 輸入輸出數據均為BCD數據
// 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 先把數據轉換為十六進制 這段要屏蔽掉,不然數碼管顯示亂碼
// 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;
//定位數據表地址
if(c==0)
{
table_addr=(year+0x64-1)*0x3;
}
else
{
table_addr=(year-1)*0x3;
}
//定位數據表地址完成
//取當年春節(jié)所在的公歷月份
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
//取當年春節(jié)所在的公歷月份完成
//取當年春節(jié)所在的公歷日
temp2=year_code[table_addr+2]&0x1f;
//取當年春節(jié)所在的公歷日完成
// 計算當年春年離當年元旦的天數,春節(jié)只會在公歷1月或2月
if(temp1==0x1)
{
temp3=temp2-1;
}
else
{
temp3=temp2+0x1f-1;
}
// 計算當年春年離當年元旦的天數完成
//計算公歷日離當年元旦的天數,為了減少運算,用了兩個表
//day_code1[9],day_code2[3]
//如果公歷月在九月或前,天數會少于0xff,用表day_code1[9],
//在九月后,天數大于0xff,用表day_code2[3]
//如輸入公歷日為8月10日,則公歷日離元旦天數為day_code1[8-1]+10-1
//如輸入公歷日為11月10日,則公歷日離元旦天數為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月為閏月,天數加1
temp4+=1;
}
//計算公歷日離當年元旦的天數完成
//判斷公歷日在春節(jié)前還是春節(jié)后
if (temp4>=temp3){ //公歷日在春節(jié)后或就是春節(jié)當日使用下面代碼進行運算
temp4-=temp3;
month=0x1;
month_p=0x1; //month_p為月份指向,公歷日在春節(jié)前或就是春節(jié)當日month_p指向首月
flag2=get_moon_day(month_p,table_addr);
//檢查該農歷月為大小還是小月,大月返回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); //從數據表中取該年的閏月月份,如為0則該年無閏月
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é)前使用下面代碼進行運算
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為月份指向,如果當年有閏月,一年有十三個月,月指向13,
無閏月指向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 ,運算結束后,把數據轉換為BCD數據
// 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;
}
資料清單:
下載地址見文章開頭