#include <reg52.h> //調用單片機頭文件 #define uchar unsigned char //無符號字符型宏定義 變量范圍0~255 #define uint unsigned int //無符號整型 宏定義 變量范圍0~65535 #include "eeprom52.h" #include "nongli.h" bit flag_200ms ; bit flag_100ms ; sbit beep = P3^7; //蜂鳴器定義 bit flag_beep_en; uint clock_value; //用作鬧鐘用的 sbit dq = P3^2; //18b20 IO口的定義 uint temperature ; //溫度變量 uchar flag_nl; //農歷陽歷顯示標志位 uchar menu_1,menu_2; uchar key_time,flag_value; //用做連加的中間變量 bit key_500ms ; uchar n_nian,n_yue,n_ri; //農歷顯示的函數 #include "ds1302.h" #include "lcd1602.h" /******************把數據保存到單片機內部eeprom中******************/ void write_eeprom() { SectorErase(0x2000); byte_write(0x2000,fen1); byte_write(0x2001,shi1); byte_write(0x2002,open1); byte_write(0x2058,a_a); } /******************把數據從單片機內部eeprom中讀出來*****************/ void read_eeprom() { fen1 = byte_read(0x2000); shi1 = byte_read(0x2001); open1 = byte_read(0x2002); a_a = byte_read(0x2058); } /**************開機自檢eeprom初始化*****************/ void init_eeprom() { read_eeprom(); //先讀 if(a_a!= 1) //新的單片機初始單片機內問eeprom { fen1 = 3; shi1 = 8; open1 = 1; a_a = 1; write_eeprom(); //保存數據 } } /***********************18b20初始化函數*****************************/ void init_18b20() { bitq; dq= 1; //把總線拿高 delay_uint(1); //15us dq= 0; //給復位脈沖 delay_uint(80); //750us dq= 1; //把總線拿高 等待 delay_uint(10); //110us q= dq; //讀取18b20初始化信號 delay_uint(20); //200us dq= 1; //把總線拿高 釋放總線 } /*************寫18b20內的數據***************/ void write_18b20(uchar dat) { uchari; for(i=0;i<8;i++) { //寫數據是低位開始 dq = 0; //把總線拿低寫時間隙開始 dq = dat & 0x01; //向18b20總線寫數據了 delay_uint(5); // 60us dq = 1; //釋放總線 dat >>= 1; } } /*************讀取18b20內的數據***************/ uchar read_18b20() { uchari,value; for(i=0;i<8;i++) { dq = 0; //把總線拿低讀時間隙開始 value >>= 1; //讀數據是低位開始 dq = 1; //釋放總線 if(dq == 1) //開始讀寫數據 value|= 0x80; delay_uint(5); //60us 讀一個時間隙最少要保持60us的時間 } returnvalue; //返回數據 } /*************讀取溫度的值 讀出來的是小數***************/ uint read_temp() { uintvalue; ucharlow; //在讀取溫度的時候如果中斷的太頻繁了,就應該把中斷給關了,否則會影響到18b20的時序 init_18b20(); //初始化18b20 write_18b20(0xcc); //跳過64位ROM write_18b20(0x44); //啟動一次溫度轉換命令 delay_uint(50); //500us init_18b20(); //初始化18b20 write_18b20(0xcc); //跳過64位ROM write_18b20(0xbe); //發出讀取暫存器命令 EA= 0; low= read_18b20(); //讀溫度低字節 value= read_18b20(); //讀溫度高字節 EA= 1; value<<= 8; //把溫度的高位左移8位 value|= low; //把讀出的溫度低位放到value的低八位中 value*= 0.625; //轉換到溫度值小數 returnvalue; //返回讀出的溫度帶小數 } /******************1ms 延時函數*******************/ void delay_1ms(uint q) { uinti,j; for(i=0;i<q;i++) for(j=0;j<120;j++); } /******************寫星期函數*******************/ void write_week(uchar hang,ucharadd,uchar week)//寫星期函數 { if(hang==1) write_com(0x80+add); else write_com(0x80+0x40+add); switch(week) { case 1:write_data('M');//星期數為1時,顯示 write_data('O'); write_data('N'); break; case 2:write_data('T');//星期數據為2時顯示 write_data('U'); write_data('E'); break; case 3:write_data('W');//星期數據為3時顯示 write_data('E'); write_data('D'); break; case 4:write_data('T');//星期數據為4是顯示 write_data('H'); write_data('U'); break; case 5:write_data('F');//星期數據為5時顯示 write_data('R'); write_data('I'); break; case 6:write_data('S');//星期數據為6時顯示 write_data('T'); write_data('A'); break; case 0:write_data('S');//星期數據為7時顯示 write_data('U'); write_data('N'); break; } } /*************時鐘顯示***************/ void init_1602_ds1302() { write_sfm2_ds1302(1,1,shi); //顯示時 write_sfm2_ds1302(1,4,fen); //顯示分 write_sfm2_ds1302(1,7,miao); //顯示秒 write_week(2,12,week); // write_sfm1(1,14,week); //顯示星期 write_sfm3_18B20(1,11,temperature); //顯示溫度 if(flag_nl== 0) //顯示陽歷 { write_sfm2_ds1302(2,2,nian); //顯示年 write_sfm2_ds1302(2,5,yue); //顯示月 write_sfm2_ds1302(2,8,ri); //顯示日 } else //顯示農歷 { write_sfm2_ds1302(2,2,n_nian); //顯示年 write_sfm2_ds1302(2,5,n_yue); //顯示月 write_sfm2_ds1302(2,8,n_ri); //顯示日 } } /*************定時器0初始化程序***************/ void init_time0() { EA = 1; //開總中斷 TMOD= 0X01; //定時器0、工作方式1 ET0 = 1; //開定時器0中斷 TR0 = 1; //允許定時器0定時 } /*************鬧鐘報警函數***************/ void menu_dis() { staticuchar mm,value; if(flag_100ms== 1) //100ms執行一次 { flag_100ms = 0; if(open1 == 1) //如果鬧鐘打開 { if((miao== 0) && (fen == fen1) && (shi == shi1)) { flag_beep_en = 1; //有報警 打開蜂鳴器響的標志位 } if(flag_beep_en== 1) //鬧鐘以被打開 { clock_value++; if(clock_value <= 30) beep= ~beep; //蜂鳴器叫3秒 else if(clock_value > 30) { beep= 1; //蜂鳴器停1秒 if(clock_value> 40) { clock_value = 0; } } // 1 分鐘后自動關閉鬧鐘 value ++; if(value >= 10) { value= 0; mm++; if(mm>= 60) { mm = 0; flag_beep_en = 0; beep = 1; } } } } } } /********************獨立按鍵程序*****************/ uchar key_can; //按鍵值 void key() //獨立按鍵程序 { staticuchar key_new; key_can= 20; //按鍵值還原 P3|= 0x78; //對應的按鍵IO口輸出為1 if((P3& 0x78) != 0x78) //按鍵按下 { delay_1ms(1); //按鍵消抖動 if(((P3 & 0x78) != 0x78) &&(key_new == 1)) { //確認是按鍵按下 key_new= 0; switch(P3& 0x78) { case 0x70: key_can = 4; break; //得到按鍵值 case 0x68: key_can = 3; break; //得到按鍵值 case 0x58: key_can = 2; break; //得到按鍵值 case 0x38: key_can = 1; break; //得到按鍵值 } // write_sfm2(1,0,key_can); //顯示按鍵值 } } else key_new = 1; } /**********************設置函數************************/ void key_with() { if(key_can== 1) //設置鍵 { menu_1++; if(menu_1 == 1) //設置時間 { menu_2= 1; write_string(1,0," - - W: "); write_string(2,0,"20 - - "); } if(menu_1 == 2) //設置鬧鐘 { menu_2= 1; write_string(1,0," set clock "); write_string(2,0," Y 00:00 "); } if(menu_1 > 2) //回到正常顯示 { menu_1= 0; write_guanbiao(1,2,0); //關閉光標 init_1602_dis_csf(); //初始化液晶顯示 } } if(key_can== 2) //選擇鍵 { flag_200ms = 1; if(menu_1 == 1) //設置時間 { menu_2++; if(menu_2> 7) menu_2 = 1; } if(menu_1 == 2) //設置鬧鐘 { menu_2++; if(menu_2> 3) menu_2 = 1; } } if(menu_1== 1) { if(menu_2 == 1) //設置時 { if(key_can== 3) //加 { shi+=0x01; if((shi & 0x0f) >= 0x0a) shi= (shi & 0xf0) + 0x10; if(shi >= 0x24) shi= 0; } if(key_can== 4) //減 { if(shi == 0x00) shi= 0x24; if((shi & 0x0f) == 0x00) shi= (shi | 0x0a) - 0x10; shi -- ; } } if(menu_2 == 2) //設置分 { if(key_can== 3) //加 { fen+=0x01; if((fen & 0x0f) >= 0x0a) fen= (fen & 0xf0) + 0x10; if(fen >= 0x60) fen= 0; } if(key_can== 4) //減 { if(fen == 0x00) fen= 0x5a; if((fen & 0x0f) == 0x00) fen= (fen | 0x0a) - 0x10; fen -- ; } } if(menu_2 == 3) //設置秒 { if(key_can== 3) //加 { miao+=0x01; if((miao & 0x0f) >= 0x0a) miao= (miao & 0xf0) + 0x10; if(miao >= 0x60) miao= 0; } if(key_can== 4) //減 { if(miao == 0x00) miao= 0x5a; if((miao & 0x0f) == 0x00) miao= (miao | 0x0a) - 0x10; miao -- ; } } if(menu_2 == 4) //設置星期 { if(key_can== 3) //加 { week+=0x01; if((week & 0x0f) >= 0x0a) week= (week & 0xf0) + 0x10; if(week >= 0x08) week= 1; } if(key_can== 4) //減 { if(week == 0x01) week= 0x08; if((week & 0x0f) == 0x00) week= (week | 0x0a) - 0x10; week -- ; } } if(menu_2 == 5) //設置年 { if(key_can== 3) //加 { nian+=0x01; if((nian & 0x0f) >= 0x0a) nian= (nian & 0xf0) + 0x10; if(nian >= 0x9a) nian= 1; } if(key_can== 4) //減 { if(nian == 0x01) nian= 0x9a; if((nian & 0x0f) == 0x00) nian= (nian | 0x0a) - 0x10; nian -- ; } } if(menu_2 == 6) //設置月 { if(key_can== 3) //加 { yue+=0x01; if((yue & 0x0f) >= 0x0a) yue= (yue & 0xf0) + 0x10; if(yue >= 0x13) yue= 1; } if(key_can== 4) //減 { if(yue == 0x01) yue= 0x13; if((yue & 0x0f) == 0x00) yue= (yue | 0x0a) - 0x10; yue -- ; } } if(menu_2 == 7) //設置日 { if(key_can== 3) //加 { ri+=0x01; if((ri& 0x0f) >= 0x0a) ri = (ri & 0xf0) + 0x10; if(ri>= 0x32) ri = 0; } if(key_can== 4) //減 { if(ri == 0x01) ri= 0x32; if((ri & 0x0f) == 0x00) ri= (ri | 0x0a) - 0x10; ri -- ; } } write_sfm2_ds1302(1,2,shi); //顯示時 write_sfm2_ds1302(1,5,fen); //顯示分 write_sfm2_ds1302(1,8,miao); //顯示秒 write_sfm1(1,14,week); //顯示星期 write_sfm2_ds1302(2,3,nian); //顯示年 write_sfm2_ds1302(2,6,yue); //顯示月 write_sfm2_ds1302(2,9,ri); //顯示日 switch(menu_2) // 光標顯示 { case1: write_guanbiao(1,2,1); break; case2: write_guanbiao(1,5,1); break; case3: write_guanbiao(1,8,1); break; case4: write_guanbiao(1,14,1); break; case5: write_guanbiao(2,3,1); break; case6: write_guanbiao(2,6,1); break; case7: write_guanbiao(2,9,1); break; } write_time(); //把時間寫進去 } /***************設置鬧鐘*********************/ if(menu_1== 2) { if(menu_2 == 1) //設置鬧鐘開關 { if(key_can== 3) { open1 = 1; //鬧鐘開 } if(key_can== 4) { open1 = 0; //鬧鐘關 } } if(menu_2 == 2) //設置鬧鐘時 { if(key_can== 3) //加 { shi1+=0x01; if((shi1 & 0x0f) >= 0x0a) shi1= (shi1 & 0xf0) + 0x10; if(shi1 >= 0x24) shi1= 0; } if(key_can== 4) //減 { if(shi1 == 0x00) shi1= 0x5a; if((shi1 & 0x0f) == 0x00) shi1= (shi1 | 0x0a) - 0x10; shi1 -- ; } } if(menu_2 == 3) //設置秒 { if(key_can== 3) //加 { fen1+=0x01; if((fen1 & 0x0f) >= 0x0a) fen1= (fen1 & 0xf0) + 0x10; if(fen1 >= 0x60) fen1= 0; } if(key_can== 4) //減 { if(fen1 == 0x00) fen1= 0x5a; if((fen1 & 0x0f) == 0x00) fen1= (fen1 | 0x0a) - 0x10; fen1 -- ; } } if(open1 == 1) write_string(2,4,"Y"); else write_string(2,4,"N"); write_sfm2_ds1302(2,7,shi1); //顯示鬧鐘時 write_sfm2_ds1302(2,10,fen1); //顯示鬧鐘分 switch(menu_2) // 光標顯示 { case1: write_guanbiao(2,4,1); break; case2: write_guanbiao(2,7,1); break; case3: write_guanbiao(2,10,1); break; } write_eeprom(); //保存鬧鐘時間 } } /*****************主函數********************/ void main() { beep= 0; //開機叫一聲 delay_1ms(150); P0= P1 = P2 = P3 = 0xff; //單片機IO口初始化為1 init_time0(); //初始化定時器 init_ds1302(); //ds1302初始化 init_1602(); //lcd1602初始化 init_1602_dis_csf();//lcd1602初始化顯示 init_eeprom(); //開始初始化保存的數據 temperature= read_temp(); //先讀出溫度的值 delay_1ms(650); temperature= read_temp(); //先讀出溫度的值 while(1) { key(); //按鍵程序 if(key_can < 10) { if(flag_beep_en== 0) //只有鬧鐘關了的時候才能進入設置 key_with(); else { flag_beep_en = 0; //按下任意鍵可關閉鬧鐘 beep = 1; clock_value = 0; read_time(); } if(menu_1== 0) { if(key_can == 4) //減鍵 { flag_nl= ~flag_nl; //切換農歷和陽歷的顯示標志位 if(flag_nl== 0) write_string(2,0,"2013"); else write_string(2,0,"N "); } } } if(flag_200ms == 1) { flag_200ms= 0; if(menu_1== 0) { read_time(); //讀時間 temperature = read_temp(); //先讀出溫度的值 init_1602_ds1302(); //顯示時鐘 } } menu_dis(); //鬧鐘報警函數 delay_1ms(1); } } /**************定時器0中斷程序*****************/ void time0() interrupt 1 { staticuchar value; TH0= 0X3C; TL0= 0XB0; //50ms value++; if((value% 2) == 0) //100ms flag_100ms = 1; if(value>= 6) //200ms { value = 0; flag_200ms = 1; } }
|