您好,欢迎访问代理记账网站
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

基于51单片机的温度报警系统

目录

前言

一、温控系统是什么?

二、设计目的

1.环境需求

2.设计基础

三、设计

1.C51程序设计

2.Proteus仿真

(1).元器件如下

(2).原理图。

总结


前言

微型计算器自20世纪70年代诞生以来,得以迅速发展、普及和应用。随着增强型8051单片机和嵌入式微处理器技术的飞速发展,以及单片机C语言应用的普及,单片机应用领域越来越广泛。

 

一、温控系统是什么?

随着社会的快速发展,科技的加速进步,测温仪器在各个领域应用越来越广泛,自动化和智能化已经成为现代的温度控制系统的主流发展方向。因为各行各业对于温度控制有着越来越高的要求,所以对温度的控制和测量就显得较为重要。温度控制器的使用范围越来越广泛,各种能够应用于不同领域的智能自动温度控制器随着产生。自动温度控制系统主要完成数据采集,温度定时的显示,温度控制,温度定时的设定以及报警等功能.

二、设计目的

对51单片机所学知识进一步强化理解和应用。

1.环境需求

软件:Proteus  (文章中使用Proteus 8.6)

          Keil (文章中使用Keil C51)

2.设计基础

掌握《C语言》、《单片机原理及应用》两门课程。

三、设计

1.C51程序设计

/*-----------------------------------------------
  名称:18B20温度测量报警
  内容:在LCD1602第一行可以显示当前温度,
		第二行显示设定的温度区间,超过此温度区间,蜂鸣器报警。
		温度区间可以通过用户按键设置
------------------------------------------------*/
#include<reg51.h>     //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<math.h>
#include<INTRINS.H>

#define uchar unsigned char
#define uint unsigned int 
/******************************************************************/
/*                    定义端口                                    */
/******************************************************************/
sbit led1=P1^3;// 温度超出范围指示灯
sbit led2=P1^4;

sbit buzzer=P3^3;//蜂鸣器引脚

sbit DQ=P3^7;//ds18b20 端口

sbit RS = P0^4;//1602数据/命令选择端(H:数据寄存器L:指令寄存器) 
sbit RW = P0^5;//1602读/写选择端 
sbit E  = P0^6;//1602使能信号端

sbit key1=P3^4;//用户按键
sbit key2=P3^5;
sbit key3=P3^6;
/******************************************************************/
/*                    全局变量                                    */
/******************************************************************/
int temp;//测得温度
char temp_max=40,temp_min=10;//设定的温度 
char TempH,TempL;
uchar flag_get,num=0;
uchar code tab[]={'0','1','2','3','4','5','6','7','8','9'};//液晶显示
uchar tab1[]="min:010  max:040";//液晶第二行显示内容
uchar  str[8];
/******************************************************************/
/*                    延时函数                                    */
/******************************************************************/
void delay1(uint i)//短延时函数
{
 	while(i--);
}
void delay(uint z) //长延时函数
{
	uint x,y;
	for(x=z;x>0;x--)
		for(y=110;y>0;y--);
}
/******************************************************************/
/*                   DS18B20 初始化                               */
/******************************************************************/
void Init_DS18B20(void)
{
	uchar x=0;
	DQ = 1;    //拉高总线,等待
 	delay1(8);
 	DQ = 0;    //单片机将DQ拉低
 	delay1(80); //精确延时 大于 480us
 	DQ = 1;    //拉高总线,等待
 	delay1(10);
 	x=DQ;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
 	delay1(5);
 }


/******************************************************************/
/*                    DS18B20读一个字节                           */
/******************************************************************/
uchar ReadOneChar(void)	// DS18B20读一个字节
{
	uchar i=0;
	uchar dat = 0;
	for (i=8;i>0;i--)
 	{
  		DQ = 0; // 给脉冲信号
  		dat>>=1;
  		DQ = 1; // 给脉冲信号,主机在读时隙期间必须释放总线
  		if(DQ)
   		dat|=0x80;
  		delay1(5);
 	}
 	return(dat);
}


/******************************************************************/
/*                 DS18B20写一个字节                              */
/******************************************************************/
void WriteOneChar(uchar dat) //DS18B20写一个字节
{
 	uchar i=0;
 	for (i=8; i>0; i--)
 	{
  		DQ = 0;
  		DQ = dat&0x01;//取最低位
  		delay1(5);
  		DQ = 1;
  		dat>>=1;//左移
 	}
	delay1(5);
}

