在日常生活中温度在我们身边无时不在,温度的控制和应用在各个领域都有重要的作用。很多行业中都有大量的用电加热设备,和温度控制设备,如用于报警的温度自动报警系统,热处理的加热炉,用于融化金属的坩锅电阻炉及各种不同用途的温度箱等,这些都采用单片机技术,利用单片机语言程序对它们进行控制。而单片机技术具有控制和操作使用方便、结构简单便于修改和维护、灵活性大且具有一定的智能性等特点,可以精确控制技术标准,提高了温控指标,也大大的提高了产品的质量和性能。
由于单片机技术的优点突出,智能化温度控制技术正被广泛地采用。本文介绍了基于单片机STC89C52 的温度控制系统的设计方案与软硬件实现。采用温度传感器DS18B20 采集温度数据,7段数码管显示温度数据,按键设置温度上下限,当设置为低于下降报警时,当温度低于设定的下限时,点亮发光二极管同时继电器工作,启动加热设备,当温度上升到上限时,断开继电器,停止加热设备工作,如此循环。当设置为高于上限报警时,当温度高于设定的上限时,点亮发光二极管同时继电器工作,启动制冷设备,当温度下降到下限时,熄灭LED,同时断开继电器,使制冷设备停止工作,使温度控制在上下限范围内。上限报警或者是下限报警可以设置,上限和下限温度也可以设置,同时设置的数据掉电后可以存储。给出了系统总体框架、程序流程图和Protel 原理图,并在硬件平台上实现了所设计功能。
温度传感器是DS18B20,显示模块是LCD1602或者数码管都可以,JLC的原理图PCB是数码管,AD的原理图PCB是LCD1602,原理图PCB和下载程序我都放在附件中,供大家参考或者使用
PCB:
AD:
JLC:
原理图:
AD:
JLC:
材料清单:
单片机:STC89C52 1片
传感器:DS18B20 1只
晶振: 11.0592MHz 1只
电容: 33pf 2个
22uf电解电容 1个
电阻: 10k 1个
4.7k 1个
1k 1个
排阻: 4.7k 9脚 1排
PNP三极管:9012或者8550或者5401 1只
蜂鸣器: 1个
轻触按钮:5个
四位一体共阴极数码管:1个
红色发光二极管: 1个
万用板: 1块
导线: 若干
代码比较长,但是愿意花心思去理解的话不会难的,下载程序我放在附件供大家下载使用
#include<reg52.h>
#include"stdio.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
/***************************************************/
sbit RS =P2^6; //LCD1602的数据命令选择
sbit RW = P2^5;
sbit EN_LCD =P2^7; //LCD1602的使能信号
sbit BUZZER = P2^0;
sbit K1 = P1^0; //右
sbit K2 = P1^1; //加
sbit K3 = P1^2; //减
/****************DS18B20引脚**********************/
sbit DS18B20 = P1^3; //DS18B20数据端
/***********************************************************/
/******************************************************/
void delay(uint16 time); // 延时函数(6us单位)
void lcd_ini(); // LCD1602的初始化
void lcd_order(uint8 date); // 向LCD1602的写1个指令
void lcd_data(uint8 date); // 向LCD1602的写1个指令
void xie1602(uint8 add,uint8 daa); //写数据
void xianshi1();//显示温度
uint8 ds18_ini(); //ds18B20初使化函数
void ds18_write(uint8 date); //功能向DS18B20中写入一个数据
uint8 ds18_read(); //功能从DS18B20中读出一个数据并返回。
void ds18_check(); //起动DS18B20行进温度采集,并返回当前温度(tmp)
void xiugai(); //修改报警范围
long tmp=0; //储存温度值
long t_h=37, t_l=10; // 温度的上限和下限
bit tmp_hb = 0; tmp_lb = 0; //温度上下限调节指示变量
void panduan(); //判断报警
uint8 hodometer[]= " H:00 L: 00 ";
uint8 temp[]= " wendu:00.00 ";
uint16 ji = 0;
uint8 ku=0; //biaozhiwei
void main()
{
lcd_ini();
ds18_ini(); //ds18B20初使化
ds18_write(0xcc); //跳过序列号
ds18_write(0x44); //启动温度转换
xie1602(4,t_h);
xie1602(12,t_l);
while(1)
{
ds18_check(); //从DS18B20中读出温度
xianshi1();
xiugai();
panduan();
}
}
void xie1602(uint8 add,uint8 daa)
{
lcd_order(0x80+add);
lcd_data(0x30+daa/10);
lcd_data(0x30+daa%10);
}
//判断是否在报警范围内
void panduan()
{
if(tmp<(t_l*1000)||tmp>(t_h*1000)&&t_l>=0)
{
BUZZER = 0;
delay(10);
}
else if(t_l<0&&tmp>(t_h*1000))
{
BUZZER = 1;
}
else
BUZZER = 1;
}
//选择修改的内容
void xiugai()
{ uint8 jj;
uint8 i = 0;
BUZZER = 1;
if(K1==0)
{
while(!K1);
while(1)
{
lcd_order(0x0f); //开启光标显示
lcd_order(0x80+5);//光标显示位置
if(K2 == 0) //判断加按键按下
{
while(K2 == 0); //等待按键释放
t_h++; //温度上限加1
xie1602(4,t_h); //将温度上限显示出来
}
if(K3 == 0) //判断减按键按下
{
while(K3 == 0); //等待按键释放
if(t_h>t_l) //判断 温度上限大于温度下限
t_h--;
xie1602(4,t_h); //将温度上限显示出来
}
if(K1 == 0) //后面的注释类似
{
while(K1 == 0);
while(1)
{
lcd_order(0x0f);
lcd_order(0x80+13);
if(K2 == 0)
{
while(K2 == 0);
if(t_l<t_h&&t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
t_l++;
xie1602(12,t_l);
}
else {
t_l++;
jj = ~t_l;
xie1602(12,jj);
}
}
if(K3 == 0)
{
while(K3 == 0);
if(t_l>(-50))
{
t_l--;
if(t_l<0)
jj = ~t_l;
}
if(t_l>=0)
{
lcd_order(0x80+11);
lcd_data(' ');
xie1602(12,t_l);
}
if(t_l<0)
{
xie1602(12,jj);
lcd_order(0x80+11);
lcd_data('-');
}
}
if(K1 == 0)
{
while(K1 == 0);
goto loop;
}
}
}
}
}
loop:BUZZER = 1;
}
/**********************************************
函数名:delay
行参 :time 延时基数
功能 :用while延时
************************************************/
// 延时函数(1ms单位)
void delay(uint16 time)
{
while(time--);
}
/**********************************************
函数名:lcd_ini
功能 :LCD1602的初始化
************************************************/
void lcd_ini()
{
uint8 i;
RW = 0;
lcd_order(0x38); //设置1602的显示光标功能
delay(100);
lcd_order(0x0e); //显示开及光标设置
delay(100);
lcd_order(0x06); //显示光标移动设置
delay(100);
lcd_order(0x01); //显示清屏
delay(100);
lcd_order(0x80);
for(i = 0;i<16;i++)
lcd_data(hodometer[i]);
}
/**********************************************
函数名:lcd_order
行参 :date 要定入的指令
功能 :向LCD1602的写1个指令
************************************************/
void lcd_order(uint8 date)
{
RS=0; //选择写指令
EN_LCD=0; //使能初使化
P0=date; //发送指令
EN_LCD=1; //开使能
delay(100); //延时
EN_LCD=0; //关使能
}
/**********************************************
函数名:lcd_order
行参 :date 要定入的指令
功能 :向LCD1602的写1个指令
************************************************/
void lcd_data(uint8 date)
{
RS=1; //选择写数据
EN_LCD=0; //使能初使化
P0=date; //发送指令
EN_LCD=1; //开使能
delay(100); //延时
EN_LCD=0; //关使能
}
/*************************************************************
DS18B20
**************************************************************/
/****************************************
函数名: ds18_ini
功能: 对DS18B20进行初使化,
若DS18B20是好的则返回1
若DS18B20是环的则返回0
****************************************/
//ds18B20初使化函数,可根据资料上的时序来写
uint8 ds18_ini()
{
uint8 ans;
DS18B20 = 1;
delay(1);
DS18B20 = 0;
delay(100);
DS18B20 = 1;
delay(6);
ans = DS18B20;
delay(100);
if(!ans)
return 1;
else
return 0;
}
/**********************************
函数名: ds18_write
函数行参: date(向ds18b20写入的数据)
功能: 功能向DS18B20中写入一个数据
***********************************/
void ds18_write(uint8 date)
{
uint8 i;
DS18B20=1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DS18B20 = 0;
if(date&0x01) //从低到高取出数据的每位
DS18B20 = 1;
else
DS18B20 = 0;
delay(10);
DS18B20 = 1;
date>>=1;
delay(1);
}
}
/*************************************************
函数名: ds18_read
函数返回值:rate(从ds18b20中读出的数据)
功能: 功能从DS18B20中读出一个数据并返回。
*************************************************/
uint8 ds18_read()
{
uint8 i,date = 0;
DS18B20 = 1; //释放总线
delay(1);
for(i = 0;i < 8;i ++) //根据时序将数据从低到高一位一位接收
{
DS18B20 = 0;
date >>= 1;
DS18B20 = 1;
if(DS18B20)
date |= 0x80; //将date的一位置1
delay(8);
DS18B20 = 1;
delay(1);
}
return date; //返回读出的数
}
/************************************************************
函数名: ds18_check
函数返回值: tmp(当前温度)
功能: 起动DS18B20行进温度采集,并返回当前温度(tmp)
*************************************************************/
void ds18_check()
{
uint8 date1,date2;
float ta;
if(ds18_ini())
{
ds18_write(0xcc); //跳过序列号
ds18_write(0x44); // 启动温度转换
ds18_ini(); // 复位
ds18_write(0xcc); //跳过序列号
ds18_write(0xbe); // 启动读取温度
date1 = ds18_read(); //读取两个温度字节
date2 = ds18_read();
tmp=date2;
tmp<<=8;
tmp=tmp|date1;
ta=tmp*0.0625;
tmp=ta*1000;
}
}
void xianshi1()
{
uint8 i;
temp[8]=0x30+tmp/10000;
temp[9]=0x30+tmp/1000%10;
temp[11]=0x30+tmp/100%10;
temp[12]=0x30+tmp/10%10;
temp[13]=0x30+tmp%10;
lcd_order(0x80+0x40);
for(i = 0;i<16;i++)
lcd_data(temp[i]);
}