1实现功能
可进行温度值的实时显示,精度为0.1摄氏度;
使用数码管作为显示设备;
检测范围是-55~125摄氏度;
可通过按键设置温度的报警范围;
温度过低,绿色指示灯亮,蜂鸣器响,加热膜加热,模拟升温装置;
温度过高,红色指示灯亮,蜂鸣器响,小风扇转动,模拟降温装置;
2硬件准备
STC89C52 | 1片 |
单片机座子 | 1个 |
12M晶振 | 1个 |
30pF独石电容 | 2个 |
电解电容10uF | 1个 |
电解电容220uF | 1个 |
电阻1K | 5个 |
电阻4.7K | 1个 |
电阻10K | 1个 |
排阻1K | 1片 |
轻触开关 | 3个 |
0.36寸4位共阴数码管 | 1个 |
DS18B20传感器 | 1个 |
DS18B20座子 | 1个 |
有源蜂鸣器 | 1个 |
S8550(PNP)三极管 | 3个 |
绿色led灯 | 1个 |
红色led灯 | 1个 |
5V继电器 | 2个 |
继电器端子 | 2个 |
1N4148二极管 | 2个 |
小风扇 | 1个 |
加热膜 | 1个 |
电源开关 | 1个 |
电源插座 | 1个 |
9*15洞洞板 | 1张 |
导线 | 若干 |
电源线 | 1根 |
3方案设计
一、概述
整个系统以STC89C52单片机为核心器件,配合电阻电容晶振等器件,构成单片机的最小系统。其它个模块围绕着单片机最小系统展开。其中包括,传感器采用DS18B20,负责采集温度数据后发给单片机。显示设备采用4位共阴数码管,显示检测到的温度值。按键模块,主要是进行报警值的设置。报警模块采用蜂鸣器+LED的模式,超出报警范围则进行声光报警,同时还有升温和降温装置工作,使得温度恒定在一个范围之内。
二、主要元件介绍
(1)、STC89C52
STC89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的STC89C52单片机可为您提供许多较复杂系统控制应用场合。
STC89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线。STC89C52有PDIP、PQFP/TQFP及PLCC等三种封装形式,以适应不同产品的需求。
(2)、DS18B20传感器
DS18B20是美国DALLAS半导体公司推出的第一片支持“一线总线”接口的温度传感器,它具有微型化,低功耗,高性能,抗干扰能力强,易配微处理器等优点,可直接将温度转化成数字信号处理器处理。测量的温度范围是-55~125℃,测温误差0.5℃。可编程分辨率9~12位,对应的可分辨温度分别为0.5℃,0.25℃,0.125℃和0.0625℃。相较热电偶传感器而言可实现高精度测温。
(3)、数码管
数码管是一类价格便宜、使用简单,通过对其不同的管脚输入相对的电流,使其发亮,从而显示出数字能够显示 时间、日期、温度等所有可用数字表示的参数的器件。在电器特别是家电领域应用极为广泛,如显示屏、空调、热水器、冰箱等等。LED数码管(LED Segment Displays)由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。这些段分别由字母a,b,c,d,e,f,g,dp来表示。当数码管特定的段加上电压后,这些特定的段就会发亮,以形成我们眼睛看到的字样了。如:显示一个“2”字,那么应当是a亮b亮g亮e亮d亮f不亮c不亮dp不亮。
4实现代码
/*基于51单片机的温度控制恒温箱设计
*/
#include <reg52.h> // 包含头文件
#include <intrins.h>
#define uchar unsigned char // 以后unsigned char就可以用uchar代替
#define uint unsigned int // 以后unsigned int 就可以用uint 代替
sbit DQ = P1^1; // DS18B20传感器的引脚定义
sbit w1 = P2^4; // 数码管第1位的控制引脚
sbit w2 = P2^5; // 数码管第2位的控制引脚
sbit w3 = P2^6; // 数码管第3位的控制引脚
sbit w4 = P2^7; // 数码管第4位的控制引脚
sbit Buzzer = P1^0; // 蜂鸣器引脚
sbit JdqLow = P2^0; // 温度过低继电器控制(加热)
sbit JdqHig = P2^1; // 温度过高继电器控制(降温)
sbit LedLow = P2^2; // 温度低指示灯
sbit LedHig = P2^3; // 温度高指示灯
sbit KeySet = P3^2; // 设置按键
sbit KeyDown = P3^3; // 减按键
sbit KeyUp = P3^4; // 加按键
/* 数码管的显示值: 0 1 2 3 4 5 6 7 8 9 - */
uchar code Array1[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40 };
/* 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. */
uchar code Array2[]={ 0xBf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef };
uchar Buff[4]; // 显示缓冲区
uchar ShowID=1; // 当前显示的是哪一个数码管
int AlarmLow=150; // 默认报警的温度下限值是15度
int AlarmHig=300; // 默认报警的温度上限值是30度
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 延时15微秒
/*********************************************************/
void Delay15us(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/*********************************************************/
// 复位DS18B20(初始化)
/*********************************************************/
void DS18B20_ReSet(void)
{
uchar i;
DQ=0;
i=240;
while(--i);
DQ=1;
i=30;
while(--i);
while(~DQ);
i=4;
while(--i);
}
/*********************************************************/
// 向DS18B20写入一个字节
/*********************************************************/
void DS18B20_WriteByte(uchar dat)
{
uchar j;
uchar btmp;
for(j=0;j<8;j++)
{
btmp=0x01;
btmp=btmp<<j;
btmp=btmp&dat;
if(btmp>0) // 写1
{
DQ=0;
Delay15us();
DQ=1;
Delay15us();
Delay15us();
Delay15us();
Delay15us();
}
else // 写0
{
DQ=0;
Delay15us();
Delay15us();
Delay15us();
Delay15us();
DQ=1;
Delay15us();
}
}
}
/*********************************************************/
// 读取温度值
/*********************************************************/
int DS18B20_ReadTemp(void)
{
uchar j;
int b,temp=0;
DS18B20_ReSet(); // 产生复位脉
DS18B20_WriteByte(0xcc); // 忽略ROM指令
DS18B20_WriteByte(0x44); // 启动温度转换指令
DS18B20_ReSet(); // 产生复位脉
DS18B20_WriteByte(0xcc); // 忽略ROM指令
DS18B20_WriteByte(0xbe); // 读取温度指令
for(j=0;j<16;j++) // 读取温度数量
{
DQ=0;
_nop_();
_nop_();
DQ=1;
Delay15us();
b=DQ;
Delay15us();
Delay15us();
Delay15us();
b=b<<j;
temp=temp|b;
}
temp=temp*0.0625*10; // 合成温度值并放大10倍
return (temp); // 返回检测到的温度值
}
/*********************************************************/
// 定时器初始化
/*********************************************************/
void TimerInit()
{
TMOD = 0x01; // 使用定时器0,工作方式1
TH0 = 248; // 给定时器0的TH0装初值
TL0 = 48; // 给定时器0的TL0装初值
ET0 = 1; // 定时器0中断使能
EA = 1; // 打开总中断
TR0 = 1; // 启动定时器0
}
/*********************************************************/
// 显示温度值
/*********************************************************/
void ShowTemp(int dat)
{
if(dat<0) // 负号
{
Buff[0]=Array1[10];
dat=0-dat;
}
else // 百位
{
Buff[0]=Array1[dat/1000];
}
Buff[1]=Array1[dat%1000/100]; // 十位
Buff[2]=Array2[dat%100/10]; // 个位
Buff[3]=Array1[dat%10]; // 小数后一位
}
/*********************************************************/
// 报警判断
/*********************************************************/
void AlarmJudge(int dat)
{
if(dat<AlarmLow) // 判断温度是否过低
{
LedLow=0; // 温度低指示灯亮
LedHig=1; // 温度高指示灯灭
JdqLow=0; // 温度过低的继电器闭合(开始加热)
JdqHig=1; // 温度过高的继电器断开(停止降温)
Buzzer=0; // 蜂鸣器报警
}
else if(dat>AlarmHig) // 判断温度是否过高
{
LedLow=1; // 温度低指示灯灭
LedHig=0; // 温度高指示灯亮
JdqLow=1; // 温度过低的继电器断开(停止加热)
JdqHig=0; // 温度过高的继电器闭合(开始降温)
Buzzer=0; // 蜂鸣器报警
}
else // 温度正常
{
LedLow=1; // 温度低指示灯灭
LedHig=1; // 温度高指示灯灭
JdqLow=1; // 温度过低的继电器断开(停止加热)
JdqHig=1; // 温度过高的继电器断开(停止降温)
Buzzer=1; // 蜂鸣器停止报警
}
}
/*********************************************************/
// 按键扫描
/*********************************************************/
void KeyScanf()
{
if(KeySet==0) // 如果设置按键被按下
{
/* 设置温度下限 */
LedLow=0; // 点亮绿色灯(代表当前正在设置温度下限)
LedHig=1; // 熄灭红色灯
Buzzer=1; // 关闭蜂鸣器
ShowTemp(AlarmLow); // 显示温度下限值
DelayMs(10); // 延时去抖
while(!KeySet); // 等待按键释放
DelayMs(10); // 延时去抖
while(1)
{
if(KeyDown==0) // 如果“减”按键被按下
{
if(AlarmLow>-550) // 判断当前温度下限是否大于-55度
{
AlarmLow--; // 温度下限值减去0.1度
ShowTemp(AlarmLow); // 刷新显示改变后的温度下限值
DelayMs(200); // 延时
}
}
if(KeyUp==0) // 如果“加”按键被按下
{
if(AlarmLow<1250) // 判断当前温度下限是否小于125度
{
AlarmLow++; // 温度下限值加上0.1度
ShowTemp(AlarmLow); // 刷新显示改变后的温度下限值
DelayMs(200); // 延时
}
}
if(KeySet==0) // 如果“设置”按键被按下
{
break; // 退出温度下限值的设置,准备进入上限值的设置
}
}
/* 设置温度上限 */
LedLow=1; // 熄灭绿色灯
LedHig=0; // 点亮红色灯(代表当前正在设置温度上限)
ShowTemp(AlarmHig); // 显示温度上限值
DelayMs(10); // 延时去抖
while(!KeySet); // 等待按键释放
DelayMs(10); // 延时去抖
while(1)
{
if(KeyDown==0) // 如果“减”按键被按下
{
if(AlarmHig>-550) // 判断当前温度上限是否大于-55度
{
AlarmHig--; // 温度上限值减去0.1度
ShowTemp(AlarmHig); // 刷新显示改变后的温度上限值
DelayMs(200); // 延时
}
}
if(KeyUp==0) // 如果“加”按键被按下
{
if(AlarmHig<1250) // 判断当前温度上限是否小于125度
{
AlarmHig++; // 温度上限值加上0.1度
ShowTemp(AlarmHig); // 刷新显示改变后的温度上限值
DelayMs(200);
}
}
if(KeySet==0) // 如果“设置”按键被按下
{
break; // 准备退出设置模式
}
}
/* 退出设置模式 */
LedLow=1; // 熄灭绿灯
LedHig=1; // 熄灭红灯
DelayMs(10); // 延时去抖
while(!KeySet); // 等待按键释放
DelayMs(10); // 延时去抖
}
}
/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
int temp;
uchar i;
TimerInit(); // 定时器0的初始化(数码管的动态扫描)
Buff[0]=Array1[0]; // 刚上电显示4个0
Buff[1]=Array1[0];
Buff[2]=Array1[0];
Buff[3]=Array1[0];
for(i=0;i<8;i++) // 由于传感器刚上电读出的温度不稳定,因此先进行几次温度的读取并丢弃
{
DS18B20_ReadTemp();
DelayMs(120);
}
while(1)
{
EA=0; // 屏蔽中断
temp=DS18B20_ReadTemp(); // 读取温度值
EA=1; // 恢复中断
ShowTemp(temp); // 显示温度值
AlarmJudge(temp); // 判断是否需要报警
for(i=0;i<100;i++) // 延时并进行按键扫描
{
KeyScanf();
DelayMs(10);
}
}
}
/*********************************************************/
// 定时器0服务程序
/*********************************************************/
void Timer0(void) interrupt 1
{
TH0 = 248; // 给定时器0的TH0装初值
TL0 = 48; // 给定时器0的TL0装初值
P0=0x00; // 先关闭所有显示
w1=1;
w2=1;
w3=1;
w4=1;
if(ShowID==1) // 判断是否显示第1位数码管
{
w1=0; // 打开第1位数码管的控制开关
P0=Buff[0]; // 第1位数码管显示内容
}
if(ShowID==2) // 判断是否显示第2位数码管
{
w2=0; // 打开第2位数码管的控制开关
P0=Buff[1]; // 第2位数码管显示内容
}
if(ShowID==3) // 判断是否显示第3位数码管
{
w3=0; // 打开第3位数码管的控制开关
P0=Buff[2]; // 第3位数码管显示内容
}
if(ShowID==4) // 判断是否显示第4位数码管
{
w4=0; // 打开第4位数码管的控制开关
P0=Buff[3]; // 第4位数码管显示内容
}
ShowID++; // 切换到下一个数码管的显示
if(ShowID==5)
ShowID=1;
}