有詳盡的注釋,有興趣的同學可以焊接一個實物燒進去試試,因為不用RTC芯片也不用擔心換紐扣電池,12MHZ的晶振帶軟件補償日誤差可以調節到1S以內。調節方法就是算出每誤差1S的情況然后改buchang參數的值就可以了。因為手頭只有一個多余的DHT11溫濕度了所以用18B20的溫度和DHT11濕度,實際上溫度精度很高,濕度也湊合吧,如果那天有了更好的濕度傳感器再改改濕度程序。
單片機源程序如下:
- #include <reg52.h>
- typedef unsigned int u16;
- typedef unsigned char u8;
- sbit k2=P3^2; //K1 K2 K3 K4按鍵接口,建議從左到右接K1-K4
- sbit k1=P3^5;
- sbit k3=P3^3;
- sbit k4=P3^4;
- sbit DQ=P3^6;
- sbit beep=P1^6;
- sbit Data=P2^0; //有源蜂鳴器在P16口
- sbit lcden=P1^4; //LCD1602接口定義
- sbit lcdrs=P1^0;
- sbit lcdrw=P2^6;
- sbit bg=P2^7; //背光變量接入LCD1602的K極,通過bg的高低電平就可控制自動熄滅與點亮
- u8 k,e,d,o=1,p=1,temp,nxflag=0,mbflag=0,tianmax;
- float temperature; //溫度變量,18B20接收時為浮點數
- u8 miao1,miao2,fen1,fen2,shi1,shi2,tian1,tian2,wk,tem1,tem2,tem3,wendufu;
- u8 day=1,mon=1,day1,day2,yue1,yue2,mbw,n=0,m=0,beiguang,RH,RL,TH,TL,tempH,tempL;
- u8 se1,se2,mon1,mon2,hou1,hou2,min1,min2,MB2,nian1,nian2,nian3,nian4;
- u16 y,MB1;
- u16 temper,buchang,tempwarn=0,tempwarn1=500; //tempwarn為溫度下限,1為溫度上限
- u8 code set[]={"NaoZhong Status"}; //上電后傻瓜調節模塊
- u8 code tempwarng[]={"Wendu Waring!"};
- u8 code temmin[]={"Min"};
- u8 code temmax[]={"Max"};
- u8 code naozhongON[]={" ON"};
- u8 code naozhongOFF[]={"OFF"};
- u8 code setsucces[]={"Set Success!"};
- u8 code thanks[]={"Welcome to use !"};
- u8 code thanksu[]={"thanks for using"};
- u8 code make[]={"Designed by LY"};
- u8 code MB[]={"Stopwatch"};
- u8 code week1[]={"[MON]"};
- u8 code week2[]={"[TUE]"};
- u8 code week3[]={"[WED]"};
- u8 code week4[]={"[THU]"};
- u8 code week5[]={"[FRI]"};
- u8 code week6[]={"[SAT]"};
- u8 code week7[]={"[SUN]"};
- void delay(unsigned int z) //定義延時函數
- {
- unsigned int x,y;
- for(x=z;x>0;x--)
- for(y=1;y>0;y--);
- }
- void DHT11_delay_us(u8 n)
- {
- while(--n);
- }
- void DHT11_delay_ms(u16 z) //定義DHT11延遲函數
- {
- u16 i,j;
- for(i=z;i>0;i--)
- for(j=110;j>0;j--);
- }
- void DHT11_start()
- {
- Data=1;
- DHT11_delay_us(2);
- Data=0;
- DHT11_delay_ms(20); //延時18ms以上
- Data=1;
- DHT11_delay_us(30);
- }
- u8 DHT11_rec_byte() //接收一個字節
- {
- u8 i,dat=0;
- for(i=0;i<8;i++) //從高到低依次接收8位數據
- {
- while(!Data); //等待50us低電平過去
- DHT11_delay_us(8); //延時60us,如果還為高則數據為1,否則為0
- dat<<=1; //移位使正確接收8位數據,數據為0時直接移位
- if(Data==1) //數據為1時,使dat加1來接收數據1
- dat+=1;
- while(Data); //等待數據線拉低
- }
- return dat;
- }
- void DHT11_receive() //接收40位的數據
- {
- u8 R_H,R_L,T_H,T_L,revise;
- DHT11_start();
- if(Data==0)
- {
- while(Data==0); //等待拉高
- DHT11_delay_us(40); //拉高后延時80us
- R_H=DHT11_rec_byte(); //接收濕度高八位
- R_L=DHT11_rec_byte(); //接收濕度低八位
- T_H=DHT11_rec_byte(); //接收溫度高八位
- T_L=DHT11_rec_byte(); //接收溫度低八位
- revise=DHT11_rec_byte(); //接收校正位
- DHT11_delay_us(25); //結束
- if((R_H+R_L+T_H+T_L)==revise) //校正
- {
- RH=R_H;
- RL=R_L;
- TH=T_H;
- TL=T_L;
- }
- }
- }
- void beepon() //PWM(如果你是無源蜂鳴器,這里寫PWM函數)
- { //當前為有源蜂鳴器,有源蜂鳴器無需更改
- beep=0;
- delay(1200);
- beep=1;
- }
- void write_nian(); //預定義
- void write_yue();
- void write_tian();
- void write_shi();
- void write_fen();
- void write_miao();
- void write_week();
- void zhuanhuan();
- void write_temp();
- void write_nz();
- void nzON();
- void write_setsuccess();
- void beiguangpd();
- void write_com(u8 com) //LCD1602初始化程序,了解1602時序圖后新手的話可以直接照搬使用
- {
- lcdrs=0;
- P0=com;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void write_data(u8 date)
- {
- lcdrs=1;
- P0=date;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void init()
- {
- lcdrw=0;
- lcden=0;
- write_com(0x38);
- write_com(0x0c);
- write_com(0x06);
- write_com(0x01);
- write_com(0x80+0x10);
- }
- void Timer0Init() //定時器0工作方式1 中斷初始化,923位12M晶振在KEIL仿真后的計算結果
- {
- TMOD=0X01;
- TH0=(65535-901)/256;
- TL0=(65535-901)%256;
- ET0=1; //打開定時器0中斷允許位
- EA=1; //打開總中斷允許
- TR0=1; //打開 定時器0,開始計時
- }
- Init_DS18B20(void) //DS18B20初始化與時序圖程序,仿真時溫度問題改進這個初始化程序就解決了
- {
- DQ=1;
- delay(70);
- DQ=0;
- delay(485);
- DQ=1;
- delay(50);
- }
- ReadOneChar(void) //18B20讀一個字節
- {
- unsigned char i=0;
- unsigned char dat=0;
- for (i=8;i>0;i--)
- {
- DQ=1;
- delay(1);
- DQ=0;
- dat>>=1;
- DQ=1;
- if(DQ)
- dat|=0x80;
- delay(4);
- }
- return(dat);
- }
- WriteOneChar(unsigned char dat) //18B20寫一個字節
- {
- unsigned char i=0;
- for(i=8;i>0;i--)
- {
- DQ=0;
- DQ=dat&0x01;
- delay(5);
- DQ=1;
- dat>>=1;
- }
- delay(4);
- }
- ReadTemperature(void) //讀取溫度函數定義,返回值為浮點數
- {
- Init_DS18B20();
- WriteOneChar(0xcc);
- WriteOneChar(0x44);
- delay(125);
- Init_DS18B20();
- WriteOneChar(0xcc);
- WriteOneChar(0xbe);
- tempL=ReadOneChar();
- tempH=ReadOneChar();
- if(tempH>0x7f)
- {
- tempH=~tempH;
- tempL=~tempL+1;
- wendufu=1;
- }
- else
- wendufu=0;
- temperature=(((tempH*256)+tempL)*0.0625)*10;
- delay(200);
- return(temperature);
- }
- void welcome() //定義歡迎函數
- { static u8 i;
- init(); //初始化1602
- delay(5000);
- for(i=0;i<16;i++)
- {
- write_com(0x80+i);
- write_data(thanks[i]);
- delay(4000);
- }
- delay(50000);
- for(i=0;i<14;i++)
- {
- write_com(0x81+0x40+i);
- write_data(make[i]);
- delay(4000);
- }
- delay(50000);
- delay(50000);
- }
- void pdtian1() //PD在上電后設置完畢主界面處的天數判斷
- {
- if((p==1||p==3)||(p==5||p==7)||(p==8||p==10)||p==12)
- tianmax=31;
- if((p==4||p==6)||(p==9||p==11))
- tianmax=30;
- if(p==2)
- {
- if(((y%4==0)&&(y%100!=0))||(y%400==0))
- tianmax=29;
- else
- tianmax=28;
- }
- }
- void pdxingqi1() //PD在上電后設置完畢至主界面處的星期判斷
- {
- static char c,yi,mt,xwk1,xwk2,xwk3;
- static int xwk,yn,xwk4;
- yn=y;
- if(p==1||p==2)
- { yn=yn-1;
- mt=p+12;
- }
- else
- mt=p;
- yi=yn%100;
- c=yn/100;
- xwk1=yi+(yi/4);
- xwk2=c/4;
- xwk3=2*c;
- xwk4=(26*mt+26)/10;
- xwk=xwk1+xwk2-xwk3+xwk4+o-1;
- while(xwk<0)
- {xwk+=7; }
- wk=xwk%7;
- }
- void Display() //定義主程序 顯示部分函數模塊
- { static u16 xunhuan;
- RH=RH%100;
- write_nian(); //1602寫入顯示年
- write_com(0x84);
- write_data('-');
- write_yue(); //寫入月
- write_com(0x87);
- write_data('-');
- write_com(0x88);
- write_tian(); //寫入天
- write_week();
- write_shi();
- write_com(0x82+0x40);
- write_data(':');
- write_fen();
- write_com(0x85+0x40);
- write_data(':');
- write_miao(); //寫入溫度,溫度TEM1與2與3是溫度的三位數
- xunhuan++;
- if(xunhuan<180)
- {if(wendufu==1)
- {
- if((temper/100)!=0)
- {
- write_com(0x89+0x40);
- write_data('-');
- write_com(0x8a+0x40);
- write_data(tem1);
- }
- else
- {
- write_com(0x89+0x40);
- write_data(' ');
- write_com(0x8a+0x40);
- write_data('-');
- }
- }
- else
- {
- write_com(0x89+0x40);
- write_data(' ');
-
- if((temper/100)!=0)
- {
- write_com(0x8a+0x40);
- write_data(tem1);
- }
- else
- {
- write_com(0x8a+0x40);
- write_data(' ');
- } }
- write_com(0x8b+0x40);
- write_data(tem2);
- write_com(0x8c+0x40);
- write_data('.');
- write_com(0x8d+0x40);
- write_data(tem3);
- write_com(0x8e+0x40);
- write_data(0xdf);
- write_com(0x8f+0x40);
- write_data('C');
- }
- if(xunhuan>180)
- {
- write_com(0x89+0x40);
- write_data(' ');
- write_com(0x8a+0x40);
- write_data(' ');
- write_com(0x8b+0x40);
- write_data(RH/10+0x30);
- write_com(0x8c+0x40);
- write_data(RH%10+0x30);
- write_com(0x8d+0x40);
- write_data('%');
- write_com(0x8e+0x40);
- write_data('R');
- write_com(0x8f+0x40);
- write_data('H');
- }
- if(xunhuan==360)
- xunhuan=0;
- }
- void NZdisplay() //定義鬧鐘模塊
- {
- static u8 nzflag=2,nzwei;
- delay(2000);
- init();
- delay(2000);
- nzON(); //鬧鐘開關選擇模塊
- while(k4) //沒有檢測到K4鍵退出時無限循環
- {
- write_nz(); //寫入鬧鐘模塊
- if(k3==0) //判斷K3鍵是否按下
- {
- delay(5000);
- if(k3==0) //延時消抖
- {beepon(); //響一聲
- if(nxflag==0) //如果NXFLAG為0,鬧鐘為關閉狀態,給其賦值為1,
- nxflag=1;
- else
- nxflag=0;
- }
- nzON(); //判斷鬧鐘的狀態
- }
- if(k1==0) //如果K1鍵按下后
- {
- delay(8000);
- if(k1==0)
- {
- beepon();
- if(nzwei==0) //通過NZWEI來判斷當前光標的位置與設置小時還是分鐘
- nzflag=0;
- if(nzwei==1)
- nzflag=1;
- }
- }
- if(nzflag==0)
- {
- while(1)
- {
- write_com(0x83+0x40); //光標閃爍
- write_data(0xff);
- delay(5000);
- write_nz(); //寫入鬧鐘
- delay(5000);
- if(k2==0) //如果K2為0
- {
- delay(50);
- if(k2==0)
- {
- beepon(); //判斷小時狀態,進行+1
- if(n<23)
- n+=1;
- else
- n=0;
- }
- }
- if(k3==0) //如果K3為0
- {
- delay(50);
- if(k3==0) //判斷小時狀態,進行-1 最大溢出重回最小,最小溢出重回最大
- {
- beepon();
- if(n>0)
- n-=1;
- else
- n=23;
- }
- }
- if(k1==0)
- {
- delay(1000); //如果K1按下,更改NZFLAG,更改鬧鐘光標位
- if(k1==0)
- {
- nzflag=1;
- beepon();
- break;
- }
- }
- if(k4==0) //如果K4按下,退出。給NZFLAG重新賦值為2,取消光標并下次進入不會直接進入光標
- {
- beepon();
- delay(6000);
- nzflag=2;
- nzwei=0;
- break; }
- }
- }
- if(nzflag==1) //如果NZ為1,同上,此時為分鐘調節
- { while(1)
- {
- write_com(0x86+0x40);
- write_data(0xff);
- delay(5000);
- write_nz();
- delay(5000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(m<59)
- m+=1;
- else
- m=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if(m>0)
- m-=1;
- else
- m=59;
- }
- }
- if(k1==0)
- {
- delay(1000);
- if(k1==0)
- {
- beepon();
- nzflag=0;
- break;
- }
- }
- if(k4==0)
- {
- beepon();
-
- delay(6000);
- nzflag=2;
- nzwei=1;
- break; }
- }
- }
- if(k4==0)
- {
- beepon();
- delay(30000);
- break;
- }
- }
- nzflag=2;
- init();
- }
- void temperwaring() //定義溫度警報模塊
- {
- static u8 temflag=2,temwei;
- delay(5000);
- init();
- delay(5000);
- while(k4)
- {
- write_temp(); //寫入溫度
- if(k3==0) //如果K3為0,為其賦值為N0-N0,關閉溫度警報,并且不會閃爍光標
- {
- beepon();
- delay(3000);
- tempwarn=(0X4e-0x30)*100;
- tempwarn1=(0X4e-0x30)*100;
- }
- if(k1==0) //如果K1為0,進入光標位,光標閃爍,根據temwei不同進入不同的初始閃爍位置
- {
- delay(8000);
- if(k1==0)
- {
- beepon();
- if(temwei==0) //為只需單獨打開溫度上限或下限報警時提供方便
- temflag=0;
- if(temwei==1)
- temflag=1;
- }
- }
- if(temflag==0) //和鬧鐘模塊 類似,如果temflag為0的話進入下限調整,否則進入上限調整
- {
- while(1)
- {
- write_com(0x86+0x40);
- write_data(0xff);
- delay(6000);
- write_temp();
- delay(4000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(tempwarn<500) //溫度范圍為精確到小數點后1位,500為50.0度,自己設置每次只調節1度
- tempwarn+=10; //如果需要溫度報警精確到0.1度,請將此處改為1并重新修改界面
- else
- tempwarn=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if(tempwarn>0&&(tempwarn!=(0X4e-0x30)*100)) //K3鍵按下,判斷當在關閉狀態與一般狀態時,溫度閥門下限減1度
- tempwarn-=10;
- else
- tempwarn=500;
- }
- }
- if(k1==0) //如果檢測K1按下,跳出循環,給FLAG重新賦值為1,光標開始在溫度上限處閃爍
- { delay(1000); //并且開始調節溫度上限
- temflag=1;
- beepon();
- break;
- }
- if(k4==0) //如果K4等于0,第一次確定,光標停止閃爍,K2K3不會更改數值
- { //目的是在確定無誤后在下次按下K4時可以直接退出
- beepon();
- delay(6000);
- temflag=2;
- temwei=0;
- break; }
- }
- }
- if(temflag==1) //進入溫度修改上限部分,同溫度修改下限
- { while(1)
- {
- write_com(0x89+0x40);
- write_data(0xff);
- delay(6000);
- write_temp();
- delay(4000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(tempwarn1<500)
- tempwarn1+=10;
- else
- tempwarn1=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if((tempwarn1>0)&&(tempwarn1!=(0X4e-0x30)*100))
- tempwarn1-=10;
- else
- tempwarn1=500;
- }
- }
- if(k1==0)
- {beepon();
- delay(1000);
- temflag=0;
- break;
- }
- if(k4==0)
- {
- beepon();
-
- delay(6000);
- temflag=2;
- temwei=1;
- break; }
- }
- }
- if(k4==0) //當光標不閃爍時,按下K4鍵,直接退出
- {
- beepon();
- delay(30000);
- break;
- }
- }
- temflag=2; //temflag重新賦值為2,目的是確保下次進入不會直接進入光標調節模塊
- init();ET0=1; //這樣就可以方便的快速關閉溫度報警及快速設置上下限
-
- }
- void miaobiaods() //定義秒表顯示模塊
- {
- static u8 i,times;
- delay(1000);
- init();
- delay(10000);
- while(1)
- {
- if(MB1==10000) //MB1位16位數,所以秒表在0.00-100.00的計數范圍使用MB1,超出后清0累加MB2
- {
- MB1=0;MB2++;
- }
- if(MB2==100) //如果秒表超出了10000秒,直接清零,若想修改更大秒表范圍請將MB2定義為16位數再修改,并修改顯示界面
- {MB2=0;MB1=0;
- mbflag=0;
- }
- for(i=0;i<9;i++) //1602循環顯示STOPWATCH
- {
- write_com(0x84+i);
- write_data(MB[i]);
- }
- write_com(0x83+0x40); //顯示秒表運行狀態模塊
- write_data(times/10+0x30);
- write_com(0x84+0x40);
- write_data(times%10+0x30); //TIMES為計數部分,不為0時每次暫停可以計數一次
- write_com(0x86+0x40);
- write_data(MB2/10+0x30);
- write_com(0x87+0x40); //秒表高位MB2與低位MB1轉換為16進制數顯示
- write_data(MB2%10+0x30);
- write_com(0x88+0x40);
- write_data('.');
- write_data((MB1/1000)+0x30);
- write_com(0x8a+0x40);
- write_data(MB1%1000/100+0x30);
- write_com(0x8b+0x40);
- write_data('.');
- write_com(0x8c+0x40);
- write_data(MB1%1000%100/10+0x30);
- write_com(0x8d+0x40);
- write_data(MB1%1000%100%10+0x30);
- if(k1==0) //由于秒表對精度要求很高,必須直接中斷不能延時
- {mbflag=1; //因此也不能只用一個K1進行開始于暫停
- beepon(); } //此時按下K1鍵為打開秒表,會有立刻的響鈴以便直觀表明計時開始
- if(k2==0) //和以上原因一樣,秒表暫停
- {mbflag=0; //按下K2鍵為暫停
- beepon();
- if(MB1!=0) //如果不為0,計次+1
- { delay(40000);
- if(times<99) //計次范圍0-99
- times+=1;
- }
- }
- if(k3==0) //按下K3,秒表數據清0
- {beepon();
- mbflag=0;
- times=0;
- MB1=0;
- MB2=0;
- }
- if(k4==0)
- {beepon(); //K4為0,退出秒表,如果打開秒表也可直接退出,秒表與時間并不沖突
- break;}
- }
- delay(1000);
- init(); //延時初始化,確保時間充足無亂碼
- delay(10000);
- }
- void naozhongfamen() //主界面上判斷是否進入鬧鐘設置界面的模塊
- {
- if(k3==0)
- {
- delay(50000); //如果K3長按,進入鬧鐘
- if(k3==0)
- {
- beepon();
- delay(3000);
- NZdisplay();
- delay(10000);
- write_setsuccess();
- delay(30000);
- init();
- }
- }
- }
- void wendufamen() //主界面上判斷是否進入溫度報警設置界面的模塊
- {
- if(k2==0)
- {
- delay(50000);
- if(k2==0)
- { beepon();
- delay(3000);
- temperwaring();
- delay(10000);
- write_setsuccess();
- delay(30000);
- init();
- }
- }
- }
- void miaobiao() //主界面上判斷是否進入秒表的模塊
- { if(mbflag==1)
- {
- if(MB1>10000)
- {
- MB1=0;MB2++;
- }
- if(MB2==100)
- {MB2=0;MB1=0;
- mbflag=0;
- }
- }
- if(k4==0)
- {
- delay(50000);
- if(k4==0)
- {
- beepon();
- delay(3000);
- miaobiaods();
- delay(10000);
- init();
- }
- }
- }
- void Timer0() interrupt 1 //定義中斷函數,923為12M晶振的精度,如果是11.05M晶振請根據仿真或實測自行改變這個值
- {
- static u16 i;
- TH0=(65535-901)/256;
- TL0=(65535-901)%256;
- i++; //i為秒,不斷累加
- beiguangpd(); //進行背光判斷,確保背光第一時間響應
- if(mbflag==1)
- { //如果檢測到打開秒表了,就開始秒表位累加
- mbw++;
- if(mbw==10)
- {
- mbw=0;
- MB1++;
- }
- }
- if(i==1000) //如果檢測到1000,秒+1
- {
- k++; i=0;
- if(beiguang<60) //如果背光變量小于60,此時背光打開
- beiguang++;
- buchang++;
- DHT11_receive();
- temper=ReadTemperature(); //檢測溫度,檢測周期是1S
- }
- if(k==60) //判斷各個變量,也可將這些放到其他模塊里,但是精度未必會提高
- {
- k=0;
- e++;
- }
- if(buchang==4955) //精度補償部分,不一定適合你的晶振
- {
- buchang=0;k+=1;
- }
- if(e==60)
- {
- e=0;
- d++;
- }
- if(d==24)
- {
- d=0;
- o++;
- if(wk<6)
- wk++;
- else
- wk=0;
- }
- if(o==tianmax+1)
- {
- o=1;
- p++;
- }
- if(p==13)
- {
- p=1;
- y++;
- }
- }
- void bijiao() //比較模塊,也是報警觸發模塊
- {
- static u8 gbflag;
- if(m==e&&n==d) //如果鬧鐘時間相同,開始響鈴,時長1分鐘
- {
- if(gbflag==0) //如果不是在響鈴并按鍵關閉后,才會響鈴
- {
- if(nxflag==1) //如果鬧鐘為開啟狀態響鈴,否則不響
- beepon();
- if(k2==0||k3==0||k4==0) //如果有K2,K3,K4任何一個按鍵觸發,就會將gbflag設置為1,停止響鈴
- gbflag=1; //因為K1鍵快速按下還有快捷粗調暫停1秒的功能,所以沒有K1鍵
- }
- }
- else
- gbflag=0; //響鈴完畢后給gbflag賦值為0;
- if(e==0&&k==0) //整點報時模塊,設置為7到24點整點報時,可改范圍,不會影響休息也比較合適
- {if((d>6&&d<24)||d==0)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100))
- {
- if(wendufu==1)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100)||(tempwarn1!=(0X4e-0x30)*100)) //判斷溫度閥門打開了上限還是下線還是關閉還是上下限同時打開
- {
- if((tempwarn==(0x4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100)) //判斷完畢后只要觸發就會報警
- {
- if(tempwarn1<temper)
- {
- beepon();
-
- }
- }
- if((tempwarn!=(0x4e-0x30)*100)&&(tempwarn1==(0X4e-0x30)*100))
- {
- if(tempwarn>temper)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100))
- {
- if((tempwarn>temper)||(tempwarn1<temper))
- {
- beepon();
-
- }
- }
- }
- }
- void zhuanhuan() //轉換模塊,將時間變量轉換為1602的16位顯示數值
- {
-
- nian1=(y/1000)+0x30;
- nian2=(y%1000/100)+0x30;
- nian3=(y%1000%100/10)+0x30;
- nian4=(y%1000%100%10)+0x30;
- yue1=(p/10)+0x30;
- yue2=(p%10)+0x30;
- tian1=(o/10)+0x30;
- tian2=(o%10)+0x30;
- shi1=(d/10)+0x30;
- shi2 =(d%10)+0x30;
- fen1=(e/10)+0x30;
- fen2=(e%10)+0x30;
- miao1=(k/10)+0x30;
- miao2=(k%10)+0x30;
- tem1=(temper/100)+0x30;
- tem2=(temper%100/10)+0x30;
- tem3=(temper%100%10)+0x30;
- }
- void tiaojie() //光標調節時間模塊
- {
- static u8 flag=0;
- if(k1==0) //檢測到K1按下一段時間后,開始調節光標
- {
- delay(30000);
- if(k1==0)
- {
- beepon(); //因為會關閉中斷并且停秒,所以給軟件補償buchang值清0
- buchang=0;
- while(1)
- {
- ET0=0;
- pdtian1(); //此時中斷已關閉,開始循環判斷
- pdxingqi1(); //判斷天數與星期,比如在將時間調到3月31號后再調到2月
- zhuanhuan();
- if(o>tianmax)
- o=tianmax;
- write_week(); //天數就會自動調節到28日,確保不會超出范圍,并自動調出星期
- write_tian();
- if(k4==0) //如果按下K4,就停止時間光標調節并跳出循環
- {
- beepon(); break;
- }
- if(flag==0) //flag調節位置判斷位
- {
- write_miao();
- delay(5000);
- write_com(0x87+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- { //此時調秒
- beepon();
- if(k<59) k+=1;
- else k=0;
- }
- if(k3==0)
- {
- beepon();
- if(k>0) k-=1;
- else k=59;
- }
- if(k1==0)
- {
- beepon();
- flag+=1; }
- write_miao();
- }
- if(flag==1) //此時調分
- {
- write_fen();
- delay(5000);
- write_com(0x84+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(e<59) e+=1;
- else e=0; }
- if(k3==0)
- {
- beepon();
- if(e>0) e-=1;
- else e=59;
- }
- if(k1==0)
- {
- beepon();
- flag+=1; }
- write_fen();
- }
- if(flag==2) //此時調時
- {
- write_shi();
- delay(5000);
- write_com(0x81+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(d<23) d+=1;
- else d=0;
- }
- if(k3==0)
- {
- beepon();
- if(d>0) d-=1;
- else d=23;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;}
- write_shi();
- }
- if(flag==3) //此時調天 天、月、年會影響星期,所以在這里加入判斷星期模塊
- {
- write_tian();
- delay(5000);
- write_com(0x89);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(o<tianmax)
- o+=1;
- else
- o=1;
- }
- if(k3==0)
- {
- beepon();
- pdtian1();
- if(o>1)
- o-=1;
- else
- o=tianmax;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;
- }
- write_tian();
- }
- if(flag==4)
- {
- write_yue(); //此時調月
- delay(5000);
- write_com(0x86);
- write_data(0xff); //循環閃爍光標
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(p<12)
- p+=1;
- else
- p=1;
- }
- if(k3==0)
- {
- beepon();
- if(p>1)
- p-=1;
- else
- p=12;
- if(o>tianmax)
- o=tianmax;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;
- }
- write_yue();
- }
- if(flag==5)
- {
- write_nian(); //此時調年
- delay(5000);
- write_com(0x83);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(y<9999)
- y+=1;
- else
- y=1;
-
- }
- if(k3==0)
- {
- beepon();
- if(y>0)
- y-=1;
- else
- y=9999;
-
- }
- if(k1==0)
- {
- beepon();
- flag=0;}
- write_nian();
- }
- //調節完畢并且K4確認后打開中斷允許,開始走時
- }
- }
- }
- ET0=1;
-
- }
- void beiguangpd() //背光判斷模塊
- {if(k1==0||k2==0||k3==0|k4==0)
- { if(bg==1) //如果再背光熄滅的情況下 ,按下任何鍵都會打開背光并響鈴
- beepon();
- beiguang=0; //無論是否熄滅,按下都會清零
- }
- if(beiguang==60) //如果檢測到沒有按鍵60S,背光自動熄滅
- bg=1;
- else
- bg=0;
- }
- void main() //主函數
- { bg=0;
- y=2017;p=5;o=25;
- DHT11_receive();
- temper=ReadTemperature();
- welcome(); //歡迎
- NZdisplay(); //斷電后第一個調節鬧鐘
- init();
- Timer0Init(); //初始化定時器,但是沒有打開ET0
- ET0=1;
- init(); //調節完畢后延時初始化并延時足夠時間,確保不會亂碼
- delay(50000);
- while(1) //循環各個模塊且不會沖突
- {
- zhuanhuan();
- bijiao();
- tiaojie();
- naozhongfamen();
- wendufamen();
- miaobiao();
- pdtian1();
- pdxingqi1();
- Display();
- }
- }
- void write_week() //1602寫并顯示星期模塊
- { static u8 i;
- switch (wk)
- {
- case(1):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week1[i]);
- }
- break;
- case(2):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week2[i]);
- }
- break;
- case(3):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week3[i]);
- }
- break;
- case(4):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week4[i]);
- }
- break;
- case(5):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week5[i]);
- }
- break;
- case(6):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week6[i]);
- }
- break;
- case(0):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week7[i]);
- }
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
非RTC多功能萬年歷.zip
(96.67 KB, 下載次數: 184)
2017-5-29 22:10 上傳
點擊文件名下載附件
源程序 下載積分: 黑幣 -5
|