DHT11传感器测量温湿度,按键调节上下限阈值,蜂鸣器报警。

DHT11传感器测量温湿度,按键调节上下限阈值,蜂鸣器报警。

  • 前言
  • 课设要求
  • 代码呈现
  • 感悟

前言

这个课设可以说写了四天,因为我接触单片机的时间也不是很长,基础也不是太扎实。写的代码bug真的是太多,绝大多数的时间都画在了找bug上了。但是幸运的是我有一个能够为我传道,授业,解惑的好老师,没有老师的帮忙,这个代码估计到现在也写不好。在实习的过程中也看到了很多厉害的同学,写代码思路很清晰,对于模块的理解也很透彻,写的也很快。我也是比较嫉妒的,希望有一天我的单片机也能学的很透彻。以后我一定要加强对于单片机方面的学习,我还想靠着单片机在一些比赛上拿一些奖项呢。

课设要求

DHT11传感器测量温湿度,按键调节上下限阈值,蜂鸣器报警。_第1张图片

代码呈现

main函数

#include "1602.h"
#include "DHT11.h"
#include "juzhen.h"
void Selay(unsigned char k);
unsigned char TTop=30;
unsigned char TLow=10;
unsigned char RHTop=80;
unsigned char RHLow=30;
extern T_Data_H;
volatile unsigned char KeyValue=0;
unsigned char Temp=0;
extern unsigned char DHT11_Data[17];
unsigned char *DHT11_Dis;
unsigned char SegData[4]={0};
unsigned char SegSata[4]={0};
void Init();
unsigned char k=0;
sbit led1=P2^4;
sbit led2=P2^5;
sbit led3=P2^6;
sbit led4=P2^7;
sbit buzzer=P1^0;

void main()
{
	unsigned char T;
	unsigned char RH;
	Init();
	LCD_Init();		//液晶初始化
	LCD_Cls();			//液晶清屏
	LCD_DisplayString(0,0,"S:",2);
	LCD_DisplayString(9,0,"X:",2);
	LCD_DisplayChar(2,0,TTop/10+0X30);
	LCD_DisplayChar(3,0,TTop%10+0X30);
	LCD_DisplayChar(11,0,TLow/10+0X30);
	LCD_DisplayChar(12,0,TLow%10+0X30);
	LCD_DisplayChar(5,0,RHTop/10+0X30);
	LCD_DisplayChar(6,0,RHTop%10+0X30);
	LCD_DisplayChar(14,0,RHLow/10+0X30);
	LCD_DisplayChar(15,0,RHLow%10+0X30);
	LCD_DisplayString(4,0,":",1);
	LCD_DisplayString(13,0,":",1);
	DHT11_Dis = Read_DHT11();					//获取温湿度
	LCD_DisplayString(0,1,DHT11_Dis,16);	//显示温湿度
	while(1)
	{	 
		KeyValue=keyscan();
		if(KeyValue)
		{	
			
			Temp = KeyValue;
			KeyValue=0;
			switch(Temp)
			{				
				case 1:TTop++;if(TTop>99)TTop=10;
					   LCD_DisplayChar(2,0,TTop/10+0X30);
					   LCD_DisplayChar(3,0,TTop%10+0X30);
				break;
				case 2:TTop--;if(TTop<10)TTop=99;
					   LCD_DisplayChar(2,0,TTop/10+0X30);
					   LCD_DisplayChar(3,0,TTop%10+0X30);
				break;
				case 3:TLow++;if(TLow>99)TLow=10;
					   LCD_DisplayChar(11,0,TLow/10+0X30);
					   LCD_DisplayChar(12,0,TLow%10+0X30);
				break;
				case 4:TLow--;if(TLow<10)TLow=99;
					   LCD_DisplayChar(11,0,TLow/10+0X30);
					   LCD_DisplayChar(12,0,TLow%10+0X30);
				break;
				case 5:RHTop++;if(RHTop>99)RHTop=30;
					   LCD_DisplayChar(5,0,RHTop/10+0X30);
					   LCD_DisplayChar(6,0,RHTop%10+0X30);
				break;
				case 6:RHTop--;if(RHTop<50)RHTop=51;
					   LCD_DisplayChar(5,0,RHTop/10+0X30);
					   LCD_DisplayChar(6,0,RHTop%10+0X30);
				break;
				case 7:RHLow++;if(RHLow>50)RHLow=49;
					   LCD_DisplayChar(14,0,RHLow/10+0X30);
					   LCD_DisplayChar(15,0,RHLow%10+0X30);
				break;
				case 8:RHLow--;if(RHLow<20)RHLow=21;
					   LCD_DisplayChar(14,0,RHLow/10+0X30);
					   LCD_DisplayChar(15,0,RHLow%10+0X30);
				break;
			}
		}		
		if(k>=40)
		{
			k = 0;
			DHT11_Dis = Read_DHT11();					//获取温湿度
			LCD_DisplayString(0,1,DHT11_Dis,16);			//显示温湿度				
		}
		T=(DHT11_Dis[11]-0x30)*10+DHT11_Dis[12]-0x30;
		RH=(DHT11_Dis[3]-0x30)*10+DHT11_Dis[4]-0x30;
		 if(TTop<T || TLow>T || RHTop<RH || RHLow>RH) 
		 {
			buzzer=0;
		 }
		 if(TTop<T)  led1=0; else {led1=1;buzzer=1;}
		 
		 if(TLow>T)  led2=0;  else {led2=1;buzzer=1;}
		 
	     if(RHTop<RH) led3=0;   else {led3=1;buzzer=1;}
	
		 if(RHLow>RH)  led4=0;    else {led4=1;buzzer=1;}
		
	}

}
//定时器初始化
void Init()
{
	TMOD=0x01;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	ET0=1;
	TR0=1;
	EA=1;
}
void Timer0() interrupt 1
{
	//led1=0;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	k++;//led1=0;
}

