功能說明:
LCD1602液晶顯示年、月、日、時、分、秒、星期、溫度,三個按鍵控制時間日期調整以及鬧鐘設定。
三個按鍵:
1、“校時”鍵,每次按下分別對應調整秒、調整分鐘、調整小時、調整星期、調整日、調整月份、調整年份、調整鬧鐘分鐘、調整鬧鐘小時、退出校時模式;
2、“增加/開鬧鐘功能”鍵,校時模式下按下此鍵則數值加一,非校時模式下按下此鍵則顯示出鬧鐘時間並開啟鬧鐘功能(螢幕顯示字母A);
3、“減小/關鬧鐘功能”鍵,校時模式下按下此鍵則數值減一,非校時模式下按下此鍵則關閉鬧鐘顯示並關閉鬧鐘功能(螢幕字母A消失);
#include<reg52.h> typedef unsigned char uchar; typedef unsigned int uint; #define rs_h P3|=0x01//單片機向LCD1602液晶RS引腳輸出高電平 #define rs_l P3&=0xfe #define rw_h P3|=0x02 #define rw_l P3&=0xfd #define en_h P3|=0x04 #define en_l P3&=0xfb #define temp_h P3|=0x40//單片機向DS18B20輸出高電平 #define temp_l P3&=0xbf//單片機向DS18B20輸出低電平 #define rst_h P3|=0x08//單片機向DS1302時鐘晶片RST引腳輸出高電平 #define rst_l P3&=0xf7 #define sck_h P3|=0x10 #define sck_l P3&=0xef #define io_h P3|=0x20 #define io_l P3&=0xdf #define SECADD 0X80//秒寄存器地址 #define MINADD 0x82 #define HRADD 0x84 #define DATEADD 0x86 #define MONTHADD 0x88 #define DAYADD 0x8a #define YEARADD 0x8c #define CONTROLADD 0x8e #define PORT (P2)//P2串連LCD1602的8個資料引腳 sbit time=P3^5;//DS1302輸入輸出引腳 sbit tmp=P3^6;//DS18B20輸入輸出引腳 void delayms(uint x);//延時函數 void lcd_com(uchar com);//LCD1602液晶寫命令函數 void lcd_dat(uchar dat);//LCD1602液晶寫資料函數 void lcd_write(uchar c,uchar r,uchar dat);//向LCD1602液晶指定行、指定列寫資料函數 void lcd_init();//LCD1602液晶初始化 void Ds1302Init();//DS1302初始化 void WriteByte(uchar dat);//往DS1302寫一位元組 uchar ReadByte();//從DS1302讀一位元組 uchar BCDtoDex(uchar dat);//BCD碼轉十進位 uchar DextoBCD(uchar dat);//十進位轉BCD碼 void Ds1302Write(uchar add,uchar dat);//往DS1302指定地址寫資料 uchar Ds1302Read(uchar add);//讀DS1302制定地址的資料 void Ds18b20_reset();//DS18B20溫度感應器複位 void Ds18b20_write(uchar dat);//往DS18B20寫一位元組 void showtem();//顯示溫度 uchar Ds18b20_read();//從DS18B20讀一位元組 char keyscan();//按鍵檢測,有鍵按下返回1,否則返回0 uchar Timflag;//表示50ms時間到 uchar Temflag;//讓"命令DS18B20轉換溫度"和"讀溫度值"兩個模組錯開執行 uchar dat1,dat2;//讀回的溫度值,dat1儲存低位元組,dat2儲存高位元組 uchar keystate=2;//按鍵狀態標誌,初始化為2,是為了程式第一次運行時能夠進入keystat1分支 #define keystate0 1//keystate0在keyscan()函數中,代表按下確認功能 #define keystate1 2//keystate1在keyscan()函數中,代表無按鍵按下 uchar keynum;//調用keyscan()函數,如果該函數返回1,說明有鍵按下,keynum儲存按索引值 uchar keynum1=0;//指示鍵1按下了多少次 uchar TimeShowEn=1;//設定此變數是為了在校時狀態期間,不讓主函數再重新整理時間顯示 uchar TimeChanged;//用來指示使用者是否修改了時間 sbit led1=P0^0;//鍵1指示燈,按下鍵1此燈變換狀態 sbit led2=P0^1;//鍵2指示燈,按下鍵2此燈變換狀態 sbit led3=P0^2;//鍵3指示燈,按下鍵3此燈變換狀態 sbit buzz=P1^0;//蜂鳴器介面 uchar AlarmEn,AlarmCome;//AlarmEn指示是否開啟了鬧鐘功能,AlarmCome指示定時時間是否到了 char AlarmMin,AlarmHr;//儲存鬧鐘分鐘、鬧鐘小時 uchar CountForAlarm;//用於累加時間,時間到,翻轉蜂鳴器介面電平,決定蜂鳴器響聲頻率 uchar ToShowAlarm;//ToShowAlarm為1,則允許主函數中顯示鬧鐘時間模組執行 uchar CountForShowAlarm;//CountForShowAlarm用於累加鬧鐘顯示時間..................void Timer0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; Timflag=1;//Timflag 為1說明50ms定時時間到了 } void Ds1302Init() { rst_l; sck_l; Ds1302Write(CONTROLADD,0);//關閉防寫保護 Ds1302Write(MINADD,DextoBCD(06)); Ds1302Write(HRADD,DextoBCD(19)); Ds1302Write(DATEADD,DextoBCD(20)); Ds1302Write(MONTHADD,DextoBCD(5)); Ds1302Write(DAYADD,DextoBCD(7)); Ds1302Write(YEARADD,DextoBCD(12)); Ds1302Write(SECADD,DextoBCD(30));//寫秒,同時啟動時鐘 //Ds1302Write(CONTROLADD,0x80);//防寫保護 } void WriteByte(uchar dat)//上升沿輸出 { uchar i; for(i=8;i>0;i--) { sck_l;//低電平時資料線可變 if(dat&0x01) io_h; else io_l; sck_h; dat>>=1; } } uchar BCDtoDex(uchar dat)//BCD碼轉十進位 { uchar i; i=dat/16; dat%=16; i=i*10+dat; return i; } uchar DextoBCD(uchar dat)//十進位轉BCD碼 { uchar i; i=dat/10; dat%=10; i=i*16+dat; return i; } uchar ReadByte()//下降沿輸出 { uchar i; uchar dat; for(i=8;i>0;i--)//要考慮之前寫完後的狀態,第一次進入此迴圈體即有下降沿 { dat>>=1; sck_l; if(time==1) dat|=0x80; sck_h; } return dat; } void Ds1302Write(uchar add,uchar dat) { rst_l; sck_l; rst_h; WriteByte(add);//最低位為0表示寫 WriteByte(dat); rst_l; } uchar Ds1302Read(uchar add) { uchar dat; rst_l; sck_l; rst_h; WriteByte(add+1);//地址最低位置1表示讀 dat=ReadByte(); rst_l; return dat; } void delayms(uint x)//延時1ms { uint y,z; for(y=x;y>0;y--) for(z=111;z>0;z--); } void lcd_init()//LCD1602初始化 { lcd_com(0x38); lcd_com(0x0c); lcd_com(0x06); lcd_write(0,5,0xb0);//顯示- lcd_write(0,8,0xb0);//顯示- lcd_write(1,3,0x3a);//顯示: lcd_write(1,6,0x3a);//顯示: } void lcd_com(uchar com)//向LCD1602寫命令 { rs_l; rw_l; PORT=com; delayms(1); en_h; delayms(1); en_l; } void lcd_dat(uchar dat)//向LCD1602寫資料 { rs_h; rw_l; PORT=dat; delayms(1); en_h; delayms(1); en_l; } void lcd_write(uchar c,uchar r,uchar dat)//向LCD1602指定行、指定列、寫資料 { lcd_com(0x80+0x40*c+r); lcd_dat(dat); } ... ...............