當調整萬年歷日期時,星期會進行自動調整;每月分大小月,每年二月分閏月和平月;基本完美實現了萬年歷和電子時鐘的功能。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (14.91 KB, 下載次數: 40)
下載附件
2018-10-22 15:05 上傳
單片機源程序如下:
- #include<reg52.h>//lcd1602 數字鐘 可調整時間和日期
- #define uint unsigned int
- #define uchar unsigned char
- //lcd_data=P0
- //位定義
- sbit lcdrs=P2^2;
- sbit lcdrw=P2^1;
- sbit lcden=P2^0;
- sbit k1=P3^3;//mod
- sbit k2=P3^2;//+
- sbit k3=P3^1;//-
- //函數聲明
- uchar i,t=0,k1num=0;//t為中斷次數計數,k1num為k1按下的次數
- uint year=2008;//year年
- char h=9,m=9,s=0,w=5,month=2,day=28;//h時,m分,s秒,w星期,year年,month月,day日
- char CC,YY,MM,DD,WW; //CC為世紀數-1;YY為年份后兩個數字;MM為月份,DD是日數,1月和2月要按上一年的13月和14月來算,這時C和y均按上一年取值。
- uchar code table1[]={" 2008-02-28 THU "};//日期
- uchar code table2[]={" 09:09:00 "};//時間
- //延時z ms
- void delay(uchar z)
- {
- uchar x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- void write_com(uchar com)
- {
- lcdrs=0;
- lcdrw=0;
- P0=com;
- delay(10);
- lcden=1;
- delay(10);
- lcden=0;
- }
- //lcd寫數據
- void write_dat(uchar dat)
- {
- lcdrs=1;
- lcdrw=0;
- P0=dat;
- delay(10);
- lcden=1;
- delay(10);
- lcden=0;
- }
- void Monday(void)
- {
- write_dat('M');
- write_dat('O');
- write_dat('N');
- }
- void Tuesday(void)
- {
- write_dat('T');
- write_dat('U');
- write_dat('E');
- }
- void Wednesday(void)
- {
- write_dat('W');
- write_dat('E');
- write_dat('D');
- }
- void Thursday(void)
- {
- write_dat('T');
- write_dat('H');
- write_dat('U');
- }
- void Friday(void)
- {
- write_dat('F');
- write_dat('R');
- write_dat('I');
- }
- void Saturday(void)
- {
- write_dat('S');
- write_dat('A');
- write_dat('T');
- }
- void Sunday(void)
- {
- write_dat('S');
- write_dat('U');
- write_dat('N');
- }
- void display_week(uchar week)//星期顯示
- {
- write_com(0x80+12);
- switch(week)
- {
- case 1:Monday();break;
- case 2:Tuesday();break;
- case 3:Wednesday();break;
- case 4:Thursday();break;
- case 5:Friday();break;
- case 6:Saturday();break;
- case 7:Sunday();break;
- }
- }
- void change_week(uint year,uchar month,uchar day)
- {
- CC=year/100-1;
- YY=year%100;
- MM=month;
- if(month==1)
- {
- MM=13;
- YY--;
- }
- if(month==2)
- {
- MM=14;
- YY--;
- }
- DD=day;
- WW=(CC/4) - 2*CC + YY + (YY/4) + (13 * (MM+1) / 5) + DD - 1;
- w=WW%7;
- if(w==0)
- w=7;
- w--;
- if(w==0)
- w=7;
- display_week(w);
- }
- //lcd初始設置
- void init(void)
- {
- lcden=0;
- write_com(0x38); //8位數據接口,16x2行顯示,5x10點陣字符
- write_com(0x0c); //顯示開,光標關,閃爍關
- write_com(0x06); //當讀或寫一個字符后,地址指針加一且光標加
- write_com(0x01); //清屏
- write_com(0x80); //0x80-1000 0000因為寫入顯示地址時要求最高位D7恒定為高電平1
- TMOD=0x01; //選擇T0計數器工作在方式1,65535個脈沖
- TH0=0x3c;TL0=0xb0;//50ms 裝初值
- EA=1; ET0=1; //CPU開啟總中斷 允許T0定時器
- TR0=1; //啟動定時器T0工作
- write_com(0x80);//第一行
- for(i=0;i<15;i++)
- {write_dat(table1[i]);delay(5);}
- write_com(0x80+0x40);//第二行
- for(i=0;i<11;i++)
- {write_dat(table2[i]);delay(5);}
- }
- void display_time(uchar ad,uchar time)//兩位的時間顯示(時分秒)
- {
- uchar a,b;
- a=time/10;b=time%10;
- write_com(0x80+0x40+ad); //數據第二行開頭
- write_dat(0x30+a);
- write_dat(0x30+b);
- }
- void display_date1(uchar ad,uchar time)//兩位的時間顯示(月日)
- {
- uchar a,b;
- a=time/10;b=time%10;
- write_com(0x80+ad); //數據第一行開頭
- write_dat(0x30+a);
- write_dat(0x30+b);
- }
- void display_date(uint nian)//日期顯示
- {
- uint y1,y2,y3,y4; //四位顯示年份
- y1=nian/1000; //千位
- y2=nian%1000/100; //百位
- y3=nian%1000%100/10; //十位
- y4=nian%1000%100%10; //個位
- write_com(0x80+1);
- write_dat(0x30+y1);
- write_dat(0x30+y2);
- write_dat(0x30+y3);
- write_dat(0x30+y4);
- }
- void keyscan(void)//按鍵掃描
- {
- if(k1==0) //按下調整按鍵
- {
- delay(10);
- k1num++;t=0; //關閉T0定時器
- while(!k1); //k1不彈起來,則死循環
- if(k1num==1)
- {TR0=0; write_com(0x80+0x40+11);write_com(0x0f);}//s
- if(k1num==2)
- {write_com(0x80+0x40+8);}//m
- if(k1num==3)
- {write_com(0x80+0x40+5);}//h
- if(k1num==4)
- {write_com(0x80+14);}//week
- if(k1num==5)
- {write_com(0x80+10);}//day
- if(k1num==6)
- {write_com(0x80+7);} //光標開始閃爍}//month
- if(k1num==7)
- {write_com(0x80+4);}//year
- if(k1num==8)
- {k1num=0;write_com(0x0c);TR0=1;}
- }
- if(k1num!=0)
- {
- if(k2==0) //加+ P2.2接口
- {
- delay(5);
- if(k2==0)
- {
- while(!k2);
- if(k1num==1)
- {
- s++;
- if(s==60)
- s=0;
- display_time(10,s);
- write_com(0x80+0x40+11);
-
- }
- if(k1num==2)
- {
- m++;
- if(m==60)
- m=0;
- display_time(7,m);
- write_com(0x80+0x40+8);
-
- }
- if(k1num==3)
- {
- h++;
- if(h==24)
- h=0;
- display_time(4,h);
- write_com(0x80+0x40+5);
- }
- if(k1num==4)
- {
- w++;
- if(w==8)
- w=1;
- change_week(year,month,day);
- write_com(0x80+14);
- }
- if(k1num==5)
- {
- day++;
- if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) //大月(31天)
- {
- if(day==32)
- day=1;
- }
- if(month==4||month==6||month==9||month==11) //小月(30天)
- {
- if(day==31)
- day=1;
- }
- if(month==2&&(year%4==0&&year%100!=0)) //閏年(29天)(能被4整除,不能被100整除)
- {
- if(day==30)
- day=1;
- }
- if(month==2&&(year%4==0&&year%100!=0)==0) //非閏年(28天)(能被4整除,不能被100整除)
- {
- if(day==29)
- day=1;
- }
- change_week(year,month,day);
- display_date1(9,day);
- write_com(0x80+10);
- }
- if(k1num==6)
- {
- month++;
- if(month==13)
- month=1;
- change_week(year,month,day);
- display_date1(6,month);
- write_com(0x80+7);
- }
- if(k1num==7)
- {
- year++;
- change_week(year,month,day);
- display_date(year);
- write_com(0x80+4);
- }
- }
- }
- if(k3==0) //減- P2.1接口
- {
- delay(10);
- if(k3==0)
- {
- while(!k3);
- if(k1num==1)
- {
- s--;
- if(s==-1)
- s=59;
- display_time(10,s);
- write_com(0x80+0x40+11);
- }
- if(k1num==2)
- {
- m--;
- if(m==-1)
- m=59;
- display_time(7,m);
- write_com(0x80+0x40+8);
- }
- if(k1num==3)
- {
- h--;
- if(h==-1)
- h=23;
- display_time(4,h);
- write_com(0x80+0x40+5);
- }
- if(k1num==4)
- {
- w--;
- if(w==0)
- w=7;
- change_week(year,month,day);
- write_com(0x80+14);
- }
- if(k1num==5)
- {
- day--;
- if(day==0)
- {
- if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) //大月(31天)
- {
- day=31;
- }
- if(month==4||month==6||month==9||month==11) //小月(30天)
- {
- day=30;
- }
- if(month==2&&(year%4==0&&year%100!=0)) //閏年(29天)(能被4整除,不能被100整除)
- {
- day=29;
- }
- if(month==2&&(year%4==0&&year%100!=0)==0) //非閏年(28天)(能被4整除,不能被100整除)
- {
- day=28;
- }
- }
- change_week(year,month,day);
- display_date1(9,day);
- write_com(0x80+10);
-
- }
- if(k1num==6)
- {
- month--;
- if(month==0)
- month=12;
- change_week(year,month,day);
- display_date1(6,month);
- write_com(0x80+7);
- }
- if(k1num==7)
- {
- year--;
- change_week(year,month,day);
- display_date(year);
- write_com(0x80+4);
- }
- }
- }
- }
- if(k1num==0)
- {
- display_time(10,s);//s
- display_time(7,m);//m
- display_time(4,h);//h
- change_week(year,month,day);//week
- display_date1(9,day);//day
- display_date1(6,month);//month
- display_date(year);//year
- }
- }
- void main(void)//主函數
- {
- init();
- while(1)
- {
- keyscan();
- }
- }
- void timer0() interrupt 1//定時器T0中斷函數
- {
- t++;
- TH0=0x3c;TL0=0xb0;//50ms
- if(t==20)
- {s++;t=0;}
- if(s==60)
- {m++;s=0;}
- if(m==60)
- {h++;m=0;}
- if(h==24)
- {w++;day++;h=0;}
- if(w==8)
- {w=1;}
- if(day==32||day==31||day==30||day==29)
- {
- if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) //大月(31天)
- {
- day=1;
- month++;
- }
- if(month==4||month==6||month==9||month==11) //小月(30天)
- {
- day=1;
- month++;
- }
- if(month==2&&(year%4==0&&year%100!=0)) //閏年(29天)(能被4整除,不能被100整除)
- {
- day=1;
- month++;
- }
- if(month==2&&(year%4==0&&year%100!=0)==0) //非閏年(28天)(能被4整除,不能被100整除)
- {
- day=1;
- month++;
- }
- }
- if(month==13)
- {
- year++;
- month=1;
- }
- }
復制代碼
0.png (45.6 KB, 下載次數: 41)
下載附件
2018-10-22 15:05 上傳
所有資料51hei提供下載:
電子時鐘.rar
(40.17 KB, 下載次數: 142)
2018-10-22 05:46 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|