基于51单片机的温度传感器小项目

温度报警器

文章目录

  • 温度报警器
  • 主界面用于实时读取温度,并具报警功能
    • **实时读取会遇到以下问题:**
    • **解决办法:**
    • ReadT函数:实时读取温度
  • **基于五一的温度传感报警器**本项目其他四个小功能
  • 1.设置Thigh和TLow温度报警阀值
    • **对于这个功能需要实现以下的处理:**
    • **解决方法**:
    • SetTOver()函数代码
  • 2.读取第一次超出阀值时候的温度
    • 需要面对的问题:
    • 解决问题:
    • Read_OverT函数
  • 3.使用电机吹风进行物理降温(如果有其他模块可以用其他模块处理高温)
    • 实现这个功能需要面对的问题:
    • 解决问题:
    • Motor_Set()函数
  • 4.计算在一段时间内的温度平均值
    • 需要面对的问题:
    • AVG函数代码
  • 主函数main的代码

主界面用于实时读取温度,并具报警功能

实时读取温度需要用到DS18B20来实现,同时需要用LCD1602对读取的温度进行展示给用户

实时读取会遇到以下问题:

1.LCD的显示只能显示整数类型,LCD的模板中没有float类型的读取

2.需要保存T的值用来对后续的功能的条件

解决办法:

1.通过将整数部分和小数部分分开显示达到显示float类型的效果

2.通过Tshow被赋值T的值,对Tshow进行显示处理来达到保护T数值的效果

ReadT函数:实时读取温度

void ReadT()
{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(1,1,'-');	//显示负号
			TShow=-T;		//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(1,3,'+');	//显示正号
			TShow=T;
		}
		LCD_ShowNum(1,4,TShow,3);		//显示温度整数部分
		LCD_ShowChar(1,7,'.');		//显示小数点
		LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分
}

基于五一的温度传感报警器本项目其他四个小功能

这四个小功能分别用 K1、K2、K3、K4来实现从主界面的跳转。

1.设置Thigh和TLow温度报警阀值

设置Thigh和TLow阀值使用键盘矩阵的方式来实现对Thigh和TLow的赋值

需要键盘矩阵模块和普通的按钮来实现

对于这个功能需要实现以下的处理:

1.用键盘矩阵进行0~9的赋值,还需要解决清除、确认、改变设置THigh or TLow的问题

2.通过再按一次K1进行退出

3.需要对Thigh和TLow的错误赋值进行错误处理

4.改变设置对象应该怎样实现

5.如何正常的显示值的改变实时更新改变的Thigh TLow的值(本小功能的最大问题)

解决方法:

1.正常用S0-S9赋值只赋值三位(DS18B20最大有效位数也才三位),处理S11用来清除、S12用来确定赋值、S16用来改变赋值对象

2.通过一个if判断K1是否按下执行return ;语句

3.通过判断Thigh是否始终大于Tlow的正确性对错误赋值进行处理

4.改变对象通过引入一个变量HLflog来实现对赋值对象的改变

5.具体通过我自己不断的调试解决了

SetTOver()函数代码