/******************************************************************/
/*                   DS18B20读取温度                              */
/******************************************************************/
uint ReadTemperature(void) //DS18B20读取温度
{
	uchar a=0;
	uint b=0;
	uint t=0;
	Init_DS18B20();//DS18B20初始化
	WriteOneChar(0xCC); // 跳过读序号列号的操作
	WriteOneChar(0x44); // 启动温度转换
	delay1(200);       //延时以求信号的稳定
	Init_DS18B20();    //DS18B20再次初始化
	WriteOneChar(0xCC); //跳过读序号列号的操作 
	WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
	a=ReadOneChar();   //低位
	b=ReadOneChar();   //高位
	b<<=8;  //b左移8位
	t=a+b;  //把a与b结合,放在16位的t中   此处两行代码也可用t=((b*256)+1)替代 原理相同
	return(t);
}
/******************************************************************/
/*                   LCD1602写命令操作                            */
/******************************************************************/
void WriteCommand(uchar com)
{
	delay(5);//操作前短暂延时,保证信号稳定
	E=0;
	RS=0;
	RW=0;

	P2=com;
	E=1;
	delay(5);
	E=0;
}
/******************************************************************/
/*                   LCD1602写数据操作                            */
/******************************************************************/
void WriteData(uchar dat)
{
	delay(5);  //操作前短暂延时,保证信号稳定
	E=0;
	RS=1;
	RW=0;

	P2=dat;
	E=1;
	delay(5);
	E=0;
}
/******************************************************************/
/*                   LCD1602初始化程序                            */
/******************************************************************/
void InitLcd()
{
	uchar i;
	delay(15);
	WriteCommand(0x38); //display mode
	WriteCommand(0x06); //显示光标移动位置
	WriteCommand(0x0c); //显示开及光标设置
	WriteCommand(0x01); //显示清屏
	WriteCommand(0x80+0x40);//将光标移到第二行
	for(i=0;i<16;i++)//显示初始化内容
	{
		WriteData(tab1[i]);
		delay(10);
	}
}
/******************************************************************/
/*                  蜂鸣器报警程序                                */
/******************************************************************/
void alarm()
{
	if(TempH>=temp_max)//当温度高于设置的最高温报警
	{	buzzer=0;
		delay(50);
		buzzer=1;
		delay(50);
		led1=0;
		led2=1;
	}
	else if(TempH<temp_min)//当温度低于设置的最低温报警
	{
		buzzer=0;
		delay(50);
		buzzer=1;
		delay(50);
		led1=1;
		led2=0;	
	}
	else//报警解除
	{
	 	buzzer=1;
		led1=1;
		led2=1;
	}
}
/******************************************************************/
/*                   显示测得的温度                               */
/******************************************************************/
void handle_T()
{

	uchar i;
	str[0]=0x20;//显示为空
	str[1]=tab[TempH/100]; //百位温度
   	str[2]=tab[(TempH%100)/10]; //十位温度
   	str[3]=tab[(TempH%100)%10]; //个位温度,带小数点
   	str[5]=tab[TempL];
	str[4]='.';
    str[6]=0xdf;
    str[7]='C';
  	if(flag_get==1)       //定时读取当前温度
    {
  		flag_get=0;       //清标志位
  		temp=ReadTemperature();//读取温度值
  		if(temp&0x8000)
        {
     		str[0]=0xb0;//负号标志
     		temp=~temp;  // 取反加1
	 		temp +=1;
	 	}

        TempH=temp>>4;	//由权重表知移4位就是整数位
  		TempL=temp&0x0F;
  		TempL=TempL*6/10;//小数近似处理

		alarm();    //判断是否需要报警
    }
	WriteCommand(0x80+0x04);//光标指向第一行第一个字符
	for(i=0;i<8;i++)// 显示
	{
		WriteData(str[i]);
		delay(10);
	}
		
}
void display_range(uchar add,int t)
{
	uchar i;
	if(t<0)
	{
		str[0]=0xb0;//负号标志
	}
	else
    {
        str[0]=tab[abs(t)/100]; //百位温度
   	    str[1]=tab[(abs(t)%100)/10]; //十位温度
   	    str[2]=tab[(abs(t)%100)%10]; //个位温度
	    WriteCommand(0x80+0x40+add);
    }
	
	for(i=0;i<3;i++)
	{
		WriteData(str[i]);
		delay(5);
	}
}
/******************************************************************/
/*              独立键盘扫描函数并显示设定的温度                  */
/******************************************************************/
void keyscan()  
{	

	uchar flag1=0,flag2=0;//有按键按下标记
	P3=0xff;//拉高P3口,以读取P3口的值
	
	if(key1==0) //两个按键控制最高/最低温度的加减 按住key1时通过其他2个键控制最高温度的加减
	{
		delay(5);
		if(key2==0)//最高温加
		{
			delay(5);//延时消抖
			if(key2==0)
			{
				temp_max++;
				if(temp_max>=85)
					temp_max=85;
			}
			while(!key2);//松手检测
			flag1=1;
		}
		if(key3==0)//最高温减
		{
			delay(5);
			if(key3==0)
			{
				temp_max--;
				if(temp_max<=temp_min)
					temp_max=temp_min;
			}
			while(!key3);
			flag1=1;
		}
	}
	
	if(key1==1)  //松开key1时通过其他2个键控制最高温度的加减
	{
		delay(5);
		if(key2==0)//最低温加
		{
			delay(5);//延时消抖
			if(key2==0)
			{
				temp_min++;
				if(temp_min>=temp_max)
					temp_min=temp_max;
			}
			while(!key2);//松手检测
			flag2=1;
		}
		if(key3==0)//最低温减
		{
			delay(5);
			if(key3==0)
			{
				temp_min--;
				if(temp_min<=-10)
					temp_min=-10;
			}
			while(!key3);
			flag2=1;
		}
	}

	if(flag1)//如有设置最高温度的键按下,更新设定的温度
	{
		flag1=0;// 清标记
		display_range(0x0d,temp_max);
	}
	if(flag2)//如有设置最低温度的键按下,更新设定的温度
	{
		flag2=0;// 清标记
		display_range(0x04,temp_min);
	}
		
}

