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

软件开发大郭
0 评论
/
36 阅读
/
11083 字
25 2022-05

一、电路原理图

基于单片机的数据采集系统方案,该方案根据热敏电阻随温度变化而变化的特性,采用串联分压电路。 单片机采集热敏电阻的电压,通过A/D转换将模拟量电压信号转换成数字量电压信号, 经过查表转换得到温度值,控制LCD实时显示温度值。 51单片机NTC测温原理图

二、源码

1.main

代码如下:

#include<reg52.h>				 
#include<intrins.h>
#include"eeprom52.h"		  //调用STC89C52单片机的EEPROM控制程序
#include "math.h"
#include"ADC0832.H"
#define uchar unsigned char		 
#define uint unsigned int		 
#define LCD1602_dat P0			 //LCD1602的数据传输IO口

sbit LCD1602_rs=P2^5;
sbit LCD1602_rw=P2^6; 
sbit LCD1602_e=P2^7;  
sbit beep=P2^0;	 //蜂鸣器IO
sbit led_1=P1^5; //超上限指示灯
sbit led_2=P1^6;//超下限指示灯

sbit key_1=P3^5;  //设置按键
sbit key_2=P3^6;//加按键
sbit key_3=P3^7;//减按键

uchar dat=0;       //AD值
uint c,d;
uint DY_dat=0;    
uchar ad_dat1=0;   //读取滤波后的AD值

float adc_value;	//暂存读取的输入变量

int temp;	//读取
char temp_h,temp_l;	//温度上下限制存储变量
uchar state,ms;	   //系统设置项变量、50ms定时变量

bit s1,beep1;	//设置闪烁标志位、报警标志位

void delay(uint T)		//系统延时程序
{
	while(T--);
}

//延时函数,i=1时,大约延时10us
void delay10us(uint c)
{
	uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}	
}

void Read_ad()
{

  static uint AD_DAT=0;		 
	float ad_buf=0;				
	static uchar i=0;			//定义三个变量
	if(i<5)		 		//累加,然后除以5,求取5次的平均值
	{
		i++;
		AD_DAT+=A_D();		// 波
	}
	else					
	{
		i=0;				//清零,方便下次计算 
		ad_dat1=(uchar)(AD_DAT/5);		 //求取平均值
		ad_buf=(float)(ad_dat1/0.51);	 
		DY_dat=(uint)(ad_buf);			 
		AD_DAT=0;						 //清零
	}
}
//1602写如数据函数
void LCD1602_write(uchar order,dat)				  //1602 一个字节  
{
    LCD1602_e=0;
    LCD1602_rs=order;
    LCD1602_dat=dat;
    LCD1602_rw=0;
    LCD1602_e=1;
    delay(1);
    LCD1602_e=0;																								     
}

//1602写入数据函数  指针式
void LCD1602_writebyte(uchar *prointer)				
{
    while(*prointer!='\0')
    {
        LCD1602_write(1,*prointer);
        prointer++;
    }
}

//初始化1602液晶 
void LCD1602_cls()				
{
	LCD1602_write(0,0x01);     //1602 清屏 指令
	delay(1500);
	LCD1602_write(0,0x38);     // 功能设置 8位、5*7点阵
	delay(1500);
	LCD1602_write(0,0x0c);     //设置 光标   
	LCD1602_write(0,0x06);
	LCD1602_write(0,0xd0);
	delay(1500);
}