DHT11.C

	//----以下变量均为全局变量--------
	//----温度高8位== T_Data_H------
	//----温度低8位== T_Data_L------
	//----湿度高8位== RH_Data_H-----
	//----湿度低8位== RH_Data_L-----
	//----校验 8位 == CRC_Data-----

#include "DHT11.h"

//----------------IO口定义区--------------------//	
sbit  DHT11_IO  = P1^1 ;
//----------------定义区--------------------//	
unsigned char  CRC_Error = 0,flag = 0;
       
void Delay(unsigned int j)
{      
	unsigned char i;
	for(;j>0;j--)
	{ 	
		for(i=0;i<127;i++);
	}
}
void Delay_10us(void)
{
	unsigned char i;
	i--;
	i--;
	i--;
	i--;
	i--;
	i--;
}

unsigned char Receive_Byte(void)
{
	unsigned char i = 0;
	unsigned char ReceiveData = 0;
	bit temp;
	for(i=0;i<8;i++)	   
	{
		while((!DHT11_IO)&&flag++);
		Delay_10us();
		Delay_10us();
		Delay_10us();
		temp=0;
		if(DHT11_IO)
			temp=1;
		while((DHT11_IO)&&flag++);//超时则跳出for循环		  

		ReceiveData <<= 1;
		ReceiveData |= temp;      
	}
	return ReceiveData;
}

unsigned char * Read_DHT11(void)
{  
	unsigned char  T_Data_H,T_Data_L,RH_Data_H,RH_Data_L,CRC_Data;
	static unsigned char DHT11_Data[17] = {0};
	DHT11_IO=0;			 
	Delay(20);	    	//主机拉低 18ms,由于上电的不稳定性,延长时间适当拉长。
	DHT11_IO=1;	 		//总线由上拉电阻拉高 主机延时40us
	Delay_10us();
	Delay_10us();
	Delay_10us();
	Delay_10us();
	DHT11_IO=1;			//主机设为输入 判断从机响应信号 	  
	if(!DHT11_IO)		//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
	{	
		flag=2;		 
		while((!DHT11_IO)&&flag++);	//判断从机是否发出 80us 的低电平响应信号是否结束
		flag=2;
		while((DHT11_IO)&&flag++);	//判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
		
		RH_Data_H = Receive_Byte();	//数据接收		
		RH_Data_L = Receive_Byte();	
		T_Data_H = Receive_Byte();		
		T_Data_L = Receive_Byte();	
		CRC_Data = Receive_Byte();
		
		DHT11_IO = 1;		 
		if( CRC_Data != RH_Data_H + RH_Data_L + T_Data_H + T_Data_L)
		{
			RH_Data_H = 0;
			RH_Data_L = 0;
			T_Data_H = 0;
			T_Data_L = 0;
			
		}
		else
		{
			
			DHT11_Data[0] = 'R';
			DHT11_Data[1] = 'H';
			DHT11_Data[2] = ':';			
			DHT11_Data[3] = RH_Data_H / 10 + 0x30;
			DHT11_Data[4] = RH_Data_H % 10 + 0x30;
			DHT11_Data[5] = '.';
			DHT11_Data[6] = RH_Data_L / 10 + 0x30;			
			DHT11_Data[7] = '%';
			
			DHT11_Data[8] = ' ';
			
			DHT11_Data[9] = 'T';
			DHT11_Data[10] = ':';
			DHT11_Data[11] = T_Data_H / 10 + 0x30;
			DHT11_Data[12] = T_Data_H % 10 + 0x30;
			DHT11_Data[13] = '.';
			DHT11_Data[14] = T_Data_L / 10 + 0x30;
			DHT11_Data[15] = 0xdf;					//1602液晶度的字符码			
		}
		return DHT11_Data;
	}
	return 0;	
}

