具体实现功能:
1、LCD1602显示屏第一行显示温度及定时时间,第二行显示温度上限和下限值;
2、按键可以设置温度的上下限值及定时时间;定时时间到开始加热
3、用两个水位检测传感器检测水位:当水位下限传感器检测到有水时,继电器开始控制加水;当水位上限传感器检测到有水时,停止加水;
4、当温度低于设置的下限温度值时,继电器开始控制加热;当温度高于设置的上限温度值时,停止加热。
系统的硬件系统以STC89C51单片机为核心,主要分两部分:直流稳压电源和智能电热水器控制电路,其原理图见附录二。直流稳压电源由变压器、整流桥、滤波电路、稳压电路组成。智能电热水器系统由时钟电路、复位电路、报警电路、键盘、温度检测电路和显示接口电路组成。
/*
基于51单片机的智能热水器
*/
//程序头函数
#include
//显示函数
#include
//宏定义
#define uint unsigned int
#define uchar unsigned char
//管脚声明
sbit jdq= P1^0; //加热继电器
sbit shui=P1^3;//加水继电器
sbit Feng = P2^6; //蜂鸣器
//按键
sbit Key1=P1^4; //设置
sbit Key2=P1^5; //加
sbit Key3=P1^6; //减
sbit Key4=P1^7; //确定
sbit shang=P3^7;//上限
sbit xia=P3^6;//下限
sbit DQ=P2^2; //定义DS18B20总线I/O
signed char w,bj,bjx,bjd; //温度值全局变量
uchar c; //温度值全局变量
bit bdata flag=0,flag_BJ,flag_off=1,que;
//时间计算
#define Imax 14000 //此处为晶振为11.0592时的取值,
#define Imin 8000 //如用其它频率的晶振时,
#define Inum1 145 //要改变相应的取值。
#define Inum2 700
#define Inum3 3000
//解码变量
unsigned char Im[4]={0x00,0x00,0x00,0x00};
//全局变量
uchar f;
unsigned char m,Tc;
unsigned char IrOK;
//设置变量
uchar xx=29;
//下限
uchar sx=35;
//上限
int ds=0;
uchar Mode=0;
void delay(uint z)
{
uint i,j;
for(i=0;i0;i--)
{
DQ = 0; // 给脉冲信号
dat>>=1;
DQ = 1; // 给脉冲信号
if(DQ)
dat|=0x80;
Delay_DS18B20(4);
}
return(dat);
}
/*****写一个字节*****/
void WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 1;
DQ = dat&0x10;
Delay_DS18B20(5);
DQ = 0;
dat>>=1;
}
}
/*****读取温度*****/
unsigned int ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
unsigned int t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xC1); //跳过读序号列号的操作
WriteOneChar(0x44); //启动温度转换
Init_DS18B20();
WriteOneChar(0xC1); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
a=ReadOneChar(); //读低8位
b=ReadOneChar(); //读高8位
t=b;
t<<=8;
t=t|a;
tt=t*0.00625;
t= tt*10+0.5; //放大10倍输出并四舍五入
return(t);
}
/*****读取温度*****/
void check_wendu(void)
{
c=ReadTemperature()-5; //获取温度值并减去DS18B20的温漂误差
w=c/10; //计算得到整数位
if(w<0){w=0;} //设置温度显示上限
if(w>99){w=99;} //设置温度显示上限
}
/**************************************************************************************************
***************************************************************************************************
**************************************************************************************************/
/**************************************************************************************************
************************************按键工作程序***************************************************
**************************************************************************************************/
void Key()
{
//模式选择
if(Key1==0)
{
while(Key1==0);
Feng=0;
Mode++;
Display_wd();
if(Mode==4)
{
Mode=1;
Feng=1;
}
write_com(0x38);//屏幕初始化
write_com(0x0d);//打开显示 无光标 光标闪烁
write_com(0x06);//当读或写一个字符是指针后一一位
switch(Mode)
{
case 1:
{
write_com(0x80+15);//位置
Feng=1;
break;
}
case 2:
{
write_com(0x80+0x40+5);//位置
Feng=1;
break;
}
case 3:
{
write_com(0x80+0x40+14);//位置
Feng=1;
break;
}
}
}
if(Key2==0&&Mode!=0)
{
while(Key2==0);
Feng=0;
switch(Mode)
{
case 1:
{
if(ds<999)
{
ds++;
write_com(0x80+13);
write_data('0'+ds/100);
write_data('0'+ds/10%10);
write_data('0'+ds%10);
write_com(0x80+15);//位置
}
Feng=1;
break;
}
case 2:
{
if(sx<99-1)
{
sx++;
write_com(0x80+0x40+4);
write_data('0'+sx/10%10);
write_data('0'+sx%10);
write_com(0x80+0x40+5);//位置
}
Feng=1;
break;
}
case 3:
{
if(xx0)
{
ds--;
write_com(0x80+13);
write_data('0'+ds/100);
write_data('0'+ds/10%10);
write_data('0'+ds%10);
write_com(0x80+15);//位置
}
Feng=1;
break;
}
case 2:
{
if(sx>xx+1)
{
sx--;
write_com(0x80+0x40+4);
write_data('0'+sx/10%10);
write_data('0'+sx%10);
write_com(0x80+0x40+5);//位置
}
Feng=1;
break;
}
case 3:
{
if(xx>0)
{
xx--;
write_com(0x80+0x40+13);
write_data('0'+xx/10%10);
write_data('0'+xx%10);
write_com(0x80+0x40+14);//位置
}
Feng=1;
break;
}
}
}
if(Key4==0)
{
while(Key4==0);
Feng=0;
Mode=0;
// write_com(0x38);//屏幕初始化
// write_com(0x0c);//打开显示 无光标 无光标闪烁
Init1602();
if(ds>0)
{
flag=1;
jdq=1;
TR1=1;
}
Feng=1;
}
if(IrOK==1)
{
if(Im[2]==0x0d) //遥控设置键
{
Feng=0;
Mode++;
Display_wd();
if(Mode==4)
{
Mode=1;
Feng=1;
}
write_com(0x38);//屏幕初始化
write_com(0x0d);//打开显示 无光标 光标闪烁
write_com(0x06);//当读或写一个字符是指针后一一位
switch(Mode)
{
case 1:
{
write_com(0x80+15);//位置
Feng=1;
break;
}
case 2:
{
write_com(0x80+0x40+5);//位置
Feng=1;
break;
}
case 3:
{
write_com(0x80+0x40+14);//位置
Feng=1;
break;
}
}
}
//+键
else if(Im[2]==0x40)
{
if(Mode!=0)
{
Feng=0;
switch(Mode)
{
case 1:
{
if(ds<999)
{
ds++;
write_com(0x80+13);
write_data('0'+ds/100);
write_data('0'+ds/10%10);
write_data('0'+ds%10);
write_com(0x80+15);//位置
}
Feng=1;
break;
}
case 2:
{
if(sx<99-1)
{
sx++;
write_com(0x80+0x40+4);
write_data('0'+sx/10%10);
write_data('0'+sx%10);
write_com(0x80+0x40+5);//位置
}
Feng=1;
break;
}
case 3:
{
if(xx0)
{
ds--;
write_com(0x80+13);
write_data('0'+ds/100);
write_data('0'+ds/10%10);
write_data('0'+ds%10);
write_com(0x80+15);//位置
}
Feng=1;
break;
}
case 2:
{
if(sx>xx+1)
{
sx--;
write_com(0x80+0x40+4);
write_data('0'+sx/10%10);
write_data('0'+sx%10);
write_com(0x80+0x40+5);//位置
}
Feng=1;
break;
}
case 3:
{
if(xx>0)
{
xx--;
write_com(0x80+0x40+13);
write_data('0'+xx/10%10);
write_data('0'+xx%10);
write_com(0x80+0x40+14);//位置
}
Feng=1;
break;
}
}
}
}
//确定键
else if(Im[2]==0x15)
{
Feng=0;
Mode=0;
Init1602();
if(ds>0)
{
flag=1;
jdq=1;
TR1=1;
}
Feng=1;
}
IrOK=0;
}
}
/**************************************************************************************************
***************************************************************************************************
**************************************************************************************************/
/**************************************************************************************************
************************************报警部分程序***************************************************
**************************************************************************************************/
void Alam()
{
if(flag_BJ==1&&flag_off==1)
{
Feng=0;
delay(1000);
Feng=1;
flag_off=0;
// flag_BJ=0;
}
}
/**************************************************************************************************
***************************************************************************************************
**************************************************************************************************/
/**************************************************************************************************
*********************************************主程序************************************************
**************************************************************************************************/
void main()
{
Init1602();
EA=1;//打开中断总开关
IT1=1;//下降沿有效
EX1=1;//外部中断1开
ET1=1;//打开允许开关
TMOD=0x01;//设置工作方式
TL1=0x3c;
TH1=0xb0;//赋初值
TH0=0;//T0赋初值
TL0=0;
TR0=0;//t0开始计时
check_wendu();
delay(1000);
bjd=99;
bjx=0; //这两个变量的作用就是,防止温度大范围跳动造成加热设备误动作
while(1)
{
check_wendu();
if(Mode==0)
{
Display_1602(c,ds,sx,xx);
if((xia==1)&&(shang==1)) //低于下限
{
que=1;
shui=0;
jdq=1;
}
else
{
que=0;
}
if((shang==0)&&(xia==0)) //高于上限
{
shui=1;
if(flag_BJ==0)
flag_BJ=1;
}
if((shang==0)&&(xia==1)) //错误
{
shui=1;
jdq=1;
Feng=0;
que=1;
}
if(flag==0)
{
if((wbjx))
{
if(w>=sx)
{
jdq=1;
if(flag_BJ==0)
flag_BJ=1;
}
else if((w=sx)
{
jdq=1;
if(flag_BJ==0)
flag_BJ=1;
}
else if((w