DHT11传感器测温湿度,按键调节阈值,蜂鸣器报警

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

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

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

    课设要求

    代码呈现

    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 <reg52.h>
    #include <intrins.h>
    
    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 <reg52.h>
    #include <intrins.h>
    
    #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 <reg52.h>
    #include <intrins.h>
    #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.要多看数据手册,多看一些比较成体系的视频,学习不要碎片化。

    作者:卡莫西夫的忧伤

    物联沃分享整理
    物联沃-IOTWORD物联网 » DHT11传感器测温湿度,按键调节阈值,蜂鸣器报警

    发表评论