//作者:中山董豪 時間:2010年 //功能:4位數碼管可以顯示 時分,月日,年份;萬年歷,整點報時,定時自動(或手動)關閉顯示器,空閑模式工作省電 //硬件:2051單片機,P1.6到P1.0分別是 A到G,P1.7=DP,P3.5=D4,P3.4=D3,P3.1=D2,P3.0=D1,P3.7控制直流蜂鳴器(整點報時)。 // P3.2=0(改時間),P3.3=0(改狀態),6Mhz晶振。 //使用說明:默認時間為 2010年1月1日,0點0分,狀態1顯示時分 // 按P3.2為0,狀態++,狀態功能分別為 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; // 用DP來表示狀態,DP每秒閃爍1次(占空比3:1)。 對應的修改位置,閃爍。 // 在顯示年月日時分的狀態啟動P3.2為0,則進入關閉顯示器模式,或打開顯示器,在關閉顯示器的模式中,按任意鍵打開顯示器。 // 在修改年月日時分的狀態啟動P3.2為0,則對應數字加一,一直按住,則一直加。注:改年份月份的時候為了不與萬年歷沖突,日期自動變為1號,年份范圍是2010到2099年 //注明:該程序不是最終程序,更新程序請聯系中山董豪 //實測參數:數碼管工作時:2mA , 數碼管不工作時:1mA //建議改進 選用更低頻晶振 , 改用ATtiny2313代替。 #include <reg52.h> #include<intrins.h> #define uint unsigned int #define uchar unsigned char uchar second,minh,minl,hourh,hourl,hour,i,j,k,l,state,slient,dpi,dps,d2; uchar day,month,dayh,dayl,monthh,monthl; //1,3,5,7,8,10,12 大 31 uchar year1,year2,year3,year4,year; //4,6,9,11,小30 //unsigned int d1,d0 ; //2月閏年29天 year%4==0&&year%100!=0||year%400==0 uchar code thourh[]={10,10,10,10,10,10,10,10,10,10,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2}; uchar code thourl[]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4}; uchar code tmonthh[]={10,10,10,10,10,10,10,10,10,10,1,1,1}; uchar code tmonthl[]={ 0,1, 2, 3, 4, 5, 6, 7, 8, 9 ,0,1,2}; uchar code tdayh[]={10,10,10,10,10,10,10,10,10,10,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3}; uchar code tdayl[]={ 0,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1}; uchar code display[]={0x7E,0x30,0x6D,0x79,0x33,0x5B,0x5F,0x70,0x7F,0x7B,0x00}; //七段譯碼 P1.6=A sbit DP=P1^7; sbit int0=P3^2; //改時間 sbit int1=P3^3; sbit bee=P3^7; sbit P3_0=P3^0; sbit P3_1=P3^1; sbit P3_4=P3^4; sbit P3_5=P3^5; void main() { TMOD=0x11; TH0=(65536-50000)/256; TL0=(65536-50000)%256; //0.05s一次中斷,時鐘 TH1=(65536-3000)/256; TL1=(65536-3000)%256; //0.006s一次中斷,掃描顯示 IE=0X8A; //EA,ET0,ET1=1 IP=0x02; //PT0=1; state=1; // 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; slient=1; // 1:正常顯示 2:關閉顯示 second=0; //2010年0點0分0秒 minl=0; minh=0; hour=0; day=1; bee=0; month=1; year1=0; year2=1; year3=0; year4=2; TR1=1; TR0=1; while(1) { PCON=0X01; //空閑模式}//while } } //main 設置 void timer0() interrupt 1 using 0 //時鐘 改狀態 改時間 { TH0=(65536-50000)/256; //0.1s TL0=(65536-50000)%256; i++; if(i==10) { i=0; bee=1; if(slient==1) //自動關閉顯示器,剩電 10s自動關閉 { d2++; if(d2==10) {d2=0; //d3++; //if(d3==200) // // d3=0; slient=0; } } //自動關閉顯示器,剩電 if(second<59) second++; else { second=0; if(minl<9) minl++; else { minl=0; if(minh<5) minh++; else { minh=0; bee=0; //整點報時 if(hour<23) hour++; else { hour=0; /////////////////////////////////////// 萬年歷 if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) //1,3,5,7,8,10,12 大 31 { if(day<31) day++; else {day=1; if(month<12) month++; else { month=1; if(year1<9) year1++; else {year1=0; if(year2<9) year2++; else {year1=0; //最高位2099年 year2=1; year3=0; year4=2; } } } } } else if(month==4 || month==6 || month==9 || month==11) //4,6,9,11,小30 { if(day<30) day++; else {day=1; if(month<12) month++; else { month=1; if(year1<9) year1++; else {year1=0; if(year2<9) year2++; else {year1=0; //最高位2099年 year2=1; year3=0; year4=2; } } } } } else if(month==2) //2月閏年29天 { year=year4*1000+year3*100+year1*10+year1; if((year%4==0&&year%100!=0)||year%400==0) {if(day<29) //閏年 day++; else {day=1; if(month<12) month++; else { month=1; if(year1<9) year1++; else {year1=0; if(year2<9) year2++; else {year1=0; //最高位2099年 year2=1; year3=0; year4=2; } } } }} else {if(day<28) //非閏年 day++; else {day=1; if(month<12) month++; else { month=1; if(year1<9) year1++; else {year1=0; if(year2<9) year2++; else {year1=0; //最高位2099年 year2=1; year3=0; year4=2;} }}}} } //////////////////////////////////////////// } } } } } /////////////////////////////////////////////////閃爍標志位 dpi++; //dps=0 的占空比為 3:1 if(dpi==5) { dpi=0; dps++; if(dps==2) {dps=0;} }// // if(int1==0) //p3.3調狀態 每秒看一次 // d2=0; // }//dpi=5 /////////////////////////////////////////////////////p3.3調狀態 if(dpi==0 || dpi==2 || dpi==4) //0.2s 掃描一次 { if(int1==0) //p3.3調狀態 { d2=0; if(slient==1) { if(state==8) state=1; else state++; }//slient==1 else { slient=1; ET1=1;} // for(d1=1000000;d1>0;d1--); } //調狀態 int1==0 ////////////////////////////////////////////////////////////p3.2改時間 if(int0==0) //P3.2調節 { d2=0; if(state==1 || state==2 || state==3) //顯示狀態下按P3.2,進入不顯示狀態,按任意鍵退出。 { if(slient==2) { slient=1; ET1=1;} else slient++; } else if(state==4) // {second=0; if(minl<9) minl++; else { minl=0; if(minh<5) minh++; else { minh=0; } } } else if(state==5) // { if(hour<23) hour++; else hour=0; } else if(state==8) // { /////////////////////////////////////// if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) //1,3,5,7,8,10,12 大 31 { if(day<31) day++; else day=1; } else if(month==4 || month==6 || month==9 || month==11) //4,6,9,11,小30 { if(day<30) day++; else day=1; } else if(month==2) //2月閏年29天 { year=year4*1000+year3*100+year1*10+year1; if((year%4==0&&year%100!=0)||year%400==0) {if(day<29) //閏年 day++; else day=1; } else {if(day<28) //非閏年 day++; else day=1; } } //////////////////////////////////////////// } else if(state==7) // { day=1; if(month<12) month++; else month=1; } else if(state==6) // 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; { day=1; if(year1<9) year1++; else { year1=0; if(year2<9) year2++; else {year1=0; //最高位2099年 year2=1; year3=0; year4=2; } } }//state=6 // for(d0=600000;d0>0;d0--); } //調時 int0 //} } //dpi==0 ,2,4 } //timer0 時間 調時 改狀態 void timer1() interrupt 3 using 3 //display { TH1=(65536-3000)/256; TL1=(65536-3000)%256; //0.006s monthl=tmonthl[month]; monthh=tmonthh[month]; dayl=tdayl[day]; dayh=tdayh[day]; hourl=thourl[hour]; hourh=thourh[hour]; if(slient==1) { if(j<4) j++; else j=1; if(state==1 || state==4 || state==5) //顯示時間 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; { if(j==1) {if(state==4 && dps==0 && int0!=0) // 閃爍,調節時不閃 P1=0x00; else {P1=display[minl]; //p3.5,p3.4,p3.1,p3.0 為勢能端 }} //11XX10 else if(j==2) {if(state==4 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[minh]; }} //11XX01 else if(j==3) {if(state==5 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[hourl]; }} //10XX11 else if(j==4) {if(state==5 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[hourh]; }} //01XX11 } else if(state==2 || state==7 || state==8) //顯示月日 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; { if(j==1) {if(state==8 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[dayl]; //p3.5,p3.4,p3.1,p3.0 為勢能端 }} //11XX10 else if(j==2) {if(state==8 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[dayh]; }} //11XX01 else if(j==3) {if(state==7 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[monthl]; }} //10XX11 else if(j==4) {if(state==7 && dps==0 && int0!=0) // 閃爍 P1=0x00; else {P1=display[monthh]; }} //01XX11 } else if(state==3 || state==6) //顯示年 { if(state==6 && dps==0 && int0!=0) P1=0x00; else {if(j==1) {P1=display[year1]; //p3.5,p3.4,p3.1,p3.0 為勢能端 } //11XX10 3e else if(j==2) {P1=display[year2]; } //11XX01 3d else if(j==3) {P1=display[year3]; } //10XX11 2f else if(j==4) {P1=display[year4]; } //01XX11 1f } } if(j==1) {P3_0=0;P3_1=1;P3_4=1;P3_5=1;} else if(j==2) {P3_0=1;P3_1=0;P3_4=1;P3_5=1;} else if(j==3) {P3_0=1;P3_1=1;P3_4=0;P3_5=1;} else if(j==4) {P3_0=1;P3_1=1;P3_4=1;P3_5=0;} /////////////////////////////////////////////////////////// DP /////////////////////////////////////////////////////////// 1:顯示時間 2:顯示月日 3:顯示年 4:修改分鐘 5:修改時鐘 6:修改年 7:修改月 8:修改日 ; if(dps==1) {if(state==1 || state==2) { if(j==1) //DP,顯示時間,月日 {DP=0;} else if(j==2) {DP=0;} else if(j==3) {DP=1;} else if(j==4) {DP=0;} } else if(state==3) { if(j==1) //DP,顯示年 {DP=0;} else if(j==2) {DP=0;} else if(j==3) {DP=0;} else if(j==4) {DP=0;} } else if(state==4) { if(j==1) //DP,改分鐘 {DP=1;} else if(j==2) {DP=1;} else if(j==3) {DP=0;} else if(j==4) {DP=0;} } else if(state==5) { if(j==1) //DP,改時鐘 {DP=0;} else if(j==2) {DP=0;} else if(j==3) {DP=1;} else if(j==4) {DP=1;} } else if(state==8) { if(j==1) //DP,改日 {DP=0;} else if(j==2) {DP=1;} else if(j==3) {DP=0;} else if(j==4) {DP=0;} } else if(state==7) { if(j==1) //DP,改月 {DP=0;} else if(j==2) {DP=0;} else if(j==3) {DP=0;} else if(j==4) {DP=1;} } else if(state==6) { DP=0; //DP, 改年 }} else //dps==0 DP=0; //////////////////////////////////////////////////////////////////DP } else //slient==0 {P1=0x00;ET1=0;} //省電,關閉顯示器,關閉顯示中斷 } //timer1 顯示