//LCD1602液晶显示程序 
void show()			//显示数据
{
		LCD1602_write(0,0x80);		   //显示位置设定
		LCD1602_writebyte("Temp:");		//显示当前温度值
		if(temp>=0)			 //显示温度整数部分
		{
		  if(temp>999)LCD1602_write(1,0x30+temp/1000%10);	   
			else LCD1602_writebyte(" ");
			if(temp>99)LCD1602_write(1,0x30+temp/100%10);
			else LCD1602_writebyte(" ");
			LCD1602_write(1,0x30+temp/10%10);
			LCD1602_writebyte(".");
		   	LCD1602_write(1,0x30+temp%10);
		}else
		{
			LCD1602_writebyte("-");	  //显示温度负数部分
			if(temp*-1>99)LCD1602_write(1,0x30+(temp*-1)/100%10);
			else LCD1602_writebyte(" ");
			LCD1602_write(1,0x30+(temp*-1)/10%10);	
			LCD1602_writebyte(".");
		   	LCD1602_write(1,0x30+(temp*-1)%10);
		}
		LCD1602_write(1,0xdf);
		LCD1602_writebyte("C  ");
		
	 	LCD1602_write(0,0xC0);	 //第二行显示温度上下限值
		LCD1602_writebyte("H:");
		if(state==1&&s1==1)		  //对应设置项设置时闪烁控制   //上限
		{
			LCD1602_writebyte("   ");
		}else					   //显示上限值
		{
			if(temp_h>=0)
			{
			   	if(temp_h>99)LCD1602_write(1,0x30+temp_h/100%10);
				else LCD1602_writebyte(" ");
				if(temp_h>9)LCD1602_write(1,0x30+temp_h/10%10);
				else LCD1602_writebyte(" ");
				LCD1602_write(1,0x30+temp_h%10);
			}else
			{
				LCD1602_writebyte("-");
				if(temp_h*-1>9)LCD1602_write(1,0x30+(temp_h*-1)/10%10);
				else LCD1602_writebyte(" ");
				LCD1602_write(1,0x30+(temp_h*-1)%10);	
			}
		}
		LCD1602_write(1,0xdf);
		LCD1602_writebyte("C L:");
		if(state==2&&s1==1)	  //对应设置项设置时闪烁控制   //下限
		{
			LCD1602_writebyte("   ");
		}else
		{
			if(temp_l>=0)		  //显示下限值
			{
			   	if(temp_l>99)LCD1602_write(1,0x30+temp_l/100%10);
				else LCD1602_writebyte(" ");
				if(temp_l>9)LCD1602_write(1,0x30+temp_l/10%10);
				else LCD1602_writebyte(" ");
				LCD1602_write(1,0x30+temp_l%10);
			}else
			{
				LCD1602_writebyte("-");
				if(temp_l*-1>9)LCD1602_write(1,0x30+(temp_l*-1)/10%10);
				else LCD1602_writebyte(" ");
				LCD1602_write(1,0x30+(temp_l*-1)%10);	
			}
		}
		LCD1602_write(1,0xdf);
		LCD1602_writebyte("C");
	
}