void SetTOver()
{
unsigned char KeyNum_Key,KeyNum_MatrixKey;
int InNum=0,Count=0;
int HLFlog=0;
LCD_Init();
LCD_ShowString(1,1,"SETTOVER:");
LCD_ShowString(2,1,"TH:");
LCD_ShowString(2,9,"TL:");
LCD_ShowSignedNum(2,4,THigh,3);
LCD_ShowSignedNum(2,12,TLow,3);	
	Compare=10;
while(HLFlog!=-1)
{
	KeyNum_Key=Key();
	KeyNum_MatrixKey=MatrixKey();
	if(KeyNum_MatrixKey||KeyNum_Key)//输入数据
	{
		if(KeyNum_MatrixKey<=10)	//如果S1~S10按键按下,输入密码
		{
			if(Count<3)	//如果输入次数小于3
			{
				InNum*=10;		
				InNum+=KeyNum_MatrixKey%10;	
				Count++;	//计次加一
			}
		}	
		if(KeyNum_MatrixKey==11)//k4初始化为默认值
		{
				InNum=0;
				Count=0;
		}
		if(KeyNum_MatrixKey==16)
		{
			switch(HLFlog)
			{
				case 0: HLFlog=1;LCD_ShowString(2,1,"TH:");LCD_ShowSignedNum(2,4,THigh,3); break;//没点确认我就不保存
				case 1: HLFlog=0;LCD_ShowString(2,9,"TL:");LCD_ShowSignedNum(2,12,TLow,3); break;//没点确认我就不保存
			}
			Count=0;
			InNum=0;
		}
		if(KeyNum_MatrixKey==12)	//如果S12按键按下,确认
		{
			if(HLFlog==0)//设置THigh
			{
				if(InNum>TLow)
				{
					HLFlog=1;
					THigh=InNum;
				}
				else//错误处理
				{
					THigh=TLow+1;
				}
				LCD_ShowSignedNum(2,4,THigh,3);	//显示阈值数据
				InNum=0;
				Count=0;
			}
			else if(HLFlog==1)//设置TLow
			{
				if(InNum<THigh)
				{
					TLow=InNum;
				}
				else//错误处理
				{
					TLow=THigh-1;
				}
				LCD_ShowSignedNum(2,12,TLow,3);	//显示阈值数据
			}
		}
		if(KeyNum_Key==1)//K2退出设置
		{
			HLFlog=-1;
		}
	if(HLFlog==0)//更新InNum的输入
	LCD_ShowSignedNum(2,4,InNum,3);	//0
	else if(HLFlog==1)
	LCD_ShowSignedNum(2,12,InNum,3); //1
	}
}
	//再显示一次,防止出现错误
	LCD_Init();
	LCD_ShowString(1,1,"T:");
	LCD_ShowString(2,1,"TH:");
	LCD_ShowString(2,9,"TL:");
	LCD_ShowSignedNum(2,4,THigh,3);
	LCD_ShowSignedNum(2,12,TLow,3);
	ReadT();
	AT24C02_WriteByte(0,THigh);		//写入到At24C02中保存
	Delay(5);
	AT24C02_WriteByte(1,TLow);
	Delay(5);
}

2.读取第一次超出阀值时候的温度

本来一开始是写好了读取第一次超出阀值时候的温度和时间但是温度的模块所需要用到的单总线和时钟模块的引脚发生了冲突导致写好的代码无奈删除QWQ

读取第一次超过阀值时候的温度可以用来事后判断事故的发生原因

具体要用到储存模块AT24C02和原来那些按钮模块

需要面对的问题:

1.显示问题

2.需要一个清除记录的功能一遍记录下一次

3.退出功能

4.断电储存(AT24C02中的模板没有储存float类型,此问题导致我搞了几天才发现)

解决问题:

1.通过上面的经验进行调试处理完毕

2.使用矩阵按键上的S16进行清除处理

3.退出功能同上

4.demo中是储存一个字节大小的数据只能满足char类型显然不能满足float存储需要四个字节大小的要求因此可以通过循环调用四次来实现读写float类型的功能,所以自己写了一个读取float类型的模板

代码如下:

void WriteFloatToMemory(float floatValue, unsigned char WordAddress)
{
	int i;	
	// 将 float 类型的数据转换为字节数据
	unsigned char *dataPointer = (unsigned char *)&floatValue;

	// 写入四个字节数据到存储器中
	for (i = 0; i < 4; ++i)
	{
			AT24C02_WriteByte(WordAddress + i, dataPointer[i]);
			Delay(5); // 延迟确保数据写入完成,实际延迟时间需根据存储器和系统情况调整
	}
}

float ReadFloatFromMemory(unsigned char WordAddress)
{
    unsigned char dataBytes[4];
    float floatValue;
    int i;
    for (i = 0; i < 4; ++i)
    {
        dataBytes[i] = AT24C02_ReadByte(WordAddress + i);
        Delay(5); // 延迟确保数据读取完成,实际延迟时间需根据存储器和系统情况调整
    }

    // 将四个字节数据组合成一个 float 类型数据
    floatValue = *((float *)dataBytes);

    return floatValue;
}

Read_OverT函数

void Read_OverT()
{
	char KeyNum_MatrixKey;
	float TShow_Over;
	LCD_Init();
	T_Over=ReadFloatFromMemory(2);
	while(1)
	{
		KeyNum=Key();
		KeyNum_MatrixKey=MatrixKey();
		if(OverFlog==2)
			LCD_ShowString(1,1,"T_HighOver:");
		if(OverFlog==3)
			LCD_ShowString(1,1,"T_LOver:");		
		if(T_Over<0)				//如果温度小于0
		{
			LCD_ShowChar(2,1,'-');	//显示负号
			TShow_Over=-T_Over;		//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(2,1,'+');	//显示正号
			TShow_Over=T_Over;
		}
		LCD_ShowNum(2,2,TShow_Over,3);		//显示温度整数部分
		LCD_ShowChar(2,5,'.');		//显示小数点
		LCD_ShowNum(2,6,(unsigned long)(TShow_Over*100)%100,2);//显示温度小数部分		
		if(KeyNum_MatrixKey==16) 
		{
			LCD_Init();
			LCD_ShowString(1,1,"Clear");
			OverFlog=1;
			KeyNum=Key();
			while(!KeyNum) KeyNum=Key();
			if(KeyNum==2)
				return;
		}
		if(KeyNum==2)
		{
			return;
		}
			
	}
}



