硬件部分 基于51單片機、 ds1302時鐘芯片、 ds18b20溫度芯片、 以及1602液晶顯示的 實時時間 和 實時溫度顯示 。同時可通過按鍵 設置 年、月、日、時、分、星期。并且可以設置鬧鐘 當鬧鐘時間到時 蜂鳴器持續發出 滴..聲 同時led燈不停閃爍 且在一分鐘內沒有按指定停止按鍵 鬧鐘將自動停止 。。。 軟件部分 #include <reg52.h> #define uchar unsigned char #define uint unsigned int sbit spk=P1^7; sbit led=P1^5; sbit DQ=P1^0; sbit RS=P2^4; sbit RW=P2^5; sbit EN=P2^6; sbit key1=P2^0; sbit key2=P2^1; sbit key3=P2^2; sbit key4=P2^3; sbit IO=P3^6; sbit RST=P3^7; sbit SCLK=P3^5; uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39}; int nian,xing,yue,ri,shi,fen,miao; uchar num,temp,c,d,time[7],a,b,aa,bb,ns,ng,ys,yg,rs,rg,ss,sg,fs,fg,ms,mg,flag; /*******************1602************************/ void delay(int z) { int x,y; for(x=z;x>0;x--) for(y=100;y>0;y--); } void write_com(uchar com) //寫命令 { RS=0; P0=com; delay(5); EN=1; delay(5); EN=0; } void write_data(uchar date) //寫數據 { RS=1; P0=date; delay(5); EN=1; delay(5); EN=0; } void init() //初始化 { RW=0; EN=0; write_com(0x38); //顯示模式設置 write_com(0x0c); //開顯示 不顯示光標 不閃 write_com(0x06); //寫一個字符 地址指針 光標 加一 整屏不移動 write_com(0x01); //顯示清零 write_com(0x80+0x04); write_data('2'); write_com(0x80+0x05); write_data('0'); write_com(0x80+0x00); write_data('c'); write_com(0x80+0x01); write_data('a'); write_com(0x80+0x02); write_data('i'); write_com(0x80+0x4e); write_data(0xdf); write_com(0x80+0x4f); write_data('C'); write_com(0x80+0x4b); write_data(0x2e); //顯示"。" } /**************DS18B20****************/ void delay1(unsigned int t) //延時函數 { while(t--); } void init1() //初始化 { uchar n=0; DQ=1; //DQ復位 delay1(8); DQ=0; //主機將DQ拉低 delay1(80); //大于480us的延時 DQ=1; delay1(5); //延時15~60us n=DQ; delay1(5); //若n=0初始成功 n=1初始失?。稍O置返回值查看n是否為1) } void write_byte(uchar dat) //寫入一個字節 { uint i; for(i=0;i<8;i++) { DQ=0; DQ=dat&0x01; delay1(12); DQ=1; dat>>=1; } delay1(4); } uchar read_byte() //讀入一個字節 { uint k=0; uchar value=0; for(k=0;k<8;k++) { DQ=0; value>>=1; DQ=1; if(DQ) value|=0x80; delay1(4); } return value; } uchar read_temp() //讀取溫度函數 { uchar a=0,b=0; init1(); write_byte(0xcc); write_byte(0x44); delay1(200); init1(); write_byte(0xcc); write_byte(0xbe); a=read_byte(); b=read_byte(); c=b; d=a; b<<=4; b+=(a&0xf0)>>4; return b; } /***********************1302**********************/ void wirte_byte1(uchar date) //寫入一個字節 { uchar i; for(i=8;i>0;i--) { IO=date&0x01; SCLK=0; SCLK=1; date=date>>1; } } uchar read_byte1() //讀一個字節 { uchar dat,i; for(i=8;i>0;i--) { dat=dat>>1; SCLK=0; if(IO) dat=dat|0x80; SCLK=1; } return(dat); } void write_ds1302(uchar add,uchar date) //將數據寫入1302中 { RST=0; SCLK=0; RST=1; wirte_byte1(add); wirte_byte1(date); RST=0; SCLK=1; } uchar read_ds1302(uchar add) //讀出1302中數據 { uchar temp; RST=0; SCLK=0; RST=1; wirte_byte1(add); temp=read_byte1(); RST=0; SCLK=0; return (temp); } uchar huan_BCD(uint z) //將數據 轉換成BCD { uint a,b; a=z/10; b=z%10; a=a&0xff; b=b&0xff; a<<=4; a=a|b; return (a); } void xian_shi() //液晶顯示函數 { if(b==0&a==0) { ms=time[0]/16; mg=time[0]%16; fs=time[1]/16; fg=time[1]%16; fen=fs*10+fg; ss=time[2]/16; sg=time[2]%16; shi=ss*10+sg; rs=time[3]/16; rg=time[3]%16; ri=rs*10+rg; ys=time[4]/16; yg=time[4]%16; yue=ys*10+yg; ns=time[6]/16; ng=time[6]%16; nian=ns*10+ng; xing=time[5]; } if(a==1|b==1) { ss=shi/10; sg=shi%10; write_com(0x80+0x41); write_data(0xff); write_com(0x80+0x40); write_data(table[ss]); write_com(0x80+0x41); write_data(table[sg]); } if(a==2|b==2) { fs=fen/10; fg=fen%10; write_com(0x80+0x44); write_data(0xff); write_com(0x80+0x43); write_data(table[fs]); write_com(0x80+0x44); write_data(table[fg]); } if(a==3) { rs=ri/10; rg=ri%10; write_com(0x80+0x0d); write_data(0xff); write_com(0x80+0x0c); write_data(table[rs]); write_com(0x80+0x0d); write_data(table[rg]); } if(a==4) { ys=yue/10; yg=yue%10; write_com(0x80+0x0a); write_data(0xff); write_com(0x80+0x09); write_data(table[ys]); write_com(0x80+0x0a); write_data(table[yg]); } if(a==5) { ns=nian/10; ng=nian%10; write_com(0x80+0x07); write_data(0xff); write_com(0x80+0x06); write_data(table[ns]); write_com(0x80+0x07); write_data(table[ng]); } if(a==6) { write_com(0x80+0x0f); write_data(0xff); write_com(0x80+0x0f); write_data(table[xing]); } write_com(0x80+0x06); //在液晶第一行第七八位顯示 年 write_data(table[ns]); write_com(0x80+0x07); write_data(table[ng]); write_com(0x80+0x08); write_data('-'); write_com(0x80+0x09); //在液晶第一行第十十一位顯示 月 write_data(table[ys]); write_com(0x80+0x0a); write_data(table[yg]); write_com(0x80+0x0b); write_data('-'); write_com(0x80+0x0c); //在液晶第一行第十三 十四位顯示 日 write_data(table[rs]); write_com(0x80+0x0d); write_data(table[rg]); write_com(0x80+0x0f); //在液晶第一行第十七位顯示 星期 write_data(table[xing]); write_com(0x80+0x40); //在液晶第二行第二三位顯示 時 write_data(table[ss]); write_com(0x80+0x41); write_data(table[sg]); write_com(0x80+0x42); write_data(':'); write_com(0x80+0x43); //在液晶第二行第五六位顯示 分 write_data(table[fs]); write_com(0x80+0x44); write_data(table[fg]); write_com(0x80+0x45); write_data(':'); write_com(0x80+0x46); //在液晶第二行第八九位顯示 秒 write_data(table[ms]); write_com(0x80+0x47); write_data(table[mg]); } void keyscan() //按鍵設置函數 可任意設置年月日時分秒星期的數值 { if(key4!=0) { if(key1==0) //key1按鍵 選擇需設置的位 { if(key1==0) { a++; delay(1); } while(!key1) { delay(1); } } if(a!=0) { if(key2==0) //key2按鍵 可將需設置的數 調大 { if(a==1) { shi++; if(shi>=24) { shi=0; } } if(a==2) { fen++; if(fen>=60) { fen=0; } } if(a==3) { ri++; if(ri>=32) { ri=1; } } if(a==4) { yue++; if(yue>=12) { yue=1; } } if(a==5) { nian++; if(nian>=99) { nian=0; } } if(a==6) { xing++; if(xing>=8) { xing=1; } } } if(key3==0) //key3按鍵 可將需設置的數 調小 { if(a==1) { shi--; if(shi<0) { shi=23; } } if(a==2) { fen--; if(fen<0) { fen=59; } } if(a==3) { ri--; if(ri<1) { ri=31; } } if(a==4) { yue--; if(yue<1) { yue=12; } } if(a==5) { nian--; if(nian<0) { nian=99; } } if(a==6) { xing--; if(xing<1) { xing=7; } } } if(a==7) //當按下key1 7次后 將個數據寫入1302 { a=0; write_ds1302(0x8e,0x00); //WP=0 寫操作 write_ds1302(0x80,0x00); //0x80是寫秒數據 write_ds1302(0x82,huan_BCD(fen)); //0x82是寫分數據 write_ds1302(0x84,huan_BCD(shi)); //0x84是寫時數據 write_ds1302(0x86,huan_BCD(ri)); //0x84是寫日數據 write_ds1302(0x88,huan_BCD(yue)); //0x84是寫月數據 write_ds1302(0x8a,huan_BCD(xing)); //0x84是寫星期數據 write_ds1302(0x8c,huan_BCD(nian)); //0x84是寫年數據 write_ds1302(0x8e,0x80); //WP=1 寫保護 } } } } void naozhong() //通過按鍵設置鬧鐘 時 分 { if(key1!=0) { if(key4==0) { if(key4==0) { b++; delay(1); } while(!key4) { delay(1); } } if(b!=0) { if(key2==0) //key2按鍵 可將需設置的數 調大 { if(b==1) { shi++; if(shi>=24) { shi=0; } } if(b==2) { fen++; if(fen>=60) { fen=0; } } } if(key3==0) //key3按鍵 可將需設置的數 調小 { if(b==1) { shi--; if(shi<0) { shi=23; } } if(b==2) { fen--; if(fen<0) { fen=59; } } } aa=huan_BCD(shi); //將設置的時鐘 賦值給aa bb=huan_BCD(fen); //將設置的分鐘 賦值給bb if(b==3) //當按下key4 3次后 鬧鐘設置完成 { b=0; } } } } void main() { uint i,temp; init(); TMOD=0x10; EA=1; TH1=(65536-51200)/256; TL1=(65536-51200)%256; ET1=1; while(1) { temp=0x81; //讀的初始地址 for(i=0;i<7;i++) //分別把秒分時日月年星期數據讀出分7次讀好一次地址加2" temp+=2;" { time[i]=read_ds1302(temp); temp+=2; } if(bb==time[1]&aa==time[2]&!time[0]) //如果讀出來的時鐘 分鐘與1302讀出來的值相等且讀出來的秒鐘為零時 進入中斷 { TR1=1; flag=1; //標志位設置為1 } if(key3==0) //進入鬧鐘后 可由key3按下 停止中斷 標志位置零 允許調時鬧鐘設置按鍵動作 停止鬧鈴 { led=1; spk=1; flag=0; TR1=0; } if(flag!=1) //當進入鬧鐘中斷后 調時與設置鬧鐘的按鍵 無效 { naozhong(); keyscan(); } xian_shi(); temp=read_temp(); write_com(0x80+0x49); write_data(table[temp/10]); //在液晶第二行第十位顯示溫度的十位 write_com(0x80+0x4a); write_data(table[temp%10]); //在液晶第二行第十一位顯示溫度的個位 write_com(0x80+0x4c); write_data(table[(d&0x0f)*625/1000]); //在液晶第二行第十三位顯示溫度的小數點后一位 write_com(0x80+0x4d); write_data(table[(d&0x0f)*625/100%10]); //在液晶第二行第十四位顯示溫度的小數點后二位 } }
void timer1() interrupt 3 //定時器 { uint t; TH1=(65536-50000)/256; TL1=(65536-50000)%256; t++; spk=0; //蜂鳴器 發出 滴答 聲 led=!led; //發光二極管 不停閃爍 delay1(10); if(t==1120) //約1分鐘后 鬧鐘自動停止 標志位 { led=1; spk=1; t=0; TR1=0; flag=0; } } |