//系统指示灯与报警处理
void proc()
{
	if(temp>temp_h*10)	 //如果当前温度高于上限温度
	{
		led_1=0; 	 
	}else			
	{
		led_1=1; 	
	}
	if(temp<temp_l*10)	//如果当前温度低于下限温度 
	{
		led_2=0;
	}else			 
	{
		led_2=1;	
	}
	if(temp>temp_h*10||temp<temp_l*10)	
	{
		beep1=1;  //开始报警
	}else
	{
		beep1=0;  //停止报警
	}
}
// 系统控制按键控制检测程序
void key()
{

	if(!key_1)	//判断按键是否按下
	{
		delay(888);	 //延时去抖
		if(!key_1)	
		{
			state=(state+1)%3;		//切换设置项
			while(!key_1);		   //按键判断释放
		}
	}
	if(state!=0)		//如果系统非设置状态
	{
		if(!key_2)		 
		{
			delay(888);	   
			if(!key_2)	
			{
				while(!key_2) show();  
				switch(state) 
				{
					case 1:				  //如果是上限设置
					if(temp_h<99)temp_h++;
					SectorErase(0x2000);	 //保存上限值
					byte_write(0x2000,temp_h);
					break;
					case 2:		     //如果是下限设置
					if(temp_h>temp_l+1)temp_l++;	
					SectorErase(0x2200);	 //保存上限值
					byte_write(0x2200,temp_l);
					break;
				}
			}
		}
		if(!key_3)	
		{
			delay(888);	 
			if(!key_3)	
			{
				while(!key_3) show();  
				switch(state)	 //判断当前设置项
				{
					case 1:			     //如果是上限设置
					if(temp_h>temp_l+1)temp_h--;
					SectorErase(0x2000);	 //保存上限值
					byte_write(0x2000,temp_h);
					break;
					case 2:			   //如果是下限设置
					if(temp_l>-40)temp_l--;
					SectorErase(0x2200);	 //保存上限值
					byte_write(0x2200,temp_l);
					break;

				}
			}
		}
	}
}
float TemperatureCalculate(float Rx,float B,float Revise,float BasicRx){
/*
Rx:  热敏电阻当前阻值
B:   热敏电阻参数B值
Revise:  校正温度
BasicRx:  热敏电阻25度时电阻(标称电阻数值)
*/  
    Rx = Rx / BasicRx;
    Rx = log(Rx);
    Rx = (Rx) / B;
    Rx = Rx + 0.003356;
    Rx = 1 / Rx;
    Rx = Rx - 273.13;  
    Rx = Rx + Revise;
    return Rx;
  
}

#define B 3950.0//温度系数
#define TN 298.15//额定温度(绝对温度加常温:273.15+25)
#define RN 10// 额定阻值(绝对温度时的电阻值10k)
#define BaseVcc 5.04 //ADC基准电压
float GetTemperature(uint adc)
{
        float RV,RT,Tmp;
        RV=BaseVcc/256.0*(float)adc;//ADC为10位ADC,求出NTC电压:RV=ADCValu/1024*BaseVcctag
        RT=RV*10/(BaseVcc-RV);//求出当前温度阻值 (BaseVcctage-RV)/R16=RV/RT;
        Tmp=1/(1/TN+(log(RT/RN)/B))-273.15;//%RT = RN exp*B(1/T-1/TN)%
         return Tmp;
}

void main()
{
	float Rad;	 //生成运算暂存变量
	LCD1602_cls();
	TMOD=0x01;	 
	TH0=0x4c;
	TL0=0x00;	 
	ET0=1;		
	TR0=1;	  
	EA=1;		
	temp_h=byte_read(0x2000);  //读取EEPROM中存储的温度上下限值
	temp_l=byte_read(0x2200);
	if(temp_h>99||temp_l>99||temp_l>=temp_h) //判断读取的温度上下限值是否错
	{
		temp_h=30;
		temp_l=10;
	}
	while(1)
	{
		Read_ad();	   //读取AD数据
		adc_value=(float)A_D();     
		//Rad=adc_value/((5.0-adc_value)/10000.0);   //计算热敏电阻当前阻值
		//temp=(int)((temp * 0.5) + (TemperatureCalculate(Rad,3950.0,0,10000.0) * 0.5)*10);//求出当前系统的当前温度
		temp=GetTemperature(adc_value);
		show();		 //显示函数
		delay10us(100);
		key();		 //按键处理程序
		proc();		 //超限处理程序
	}
}
//定时器0中断服务程序
void UART_1() interrupt 1 
{
	TH0=0x4c;	//重新赋值
	TL0=0x00;
	ms++;	  //50ms定时变量计时
	if(ms%5==0)	  //区分250ms定时
	{
		s1=!s1;		
		if(beep1==1) beep=!beep;  //判断报警标志位是否报警   
		else	beep=1;
	}
	if(ms>19)	//1s定时
	{
		ms=0;		
	}
} 

2.eeprom52

代码如下:

#ifndef _EEPROM52_H_
#define _EEPROM52_H_
#include <intrins.h>

