本溫度控制系統(tǒng)共有四個模塊,分別是單片機(jī)控制系統(tǒng),矩陣鍵盤電路,溫度檢測電路,液晶顯示電路,其中以單片機(jī)控制系統(tǒng)為控制核心,首先由溫度檢測電路對環(huán)境進(jìn)行溫度采集,本系統(tǒng)中檢測電路中用的溫度傳感器是DS18B20,將所在環(huán)境溫度檢測出來,單片機(jī)讀取溫度數(shù)據(jù),接著進(jìn)行液晶顯示。矩陣鍵盤輸入設(shè)定的數(shù)據(jù),然后與實際溫度比較,決定加熱還是降溫,并在液晶顯示屏上顯示相應(yīng)的狀態(tài)。 仿真圖:
程序:#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define ActualTemp_worth 9
#define TempSet_worth 9
#define row_worth 16
void dentify_key(uchar key);
void get_temp(void);
uchar keyscan();
void solid_data(void);
uchar sk,temp2;//sk表示有鍵按下標(biāo)志,temp2用來臨時存儲掃描值
uchar code table[]="RealTemp:";
uchar code table1[]="TempRset:";
uchar code table2[]={0xdf,'C'};
uchar code table3[]="ADD";
uchar code table4[]="SUB";
uchar a,a_low,b,t,t1,temp1,key,c;//t表示溫度整數(shù)部分,t1表示溫度小數(shù)部分,temp1為中間變量(P3)
float t2,f_temp;
uint temp;
uchar sg=0,made_temp=0,made_temp1=0; sbit lcden=P1^7; //*******************LCD1602的使能端
sbit lcdrs=P1^6; //*******************LCD1602的數(shù)據(jù)命令端
sbit DQ=P1^1; //*******************DS18B20的DS端
sbit SIG=P1^5; //******************按鍵輸入信號
sbit ADD=P1^2;
sbit SUB=P1^3;
sbit ex0_enter=P3^2; uchar code tablenum[]={0xc0,0xf9,0xa4,0xb0,0x99, //0~9
0x92,0x82,0xf8,0x80,0x90};
uchar code tablenum2[]={0x30,0x31,0x32,0x33,0x34, //0~9的ASIIC值
0x35,0x36,0x37,0x38,0x39};
/*****************************************************************
LCD1602液晶顯示
*****************************************************************/
uchar num=0;
void delay(int z)//延遲函數(shù)delay
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delay1(uint i)//延遲函數(shù)delay1
{
while(i>0) i--;
}
void write_com(uchar com)
{
lcdrs=0;
P0=com;
delay(1);
lcden=1;
delay(1);
lcden=0;
}
void write_data(uchar date)
{
lcdrs=1;
P0=date;
delay(1);
lcden=1;
delay(1);
lcden=0;
}
void init_lcd()//LCD1602初始化函數(shù)
{
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
bit int_DS18B20(void)//DS18B20初始化函數(shù)
{
unsigned char x=0;
uint i;
DQ=0;
i=103;
while(i>0)i--;
DQ=1;
i=4;
while(i>0)i--;
x=DQ; //延時片刻后,若x=0,則初始化成功;若x=1,則初始化失敗
delay(20);
return x;
}
//*************DS18B20讀取一位數(shù)據(jù)函數(shù)
bit tempreadbit(void)
{
uint i;
bit dat;
DQ=0;i++;
DQ=1;i++;i++;
dat=DQ;
i=8;while(i>0)i--;
return (dat);
}
//*************DS18B20讀取一個字節(jié)函數(shù)
uchar Read(void)//DS18B20讀取一個字節(jié)
{
unsigned char i=0;
unsigned char j=0;
unsigned char dat=0;
for(i=8;i>0;i--)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1);
}
return(dat);
}
//*************DS18B20寫一個字節(jié)函數(shù)
Write(unsigned char dat)
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb)
{
DQ=0;
i++;i++;
DQ=1;
i=8;while(i>0)i--;
}
else
{
DQ=0;
i=8;while(i>0)i--;
DQ=1;
i++;i++;
}
}
}
//****************啟動轉(zhuǎn)換函數(shù)
void int_(void)
{
while(int_DS18B20());//若為1,重新初始化
delay(1);
Write(0xcc);
Write(0x44);
}
//main()主函數(shù)
void main()
{
init_lcd();//液晶初始化
int_(); //啟動溫度轉(zhuǎn)換
sk=0;
c=0;
EA=1; //開總中斷
EX0=1; //打開外部中斷0中斷
solid_data();//打印固定數(shù)據(jù)
while(1)
{
int_();
delay1(1700);//等待溫度傳感器轉(zhuǎn)換溫度
get_temp();
keyscan(); //此次掃描主要是用來檢測設(shè)置按鍵是否被按下
if((sk!=0)&&(c==1))//表明所要設(shè)置的溫度已經(jīng)給定
{
if((t+1)>made_temp)
{
ADD=1;
SUB=0;
write_com(0x80+0x4c);
for(num=0;num<3;num++)
write_data(table4[num]);
}
else
{
SUB=1;
ADD=0;
write_com(0x80+0x4c);
for(num=0;num<3;num++)
write_data(table3[num]);
}
}
}
}//main函數(shù)
//***********************溫度讀取函數(shù)
void get_temp(void)
{
while(int_DS18B20());
Write(0xcc);
Write(0xBE);//讀取溫度寄存器指令
a=Read();
b=Read();
temp=b;
temp<<=8;
temp=temp|a;
f_temp=temp*0.0625;
t=(uchar)(f_temp);
t2=f_temp-t;
t1=(uchar)(t2*10);
/* if(b>127)
{
sg=1;
temp=~temp;
temp=temp+1;
if(a==0x00)
b=b+1;
a_low=a&0x0f;
t2=a_low*5/80;
t1=(uchar)(t2*10);
a=a>>4;
b=b<<4;
b=b&0x70;//把b中的最高位符號位置0
t=b|a;
t=t*5/80;
}
else
{
sg=0;
a_low=a&0x0f;
t2=a_low*5/80;
t1=(uchar)(t2*10);
a=a>>4;
b=b<<4;
b=b&0x70;
t=b|a;
t=t*5/80;
}
*/
//*************************輸入溫度小數(shù)部分
write_com(0x80+0x0d);
write_data(0x30+t1);
//*************************輸入溫度整數(shù)部分
write_com(0x80+0x0a);
write_data(0x30+t/10);
write_com(0x80+0x0b);
write_data(0x30+t%10);
// int_();
}
//顯示數(shù)據(jù)函數(shù)
void dentify_key(uchar key)
{
if(key>=0&&key<=9)
{
write_data(tablenum2[key]);
}
}
//*************************顯示固定數(shù)據(jù)
void solid_data(void)
{
//*************************寫第一行顯示數(shù)據(jù)
write_com(0x80);
for(num=0;num<ActualTemp_worth;num++)
{
write_data(table[num]);
delay(1);
}
//*************************打印溫度小數(shù)點以及攝氏度" °"
write_com(0x80+0x0c);
write_data(0x2e);//打印小數(shù)點,'0x2e'為小數(shù)點的ASCII碼
write_com(0x80+0x0e);
for(num=0;num<2;num++)
{
write_data(table2[num]);
delay(1);
}
//*************************寫第二行顯示數(shù)據(jù)
write_com(0x80+0x40);
for(num=0;num<TempSet_worth;num++)
{
write_data(table1[num]);
delay(1);
}
}
//*************************矩陣鍵盤掃描函數(shù)
uchar keyscan()
{
//*************************矩陣鍵盤第一列掃描
P2=0xfe;
temp1=P2;
temp1=temp1&0xf0;
if(temp1!=0xf0)
{
delay(10);//延時消斗
temp1=P2;
temp1=temp1&0xf0;
while(temp1!=0xf0)
{
sk=sk+1;//有按鍵按下標(biāo)志
temp1=P2;
switch(temp1)
{
case 0xee:key=0;break;
case 0xde:key=4;break;
case 0xbe:key=8;break;
}
while(temp1!=0xf0)
{
temp1=P2;
temp1=temp1&0xf0;
}
}
}
//*************************矩陣鍵盤第二列掃描
P2=0xfd;
temp1=P2;
temp1=temp1&0xf0;
if(temp1!=0xf0)
{
delay(10);
temp1=P2;
temp1=temp1&0xf0;
while(temp1!=0xf0)
{
sk=sk+1;//有按鍵按下標(biāo)志
temp1=P2;
switch(temp1)
{
case 0xed:key=1;break;
case 0xdd:key=5;break;
case 0xbd:key=9;break;
}
while(temp1!=0xf0)
{
temp1=P2;
temp1=temp1&0xf0;
}
}
}
//*************************矩陣鍵盤第三列掃描
P2=0xfb;
temp1=P2;
temp1=temp1&0xf0;
if(temp1!=0xf0)
{
delay(10);
temp1=P2;
temp1=temp1&0xf0;
while(temp1!=0xf0)
{
temp1=P2;
sk=sk+1;//有按鍵按下標(biāo)志
switch(temp1)
{
case 0xeb:key=2;break;
case 0xdb:key=6;break;
case 0xbb:key=10;break;
}
while(temp1!=0xf0)
{
temp1=P2;
temp1=temp1&0xf0;
}
}
}
//*************************矩陣鍵盤第四列掃描
P2=0xf7;
temp1=P2;
temp1=temp1&0xf0;
if(temp1!=0xf0)
{
delay(10);
temp1=P2;
temp1=temp1&0xf0;
while(temp1!=0xf0)
{
temp1=P2;
sk=sk+1;//有按鍵按下標(biāo)志
switch(temp1)
{
case 0xe7:key=3;break;
case 0xd7:key=7;break;
case 0xb7:key=11;break;
}
while(temp1!=0xf0)
{
temp1=P2;
temp1=temp1&0xf0;
}
}
}
return (key);
}
//*************************中斷函數(shù)
void ex_enter() interrupt 0
{
c=1;//表明已進(jìn)入中斷
delay(100);
write_com(0x80+0x4c);
for(num=0;num<4;num++)//在按下設(shè)置后清屏設(shè)置部分的數(shù)據(jù)
{
write_data(0x20);
}
ADD=1;
SUB=1;
write_com(0x80+0x49);
write_com(0x0f);//開光標(biāo)并閃爍
sk=0;
ex0_enter=1;//外部中斷0中斷復(fù)位
SIG=0;
write_com(0x80+0x49);
delay(100);//******************可能是因為剛剛按設(shè)置鍵的時候,由于單片機(jī)速度過快,進(jìn)入中斷后還沒
//******************釋放按鍵,導(dǎo)致進(jìn)入do...while語句,使得sk值迅速變?yōu)?;
//******************因此在此加一延時,可以防止這種情況發(fā)生。
do
{
sk=0;
made_temp=temp2=keyscan(); //sk自加已在keyscan函數(shù)中實現(xiàn)
}while((sk!=1)||(temp2==10||temp2==11));//檢測按鍵是否是設(shè)置鍵,如是設(shè)置鍵,繼續(xù)掃描
if(sk!=0)//打印數(shù)據(jù)
{
for(num=0;num<sk;num++)
dentify_key(temp2);
}
made_temp=made_temp*10;
sk=0;
delay(100);//******************作用于上面相同
do
{
sk=0;
made_temp1=temp2=keyscan();//sk自加已在keyscan函數(shù)中實現(xiàn)
}while((sk!=1)||(temp2==10||temp2==11));
if(sk!=0)
{
for(num=0;num<sk;num++)
dentify_key(temp2);
}
made_temp=made_temp+made_temp1;
write_com(0x0c);
sk=0;
delay(100);
do //***************檢測確定按鍵
{
sk=0;
temp2=keyscan();//sk自加已在keyscan函數(shù)中實現(xiàn)
}while((sk!=1)||(temp2!=11));
delay(50);
SIG=1;
if(sk!=0)
{
if((t+1)>made_temp)
{
ADD=1;
SUB=0;
write_com(0x80+0x4c);
for(num=0;num<3;num++)
write_data(table4[num]);
}
else
{
SUB=1;
ADD=0;
write_com(0x80+0x4c);
for(num=0;num<3;num++)
write_data(table3[num]);
}
}
}
|