DHT11.h

#ifndef __DHT11_H_
#define __DHT11_H_

#include 
#include 

void Delay(unsigned int j);
void Delay_10us(void);
unsigned char Receive_Byte(void);
unsigned char * Read_DHT11(void);

#endif

LCD1602.C

/******** (C) Copyright 2012 All rights reserved ********
* 文件名          : 160.2.c
* 版本            : V1.0
* 完成日期        : 2011-05-17
* 功能描述        : 1602液晶驱动程序
********************************************************************/
#include "1602.H"
sbit	RS = P3^5;
sbit	RW = P3^6;
sbit	E  = P3^7;
#define		RS_High()	RS = 1;_nop_();_nop_()		//数据
#define		RS_Low()	RS = 0;_nop_();_nop_()		//指令

#define		RW_High()	RW = 1;_nop_();_nop_()		//读操作
#define		RW_Low()	RW = 0;_nop_();_nop_()		//写操作

#define		E_High()	E = 1;_nop_();_nop_()		//使能
#define		E_Low()		E = 0;_nop_();_nop_()		//禁止

#define		DataPort	P0
#define		DataInput()	DataPort = 0xff

#define		FirstLineAdd	0x80
#define		SecondLineAdd	0xC0

#define		DisplayData 1
#define		Command		0

#define		DisplayMode		0x38
#define		DisplayOFF		0x08
#define		LcdCls			0x01
#define		DisplayCursor	0x06
#define		DisplayOn		0x0C	

/**************************************************
*函数名:Delay_Ms
*功能  :毫秒延时函数
*参数  :DelayTime - 延时时间 DelayTime 毫秒 晶振:12Mhz
**************************************************/
void Delay_Ms(unsigned char DelayTime)
{
	unsigned int j;   
    while(DelayTime)   
    {   
        for(j = 0;j < 250;j ++)   
            _nop_();
			   
    	DelayTime --;               
    }   
}

/**************************************************
* 函数名称:LCD_CheckBusy()
* 功能	  :判断液晶工作状态
* 返回值  :
**************************************************/
void LCD_CheckBusy()
{
	DataInput();	//将P0口设置为数据输入
	RS_Low();		//命令
	RW_High();		//读数据
	E_Low();
	_nop_();
	E_High();		//使能
	while((bit)(DataPort & 0x80))
	{
		LCD_CheckBusy();
	}
}
/**************************************************
* 函数名称:LCD_Cls()
* 功能	  :清屏
**************************************************/
void LCD_Cls()
{
	LCD_WriteByte(Command,LcdCls);
	Delay_Ms(10);	
}
/**************************************************
* 函数名称:LCD_WriteByte(bit DataOrCommand,unsigned char Data)
* 功能	  :向液晶写入数据或者命令 
* 参数	  :DataOrCommand:数据或者命令判断    Data
**************************************************/
void LCD_WriteByte(bit DataOrCommand,unsigned char Data)
{
	if(DataOrCommand == Command)		//判断指令或者数据 
	{	RS_Low();}
	else
	{	RS_High();}
	RW_Low();		//写入 
	E_High();
	DataPort = Data;
	Delay_Ms(5);
	E_Low();
}
/**************************************************
* 函数名称:LCD_DisplayChar
* 功能	  :在指定位置显示字符 
* 参数	  :Local_X X坐标, Local_Y Y坐标, Data 待显示字符 
**************************************************/
void LCD_DisplayChar(unsigned char Local_X,unsigned char Local_Y,unsigned char Data)
{
	LCD_CheckBusy();
	if (Local_Y == FirstLine)     
	 	LCD_WriteByte(Command,FirstLineAdd  + Local_X);     //第一行X位置 
 	else 
 		LCD_WriteByte(Command,SecondLineAdd + Local_X);     //第二行X位置  
 	LCD_WriteByte(DisplayData,Data);   
}
/**************************************************
* 函数名称:LCD_DisplayString
* 功能	  :在指定位置显示字符 
* 参数	  :Local_X X坐标(0-15), Local_Y Y坐标(0-1), Str 待显示字符串 
**************************************************/
void LCD_DisplayString(unsigned char Local_X,unsigned char Local_Y,unsigned char *Str,unsigned char Num)
{
	LCD_CheckBusy();
	if (Local_Y == FirstLine)     
	 	LCD_WriteByte(Command,FirstLineAdd  + Local_X);     //第一行X位置 
 	else 
 		LCD_WriteByte(Command,SecondLineAdd + Local_X);     //第二行X位置  
 	while(Num--) 
 	{     
		 LCD_WriteByte(DisplayData,*Str);     
		 Str ++;     
 	}
}
/**************************************************
* 函数名称:LCD_Init
* 功能	  :液晶屏初始化 
**************************************************/
void LCD_Init()
{
	
	LCD_WriteByte(Command,DisplayMode);		//显示模式: 16*2行显示,5*7点阵,8位数据接口
	Delay_Ms(10);
	LCD_WriteByte(Command,DisplayMode);		//显示模式: 16*2行显示,5*7点阵,8位数据接口
	Delay_Ms(10);
	LCD_WriteByte(Command,DisplayMode);		//显示模式: 16*2行显示,5*7点阵,8位数据接口
	Delay_Ms(10);
	LCD_WriteByte(Command,DisplayMode);		//显示模式: 16*2行显示,5*7点阵,8位数据接口
	LCD_WriteByte(Command,DisplayOFF);		//显示关闭 
	LCD_WriteByte(Command,LcdCls);			//显示清屏 
	LCD_WriteByte(Command,DisplayCursor);	//显示光标 地址加1,光标加1 
	Delay_Ms(10);
	LCD_WriteByte(Command,DisplayOn);		//显示开 
}
	