/********STC89C52扇区分布*******
第一扇区:2000H--21FF
第二扇区:2200H--23FF
第三扇区:2400H--25FF
第四扇区:2600H--27FF
第五扇区:2800H--29FF
第六扇区:2A00H--2BFF
第七扇区:2C00H--2DFF
第八扇区:2E00H--2FFF
*****************/

#define RdCommand 0x01 //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03 
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2;  //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;

/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
	 EA = 0;       /* 关中断   */
	 ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
	 ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
	 ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
	 ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
	 ISP_TRIG = 0x00;
	 EA   =   1;   /* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
	 ISP_IAP_enable();   /* 打开 ISP,IAP 功能 */
	 ISP_TRIG = 0x46;  /* 触发ISP_IAP命令字节1 */
	 ISP_TRIG = 0xb9;  /* 触发ISP_IAP命令字节2 */
	 _nop_();
}
/* ==================== 字节读 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
	EA = 0;
	 ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址赋值 */
	 ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
	 ISP_CMD   = ISP_CMD & 0xf8;   /* 清除低3位  */
	 ISP_CMD   = ISP_CMD | RdCommand; /* 写入读命令 */
	 ISPgoon();       /* 触发执行  */
	 ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
	 EA  = 1;
	 return (ISP_DATA);    /* 返回读到的数据 */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
	 unsigned int iSectorAddr;
	 iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
	 ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
	 ISP_ADDRL = 0x00;
	 ISP_CMD = ISP_CMD & 0xf8;   /* 清空低3位  */
	 ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3  */
	 ISPgoon();       /* 触发执行  */
	 ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
}
/* ==================== 字节写 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
	 EA  = 0;
//	 SectorErase(byte_addr);
	 ISP_ADDRH = (unsigned char)(byte_addr >> 8);  /* 取地址  */
	 ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
	 ISP_CMD  = ISP_CMD & 0xf8;    /* 清低3位 */
	 ISP_CMD  = ISP_CMD | PrgCommand;  /* 写命令2 */
	 ISP_DATA = original_data;   /* 写入数据准备 */
	 ISPgoon();       /* 触发执行  */
	 ISP_IAP_disable();     /* 关闭IAP功能 */
	 EA =1;
}
		
#endif

3.ADC0832

代码如下:

sbit ADC0832_CS=P1^0;
sbit ADC0832_CLK=P1^2;
sbit ADC0832_DIO=P1^1;
 
unsigned int A_D()
{
   unsigned char i,dat;
   ADC0832_CS=1;   //一个转换周期开始
   ADC0832_CLK=0;  //为第一个脉冲作准备
   ADC0832_CS=0;  //CS置0,片选有效

   ADC0832_DIO=1;    //DIO置1,规定的起始信号  
   ADC0832_CLK=1;   //第一个脉冲
   ADC0832_CLK=0;   //第一个脉冲的下降沿,此前DIO必须是高电平
   ADC0832_DIO=1;   //DIO置1, 通道选择信号  
   ADC0832_CLK=1;   //第二个脉冲,第2、3个脉冲下沉之前,DI必须跟别输入两位数据用于选择通道,这里选通道CH0 
   ADC0832_CLK=0;   //第二个脉冲下降沿 
   ADC0832_DIO=0;   //DI置0,选择通道0
   ADC0832_CLK=1;    //第三个脉冲
   ADC0832_CLK=0;    //第三个脉冲下降沿 
   ADC0832_DIO=1;    //第三个脉冲下沉之后,输入端DIO失去作用,应置1
   ADC0832_CLK=1;    //第四个脉冲
   for(i=0;i<8;i++)  //高位在前
    {
      ADC0832_CLK=1;         //第四个脉冲
      ADC0832_CLK=0; 
      dat<<=1;       //将下面储存的低位数据向右移
		dat|=(unsigned char)ADC0832_DIO; 	 //将输出数据DIO通过或运算储存在dat最低位 
    }	  		        
    ADC0832_CS=1;          //片选无效 
	return dat;	 //将读书的数据返回     
  }

    暂无数据