3.使用电机吹风进行物理降温(如果有其他模块可以用其他模块处理高温)

电机对温度的物理降温处理需要电机模块使用PWM来实现对电机速度的自动控制

实现这个功能需要面对的问题:

1.本项目用的K系列案件是由定时器0每隔一段时间进行检测消抖,和点击使用PWM的时间初值设计上有一点点的不同

2.设计一个合理的方案实现电机的速度变化

解决问题:

1.电机的定时器周期和按键检测周期的时间刚好相差十倍可以通过对Count除于10实现周期的同步

void Timer0_Routine() interrupt 1
{
		static unsigned int T0Count;
		TL0 = 0x18;		//设置定时初值
		TH0 = 0xFC;		//设置定时初值
		if(TimeFlog)
		{
			Counter++;
			Counter%=10;	//计数值变化范围限制在0~10
			if(Counter<Compare)	//计数值小于比较值
			{
				Motor=1;		//输出1
			}
			else				//计数值大于比较值
			{
				Motor=0;		//输出0
			}
		}
		T0Count++;
		if(T0Count>=20)
		{
			T0Count=0;
			Key_Loop();	//每20ms调用一次按键驱动函数
		}
}

2.用温度溢出值的大小实现电机的转速

Motor_Set()函数

void Motor_Set()
{
	LCD_Init();
	while(1)
	{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		Compare=0;
		KeyNum=Key();
		if(T>=THigh+20){Compare=10;}//设置比较值,改变PWM占空比
		else if(T>=THigh+10){Compare=9;}
		else if(T>=THigh){Compare=8;}
		LCD_ShowString(2,1,"Colding...");
		if(KeyNum==3)
			break;
	}
}

4.计算在一段时间内的温度平均值

通过Delay实现对温度平均值的计算

需要面对的问题:

1.按错了如何退出

2.如何设置每次读取时间的周期间隔

3.如何记录并且显示每一次读取的值

4.如何显示平均值

解决方案:

1.进入功能四后需要再按一次K4程序才会启动,也可以解决设置是否需要设置问题K2、K3用来用户退出

2.通过K1案件设置、K2、K3用来++或者–

3.设计一个数组来读取值

4.同上面几个功能进行设计float的显示

AVG函数代码


void Avg()
{
		static unsigned char Sep=1;
		int j;
		float aver,averShow;
		float Sum=0;
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		LCD_Init();
		LCD_ShowString(1,1,"k1-set k4_run");
		LCD_ShowString(2,1,"k2 or k3 exit");
		KeyNum=Key();
		while(!KeyNum) KeyNum=Key();//判断按键
		if(KeyNum==1)
		{
			LCD_Init();
			LCD_ShowString(1,1,"Sep_set:");
			LCD_ShowNum(2,1,Sep,3);
			while(1)
			{
				KeyNum=Key();
				if(KeyNum==2)
				{
					Sep--;
					LCD_ShowNum(2,1,Sep,3);
				}
				if(KeyNum==3)
				{
					Sep++;
					LCD_ShowNum(2,1,Sep,3);
				}
				if(KeyNum==1)
					break;
			}
		}
		else if(KeyNum==4)
		{
			LCD_Init();
			LCD_ShowString(2,1,"Aver:");
			for(j=1;j<=5;j++)
			{
				ReadT();
				TData[j]=T;
				LCD_ShowString(1,1,"T :");
				LCD_ShowNum(1,2,j,1);
				Sum+=TData[j];
				Delay(1000*Sep);//十秒
			}
			aver=Sum/5.0;
			if(aver<0)				//如果温度小于0
			{
				LCD_ShowChar(2,6,'-');	//显示负号
				averShow=-aver;		//将温度变为正数
			}
			else				//如果温度大于等于0
			{
				LCD_ShowChar(2,6,'+');	//显示正号
				averShow=aver;
			}
			LCD_ShowNum(2,7,averShow,3);		//显示温度整数部分
			LCD_ShowChar(2,10,'.');		//显示小数点
			LCD_ShowNum(2,11,(unsigned long)(averShow*100)%100,2);//显示温度小数部分
			KeyNum=Key();												
			while(!KeyNum)KeyNum=Key();	
				if(KeyNum==4)
					return;
		}
		else
			return;
		
}