LCD1602.h

#ifndef __1602_H_
#define __1602_H_

#include 
#include 

#define		FirstLine		0
#define		SecondLine		1

void Delay_Ms(unsigned char DelayTime);
void LCD_CheckBusy(); 
void LCD_Cls();
void LCD_WriteByte(bit DataOrCommand,unsigned char Data);
void LCD_DisplayChar(unsigned char Local_X,unsigned char Local_Y,unsigned char Data);
void LCD_DisplayString(unsigned char Local_X,unsigned char Local_Y,unsigned char *Str,unsigned char Num);
void LCD_Init();

#endif

JuZhen.C

#include 
#include 
#include "juzhen.h"
#define u8 unsigned char


//矩阵键盘的扫描

unsigned char keyscan()
{
	unsigned char value = 0;//定义按键值
	u8 row,column;
	P2=0xf0;
	if(P2!=0xf0)
	{
		Selay(20);
		if(P2!=0xf0)
		{
			row=P2;
			P2=0x0f;
			column=P2;
			switch(row|column)
			{
				case 0x77:Selay(50);value=1;if(value==1);Selay(50);break;//温度上限阈值+1
				case 0xb7:Selay(50);value=2;if(value==2);Selay(50);break;//温度上限阈值-1
				case 0xd7:Selay(50);value=3;if(value==3);Selay(50);break;//温度下限阈值+1
				case 0xe7:Selay(50);value=4;if(value==4);Selay(50);break;//温度下限阈值-1
				case 0x7b:Selay(50);value=5;if(value==5);Selay(50);break;
				case 0xbb:Selay(50);value=6;if(value==6);Selay(50);break;
				case 0xdb:Selay(50);value=7;if(value==7);Selay(50);break;
				case 0xeb:Selay(50);value=8;if(value==8);Selay(50);break;
				default:value=0;break;
			}
		}
	}
	return value;//返回最终的键值
}

void Selay(unsigned char k)		//@11.0592MHz                                                                       
{
	unsigned char o, u;
    while(k--)
	{
	_nop_();
	o = 2;
	u = 199;
	do
	{
		while (--u);
	} while (--o);
    }
}





JuZhen.h

#ifndef __JUZHEN_H_
#define __JUZHEN_H_

unsigned char keyscan();
void Selay(unsigned char k);


#endif

感悟

通过这次课设我也学习到了很多,通过写博客的方式来分享我的学习成果:
1.要学会使用switch case语句,要不一直用if语句会很麻烦。
2.定时器延时与Delay延时的区别:
定时器的做法是在你的程序里还有其他事要做的情况下去设置的。也就是说设置了定时器后就可以去做其他事情了,delay就是不做事光用消耗的,消耗一定的时间后再去做其他事。
3.extern后面要加全局变量,不能加局部变量。
4.使用指针定义的时候,要将指针指向一个区域。例如:unsigned char *p; p=&a;
5.指针与数组是可以相互转换的。
6.要让lcd上面显示相应的字符,要写入这个字符对应的Ascll码值,写入的整数字符要+0x30。要想变回原来的整数也要减去相应的0x30。
例: T=(DHT11_Dis[11]-0x30)*10+DHT11_Dis[12]-0x30;
7.要多看数据手册,多看一些比较成体系的视频,学习不要碎片化。

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