本温度控制系统共有四个模块,分别是单片机控制系统,矩阵键盘电路,温度检测电路,液晶显示电路,其中以单片机控制系统为控制核心,首先由温度检测电路对环境进行温度采集,本系统中检测电路中用的温度传感器是DS18B20,将所在环境温度检测出来,单片机读取温度数据,接着进行液晶显示。矩阵键盘输入设定的数据,然后与实际温度比较,决定加热还是降温,并在液晶显示屏上显示相应的状态。 仿真图:
程序:#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表示有键按下标志,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表示温度整数部分,t1表示温度小数部分,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的数据命令端
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)//延迟函数delay
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delay1(uint i)//延迟函数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初始化函数
{
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
bit int_DS18B20(void)//DS18B20初始化函数
{
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读取一位数据函数
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读取一个字节函数
uchar Read(void)//DS18B20读取一个字节
{
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写一个字节函数
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++;
}
}
}
//****************启动转换函数
void int_(void)
{
while(int_DS18B20());//若为1,重新初始化
delay(1);
Write(0xcc);
Write(0x44);
}
//main()主函数
void main()
{
init_lcd();//液晶初始化
int_(); //启动温度转换
sk=0;
c=0;
EA=1; //开总中断
EX0=1; //打开外部中断0中断
solid_data();//打印固定数据
while(1)
{
int_();
delay1(1700);//等待温度传感器转换温度
get_temp();
keyscan(); //此次扫描主要是用来检测设置按键是否被按下
if((sk!=0)&&(c==1))//表明所要设置的温度已经给定
{
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函数
//***********************温度读取函数
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;
}
*/
//*************************输入温度小数部分
write_com(0x80+0x0d);
write_data(0x30+t1);
//*************************输入温度整数部分
write_com(0x80+0x0a);
write_data(0x30+t/10);
write_com(0x80+0x0b);
write_data(0x30+t%10);
// int_();
}
//显示数据函数
void dentify_key(uchar key)
{
if(key>=0&&key<=9)
{
write_data(tablenum2[key]);
}
}
//*************************显示固定数据
void solid_data(void)
{
//*************************写第一行显示数据
write_com(0x80);
for(num=0;num<ActualTemp_worth;num++)
{
write_data(table[num]);
delay(1);
}
//*************************打印温度小数点以及摄氏度" °"
write_com(0x80+0x0c);
write_data(0x2e);//打印小数点,'0x2e'为小数点的ASCII码
write_com(0x80+0x0e);
for(num=0;num<2;num++)
{
write_data(table2[num]);
delay(1);
}
//*************************写第二行显示数据
write_com(0x80+0x40);
for(num=0;num<TempSet_worth;num++)
{
write_data(table1[num]);
delay(1);
}
}
//*************************矩阵键盘扫描函数
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;//有按键按下标志
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;//有按键按下标志
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;//有按键按下标志
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;//有按键按下标志
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);
}
//*************************中断函数
void ex_enter() interrupt 0
{
c=1;//表明已进入中断
delay(100);
write_com(0x80+0x4c);
for(num=0;num<4;num++)//在按下设置后清屏设置部分的数据
{
write_data(0x20);
}
ADD=1;
SUB=1;
write_com(0x80+0x49);
write_com(0x0f);//开光标并闪烁
sk=0;
ex0_enter=1;//外部中断0中断复位
SIG=0;
write_com(0x80+0x49);
delay(100);//******************可能是因为刚刚按设置键的时候,由于单片机速度过快,进入中断后还没
//******************释放按键,导致进入do...while语句,使得sk值迅速变为1;
//******************因此在此加一延时,可以防止这种情况发生。
do
{
sk=0;
made_temp=temp2=keyscan(); //sk自加已在keyscan函数中实现
}while((sk!=1)||(temp2==10||temp2==11));//检测按键是否是设置键,如是设置键,继续扫描
if(sk!=0)//打印数据
{
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函数中实现
}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函数中实现
}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]);
}
}
}
|