/****************************************************************/
/*                    主函数                                    */
/******************************************************************/
void main()
{	
	TMOD|=0x01;//定时器设置
	TH0=0xEF;//装初始值
	TL0=0xF0;    
	EA=1;// 开总中断
	ET0=1;//允许定时器0中断
	TR0=1;//开定时器0中断
	InitLcd();//lcd1602初始化
	flag_get=1;
	while(1)
	{
		handle_T();// 处理温度:获得、显示、报警
		keyscan();  //独立按键扫描
  	} 
}
/******************************************************************/
/*    定时0中断处理程序,用于温度检测间隔,大约1秒测一次温度      */
/******************************************************************/
void timer0(void) interrupt 1 using 1
{
	TH0=0xEF;//定时器重装值
	TL0=0xF0;
	num++;
	if (num==50)
    {
		num=0;
	  	flag_get=1;//标志位有效,开始测温
	}
}

PS:按键控制温度加减区块也可用此种类型做到松手检测   (具体如何操作不做叙述)当然如果觉得2个按键控制可能因为抖动影响结果,可以更换其他方法。

if(key2==0&&flag==0)
{
	flag=1;
}
if(flag==1&&key2==1)
{
	temp_max++;
	if(temp_max>=85)
	temp_max=85;
	flag=0;
}

因为涉及到C语言部分知识的解析,分装代码将在下一篇文章中更新。(不是没有做出来,下图。下篇打包发出,需要自取。)

2.Proteus仿真

以Proteus 8.6为例 (PS:本人在使用Proteus 8.9过程中出现LCD1602显示屏第一行无法正常工作,被迫使用Proteus 8.6。没有找到问题原因,欢迎大佬留言解答。)

(1).元器件如下

关于buzzer(蜂鸣器)的选择,选择第二个即可。

LCD602在Proteus中选择LM016。

(2).原理图。

(PS:框框里的红色部分可以不用画,多余的,自己测speaker的工作原理时用到了没有删。)

按键控制这块再说一下,此文章中使用的是两个的按键控制温度加减。

按住key0,key1-->最高温度加,key2-->最高温度减。

松开key0(即默认),key1-->最低温度加,key2-->最低温度减。

从上到下依次key0、key1、key2。

至于怎么按住第一个键,单击按键右侧按钮。(如图啊)


总结

以上便是基于51单片机设计的温度报警系统。细致的讲解在后面更新。

 


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进