基于51单片机的温度控制恒温箱设计

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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值