主函数main的代码

#include 
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "Key.h"
#include "Timer0.h"
#include "Buzzer.h"
#include "MatrixKey.h"
float TData[5];
sbit Motor=P1^0;
unsigned char Counter,Compare=0;	
float T,TShow;
int TLow,THigh;
unsigned char KeyNum;
int OverFlog=1;
float T_Over;
int TimeFlog=0;
........................

void main()
{
	Motor=0;
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	THigh=AT24C02_ReadByte(0);	//读取温度阈值数据
	TLow=AT24C02_ReadByte(1);
	if(THigh>125 || TLow<-55 || THigh<=TLow)
	{
		THigh=25;			//如果阈值非法,则设为默认值
		TLow=15;
	}
	LCD_Init();
	LCD_ShowString(1,1,"T:");
	LCD_ShowString(2,1,"TH:");
	LCD_ShowString(2,9,"TL:");
	LCD_ShowSignedNum(2,4,THigh,3);
	LCD_ShowSignedNum(2,12,TLow,3);
	Timer0_Init();
	while(1)
	{
		Compare=0;
		KeyNum=Key();
		/*温度读取及显示*/
		ReadT();
		if(T>THigh)			//越界判断
		{
			LCD_ShowString(1,13,"OV:H");
			if(OverFlog==1)
			{
				int i;
				WriteFloatToMemory(T,2);
				Delay(5);
				OverFlog=2;
				for(i=0;i<3;i++)
				{
					Buzzer_Time(500);
					Delay(300);
				}
			}
				
		}
		else if(T<TLow)
		{
			LCD_ShowString(1,13,"OV:L");
			if(OverFlog==1)
			{
				int i;
				WriteFloatToMemory(2,T);
				Delay(5);
				OverFlog=3;
				for(i=0;i<3;i++)
				{
					Buzzer_Time(1000);
					Delay(300);
				}
			}
				
		}
		else
		{
			LCD_ShowString(1,13,"    ");
		}
		//功能
		if(KeyNum)
		{
			if(KeyNum==1)	//设置Thigh,和Tlow的值
			{
				SetTOver();
			}
			if(KeyNum==2)//读取第一次溢出的值
			{
				Read_OverT();//查看第一次溢出值
				LCD_Init();
				LCD_ShowString(1,1,"T:");
				LCD_ShowString(2,1,"TH:");
				LCD_ShowString(2,9,"TL:");
				LCD_ShowSignedNum(2,4,THigh,3);
				LCD_ShowSignedNum(2,12,TLow,3);
				ReadT();
			}
			if(KeyNum==3)//使用电机来降温
			{
				TimeFlog=1;
				Motor_Set();//电机启动
				TimeFlog=0;
				LCD_Init();
				LCD_ShowString(1,1,"T:");
				LCD_ShowString(2,1,"TH:");
				LCD_ShowString(2,9,"TL:");
				LCD_ShowSignedNum(2,4,THigh,3);
				LCD_ShowSignedNum(2,12,TLow,3);
				ReadT();
				Motor=0;
			}
			if(KeyNum==4)
			{
				Avg();
				LCD_Init();
				LCD_ShowString(1,1,"T:");
				LCD_ShowString(2,1,"TH:");
				LCD_ShowString(2,9,"TL:");
				LCD_ShowSignedNum(2,4,THigh,3);
				LCD_ShowSignedNum(2,12,TLow,3);
			}
		}
	}
}

void Timer0_Routine() interrupt 1
{
		static unsigned int T0Count;
		TL0 = 0x18;		//设置定时初值
		TH0 = 0xFC;		//设置定时初值
		if(TimeFlog)
		{
			Counter++;
			Counter%=10;	//计数值变化范围限制在0~99
			if(Counter<Compare)	//计数值小于比较值
			{
				Motor=1;		//输出1
			}
			else				//计数值大于比较值
			{
				Motor=0;		//输出0
			}
		}
		T0Count++;
		if(T0Count>=20)
		{
			T0Count=0;
			Key_Loop();	//每20ms调用一次按键驱动函数
		}
}


你可能感兴趣的:(算法,单片机,嵌入式硬件)