最近利用DS1302與DS18B20做了一個能顯示當前時間、日期、溫度的東西。有三個按鍵,正常運行時顯示當前的時間,利用按鍵2、3可以切換到日期與溫度。按下按鍵1進入設置時間狀態,在設置時間狀態利用按鍵2、3可調整時間與日期。調整好后不進行任何操作6秒退出設置狀態。
實物圖:
顯示當前時間:(11時:24分:47秒)

顯示當前日期:(09年:01月:15日)
顯示當前溫度:(17.2度)

源程序:
#include <reg51.h>
#include<intrins.h>
sbit dq = P0^0;//定義P0.0為DS18B20的數據線
sbit t_rst=P0^2;//DS1302數據線
sbit t_clk=P0^4;
sbit t_io=P0^3;
sbit P2_0=P2^0;//按鍵
sbit P2_1=P2^1;
sbit P2_2=P2^2;
sbit P3_0=P3^0;//顯示
sbit P3_1=P3^1;
sbit P3_2=P3^2;
sbit P3_3=P3^3;
sbit P3_4=P3^4;
sbit P3_5=P3^5;
sbit P3_6=P3^6;
sbit P3_7=P3^7;
void delay(unsigned char i);//定義延時函數
bit init_18b20();//定義DS18B20初始化復位函數
void w_18b20(unsigned char dat);//定義寫DS18B20函數
unsigned char r_18b20();//定義讀DS18B20函數
void GetTem(void);//定義獲得溫度函數
void Temdisp(void);//溫度顯示函數
void in_1302(unsigned char tdat);//定義寫一個字節到DS1302函數
unsigned char out_1302(void);//定義從DS1302讀一個字節函數
void w_1302(unsigned char ucAddr, unsigned char ucDa);//定義寫DS1302函數
void set1302(void);//設置時間
void get1302(void);//讀取時間
void timedisp(void);//時間顯示函數
void datedisp(void);//日期顯示函數
void setbom(void);
unsigned char TemL;//溫度低位
unsigned char TemH;//溫度高位
unsigned char Tem1;//轉換后溫度個位
unsigned char Tem2;//轉換后溫度十位
unsigned char Led[4];
unsigned char dis[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//不帶點的0~9
unsigned char dis1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//帶點的0~9
bit TempS;//溫度符號位
unsigned int ms;
unsigned char time[7]={0x00,0x24,0x11,0x15,0x01,0x04,0x09};
main()
{
set1302();
while(1)
{
if(!P2_1){get1302();datedisp();}
if(!P2_2){GetTem();Temdisp();}
if(P2_1 && P2_2){ get1302();timedisp();}
if(!P2_0)
{
TMOD=0x01; EA=1;ET0=1;TH0=0xFC;TL0=0x66;
while(!P2_0);delay(255);delay(255);delay(255);
setbom();
}
}
}
void delay (unsigned char i) //延時程序,12M晶振下延時為:(2i+3)us ,i=0~255
{
while (--i);
}
bit init_18b20() //初始化,init_18b20=0初始化成功,init_18b20=1初始化失敗,可能18b20不存在
{
bit SS;
dq=1;
_nop_();
dq=0;
delay(255);
dq=1;
delay(34);
SS=dq;
delay(120);
return (SS);
}
void w_18b20(unsigned char dat) //寫一個字節到18b20
{
unsigned char i=0;
for(i=8;i>0;i--)
{
dq=0;
delay(5);
dq=dat&0x01;
delay(22);//延時
dq=1;
dat>>=1;
}
}
unsigned char r_18b20()//從18b20讀一個字節
{
unsigned char i=0;
unsigned char dat=0;
for(i=8;i>0;i--)
{
dq=0;
dat>>=1;
dq=1;
delay(6);
if(dq) dat|=0x80;
delay(22);
}
return(dat);
}
void GetTem() //獲得溫度函數
{
bit SS;
unsigned char A;
unsigned long Tem;//溫度變量
unsigned char TemLH;//低位溫度高位
unsigned char TemLL;//低位溫度低位
do SS=init_18b20();while(SS);//初始化DS18B20,檢測是否存在,存在繼續
w_18b20(0xCC);//跳過ROM匹配
w_18b20(0x44);//開始溫度轉換
do//等待溫度轉換完成
{
dq=0;
_nop_();
_nop_();
_nop_();
dq=1;
delay(6);
SS=dq;
delay(22);
Temdisp();
}
while (!SS);//溫度轉換完成后繼續
init_18b20();//復位
w_18b20(0xCC);//跳過ROM匹配
w_18b20(0xBE);//讀取溫度值
TemL=r_18b20();//低位
TemH=r_18b20();//高位
if (TemH&0x80)//把讀取的溫度值進行轉換,并存進Led[]中
{
TemH=~TemH;
TemL=(~TemL)+1;
TempS=1;
Led[0]=0x40;//顯示負號
}
else TempS=0;
TemLH=TemL>>4;
TemLL=TemL&0x0F;
Tem=(TemH*16 + TemLH + TemLL*0.0625)*10000;
A=Tem/100000;
Led[1]=dis[A];
Tem=Tem%100000;
A=Tem/10000;
Led[2]=dis1[A];
Tem=Tem%10000;
A=Tem/1000;
Led[3]=dis[A];
}
void Temdisp()//溫度顯示函數,符號位(為負號顯示),十位(為0不顯示,個位(帶小數點),小數位
{
if (TempS==1)//溫度為負則顯示負號,否則不顯示
{
if (Led[1]!=0x3f)
{
P1=Led[0];
P3_5=0;
delay(255);
P3_5=1;
}
else
{
P1=Led[0];
P3_4=0;
delay(255);
P3_4=1;
}
}
if (Led[1]!=0x3f)//十位不為零則顯示,否則不顯示
{
P1=Led[1];
P3_4=0;
delay(255);
P3_4=1;
}
P1=Led[2];//個位
P3_3=0;
delay(255);
P3_3=1;
P1=Led[3];//小數位
P3_2=0;
delay(255);
P3_2=1;
}
void in_1302(unsigned char tdat) //寫一個字節到DS1302
{
unsigned char i;
for(i=8;i>0;i--)
{
t_io=tdat&0x01;
_nop_();
t_clk=1;
_nop_();
t_clk=0;
tdat>>=1;
}
}
unsigned char out_1302(void) //從DS1302讀一個字節
{
unsigned char i;
unsigned char tdat;
for(i=8;i>0;i--)
{
tdat>>=1;
if(t_io){tdat=tdat|0x80;}
t_clk=1;
_nop_();
t_clk=0;
}
return(tdat);
}
void w_1302(unsigned char ucAddr, unsigned char ucDa) //往DS1302寫入數據,先寫地址,后寫命令/數據
{
t_rst = 0;
t_clk = 0;
t_rst = 1;
in_1302(ucAddr); /* 地址,命令 */
in_1302(ucDa); /* 寫1Byte數據*/
t_clk = 1;
t_rst =0;
}
unsigned char r_1302(unsigned char ucAddr)//從DS1302讀出數據,先寫地址,后讀命令/數據
{
unsigned char ucDa;
t_rst = 0;
t_clk = 0;
t_rst = 1;
in_1302(ucAddr); /* 地址,命令 */
ucDa = out_1302(); /* 讀1Byte數據 */
t_clk = 1;
t_rst =0;
return(ucDa);
}
void set1302(void)
{
unsigned char i;
unsigned char ucAddr = 0x80;
w_1302(0x8e,0x00); /* 控制命令,WP=0,寫操作?*/
for(i =0;i<7;i++)
{
w_1302(ucAddr,time[ i]); /* 秒 分 時 日 月 星期 年 */
ucAddr +=2;
}
w_1302(0x8e,0x80); /* 控制命令,WP=1,寫保護?*/
}
void get1302(void)
{
unsigned char i;
unsigned char ucAddr = 0x81;
for (i=0;i<7;i++)
{
time = r_1302(ucAddr);/*格式為: 秒 分 時 日 月 星期 年 */
ucAddr += 2;
}
}
void timedisp(void)
{
unsigned char m;unsigned char n;
m=time[0]>>4;n=time[0]&0x0f;//顯示秒
P1=dis[m];
P3_3=0;
delay(255);delay(255);delay(255);delay(255);
P3_3=1;
P1=dis1[n];
P3_2=0;
delay(255);delay(255);delay(255);delay(255);
P3_2=1;
m=time[1]>>4;n=time[1]&0x0f;//顯示分
P1=dis[m];
P3_5=0;
delay(255);delay(255);delay(255);delay(255);
P3_5=1;
P1=dis1[n];
P3_4=0;
delay(255);delay(255);delay(255);delay(255);
P3_4=1;
m=time[2]>>4;n=time[2]&0x0f;//顯示時
P1=dis[m];
P3_7=0;
delay(255);delay(255);delay(255);delay(255);
P3_7=1;
P1=dis1[n];
P3_6=0;
delay(255);delay(255);delay(255);delay(255);
P3_6=1;
}
void datedisp(void)
{
unsigned char m;unsigned char n;
m=time[3]>>4;n=time[3]&0x0f;//顯示日
P1=dis[m];
P3_3=0;
delay(255);delay(255);delay(255);delay(255);
P3_3=1;
P1=dis1[n];
P3_2=0;
delay(255);delay(255);delay(255);delay(255);
P3_2=1;
m=time[4]>>4;n=time[4]&0x0f;//顯示月
P1=dis[m];
P3_5=0;
delay(255);delay(255);delay(255);delay(255);
P3_5=1;
P1=dis1[n];
P3_4=0;
delay(255);delay(255);delay(255);delay(255);
P3_4=1;
m=time[6]>>4;n=time[6]&0x0f;//顯示年
P1=dis[m];
P3_7=0;
delay(255);delay(255);delay(255);delay(255);
P3_7=1;
P1=dis1[n];
P3_6=0;
delay(255);delay(255);delay(255);delay(255);
P3_6=1;
}
void setbom(void)
{
unsigned char i,m,n;
TR0=1;
while(ms<6000)
{
if(!P2_0)
{
i++;ms=0;
if(i==5) {i=6;}
if(i==7) {i=0;}
while(!P2_0);
delay(255);delay(255);delay(255);
ms=0;
}
if(!P2_1)
{
m=time>>4; n=time&0x0f;
if(n!=9) n=n+1;
else{m=m+1;n=0;}
time=(m<<4)|n;
while(!P2_1);
delay(255);delay(255);delay(255);
ms=0;
}
if(!P2_2)
{
m=time>>4; n=time&0x0f;
if(m!=0 && n==0) {n=9;m=m-1;}
else if(n!=0) {n=n-1;}
time=(m<<4)|n;
while(!P2_2);
delay(255);delay(255);delay(255);
ms=0;
}
if (time[0]==0x60)time[0]=0x00;
if (time[1]==0x60)time[1]=0x00;
if (time[2]==0x24)time[2]=0x00;
if (time[3]==0x32)time[3]=0x00;
if (time[4]==0x13)time[4]=0x00;
if (time[6]==0x99)time[6]=0x00;
set1302();
if(i<3){get1302();timedisp();}
else {get1302();datedisp();}
}
TR0=0;
ms=0;
}
void time0() interrupt 1 //定時器0中斷
{
TR0=0;
TH0=0xFC;TL0=0x66;
ms++;
TR0=1;
}
|