资讯详情

基于51单片机的双通道DHT11温湿度显示器(LCD1602)

基于STC89C单片机双通道51DHT11实时温湿度显示系统(LCD1602)

  • 前言
    • 题目要求
    • 实现的功能
    • 思路介绍
  • 代码部分
    • 注意事项
    • 驱动部分
      • LCD1602驱动
      • 按键驱动
    • 主要模块
      • 初始化
      • DHT11驱动
      • 中断服务程序
      • 显示函数
      • 主函数
      • 数学处理函数
  • 总结

前言

这是单片机系统的课程作业,有点匆忙。事实上,代码可以再次优化。我希望它能给你带来一些想法。这也是第一次使用 ,顺便学写作,甘,别说那么多废话。

题目要求

本课题要求学生利用数字温湿度收集环境信息I2C串口通信技术返回单片机LCD实时显示显示器要求湿度误差不大于5%,温度误差不大于2摄氏度;在LCD显示在屏幕上,刷新评率不低于0.5 Hz。包括系统组成STC-89C52开发板,LCD1602显示屏,数字传感器DHT11。LCD两个传感器的温度和湿度可以同时显示。

在这里插入图片描述

实现的功能

前三个问题已经解决了。当按钮切换到不同的状态时,,最大值为,检测到平均值平均值(51性能有限,其实答题能力有限),单片机过多次无法显示正确数据。标题中提到的使用IIC,但答主用,DHT11通过单总线通信,然后简单复制实现两个操作。

至于第四个问题,答案还没有出来。如果能在课程时间内更新,如果不行,就会随缘。~提供一个想法:LCD1602作为字符型LCD,没有画点函数,但内置8个自定义字符可以通过自定义字符显示曲线吗?如果你感兴趣,你可以试试。

  • 以往版本优化: 21.10:00 添加外部中断按钮抖动,优化部分代码,稍微提高速度.1要求 解决了切割屏幕后温度不实时更新的问题 21.18:07 完成任务1.3 21.22:00 1.最大值部分调试成功 22.09:26 1.2最大值可实现无缝记录,从启动到显示的最大值始终有效。 22.10:28 1.成功测量单平均值22串 22.11:16 1.2多平均值实时lcd、串口测量成功 22.15:30 1.1显示实时值刷新率提高

思路介绍

在这个实验中,首先是两条路DHT11温湿度传感器,管脚分别连接P2.0,P2.1。剩下的两个管脚分别由板子连接VCC和GND。将外部中断P3.连接到一个独立的按钮。按要求插好LCD1602.工作时DHT11测量外部温度。发送温度信息STC-C52,STC-C52实时检测DHT11的在线状态,使LCD1602实时显示.通过按钮切换显示两条路DHT离线状态、实时温湿度、平均温湿度和最大温湿度为11温湿度传感器。

开发板集成在芯片中CPU( 中央处理器),RAM( 数据存储器),ROM( 程序存储器)、定时器/ 计数器及多种功能I/O( 输入/ 输出) 计算机所需的基本功能部件,如接口,可以完成复杂的操作、逻辑控制、通信等功能。 软件设计理念:软件程序的设计包括多个模块,包括LCD1602显示驱动模块、延迟函数模块、按键检测模块等。

代码部分

以下是大家喜欢看到的代码部分

注意事项

驱动部分

为了方便管理,我把按钮和LCD驱动程序写了两个图书馆文件,但在实际使用中没有使用按钮扫描,因为避免程序运行太慢,无法检测到,选择使用外部中断来实现按钮。

LCD1602驱动

先来个头文件:注意PIN口的定义,这里只是一个简单的驱动函数,每个人都可以在网上找到类似的。

#ifndef __LCD_H_ #define __LCD_H_  /********************************** 包含头文件 **********************************/ #include<reg52.h>   /********************************** PIN口定义 **********************************/ #define LCD1602_DB P0  sbit LCD1602_RS = P3^5; sbit LCD1602_RW = P3^6; sbit LCD1602_EN = P3^4;    //void Lcd1602_Delay1ms(uint c); //误差 0usvo void LCD_Delay10ms(unsigned 
       
        int c
        )
        ; 
        //void Read_Busy(); //忙检测函数,判断bit7是0,允许执行;1禁止 
        void 
        Lcd1602_Write_Cmd
        (
        unsigned 
        char cmd
        )
        ; 
        //写命令 
        void 
        Lcd1602_Write_Data
        (
        unsigned 
        char dat
        )
        ; 
        //写数据 
        void 
        LcdSetCursor
        (
        unsigned 
        char x
        ,
        unsigned 
        char y
        )
        ; 
        //坐标显示 
        void 
        LcdShowStr
        (
        unsigned 
        char x
        ,
        unsigned 
        char y
        ,
        unsigned 
        char 
        *str
        )
        ; 
        //显示字符串 
        void 
        InitLcd1602
        (
        )
        ; 
        //1602初始化 
        #endif 
       

再来个C文件:只是简单的驱动函数,大家在网上随便都能找到相似的,也可以通过数据手册自己写。 这里有一个点,就是很多驱动都,具体原因求大佬告知。在这里为简化代码,我也忽略了。

#include <reg52.h>
#include "LCD.h"

void Lcd1602_Write_Cmd(unsigned char cmd)     //写命令
{ 
        
    //Read_Busy();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
	LCD_Delay10ms(1);
    LCD1602_EN = 1;
	LCD_Delay10ms(1);
    LCD1602_EN = 0;    
}

void Lcd1602_Write_Data(unsigned char dat)   //写数据
{ 
        
      //Read_Busy();
      LCD1602_RS = 1;
      LCD1602_RW = 0;
      LCD1602_DB = dat;
	  LCD_Delay10ms(1);
      LCD1602_EN = 1;
	  LCD_Delay10ms(1);
      LCD1602_EN = 0;
}

//指定位置开始显示数据!
void LcdSetCursor(unsigned char x,unsigned char y)  //坐标显示
{ 
        
    unsigned char addr;
    if(y == 0)
        addr = 0x00 + x;//第一行开始,x表示一行的第x个
    else
        addr = 0x40 + x;//第二行开始,x表示一行的第x个
    
    Lcd1602_Write_Cmd(addr|0x80);
}

void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)     //显示字符串
{ 
        
    LcdSetCursor(x,y);      //当前字符的坐标
    while(*str != '\0')
    { 
        
        Lcd1602_Write_Data(*str++);
    }
}

void InitLcd1602()              //1602初始化
{ 
        
    Lcd1602_Write_Cmd(0x38);    //打开,5*8,8位数据
    Lcd1602_Write_Cmd(0x0c);	//开显示,未添加光标闪烁
	Lcd1602_Write_Cmd(0x01);    //清屏 
	Lcd1602_Write_Cmd(0x06); 
   // Lcd1602_Write_Cmd(0x07); //地址指针加一,右移
    
}

void LCD_Delay10ms(unsigned int c)   //误差 0us
{ 
        
    unsigned char a,b;
    for(;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}



按键驱动

没啥好说的,虽然写了,但其实我就没咋用到。。。。。。

头文件

#ifndef __KEY_H_
#define __KEY_H_

#include<reg52.h>

#define FOSC 11059200L
#define uint unsigned int
/********************************** PIN口定义 **********************************/  


sbit KEY    = P3^0;//独立按键S2
sbit KEY0   = P3^1;//独立按键S3
//sbit KEY = P3^6;//上课用单片机
//sbit KEY0 = P3^5;




void KeyScanInd();//独立按键检测
void Keymode();  //模式切换
					 
#endif

C文件:没用到就注释了哈

#include <reg52.h>
#include "key.h"
#include "LCD.h"

//uint KeyValue=0;



//void KeyScanInd()
//{ 
        
// KEY = 1; //判断独立按键
// KEY0 = 1; //判断独立按键
// 
// if(KEY != 1)
// { 
        
// Delayms(5);//软件消抖
// if( KEY!= 1)
// { 
        
// KeyValue++;
// if(KeyValue==4) KeyValue=1;
// while(KEY != 1);//松手检测 
// }
// }
// 
// if(KEY0 != 1)
// { 
        
// Delayms(5);//软件消抖
// if( KEY0!= 1)
// { 
        
// KeyValue--;
// if(KeyValue==0) KeyValue=3;
// while(KEY0 != 1);//松手检测 
// }
// }
// 
//}

//void Keymode()
//{ 
        
// if(KeyValue==1)//当前值
// { 
        
// LcdShowStr(0,0,"Present value!");
// P1 = ~P1;
// }
// if(KeyValue==2)//平均值
// { 
        
// LcdShowStr(0,0,"Average value!");
// P1 = ~P1;
// }
// if(KeyValue==3)//最大值
// { 
// LcdShowStr(0,0,"Maximum value!");
// P1 = ~P1;
// 
// } 
//}



我使用到的按键是P3^3,通过外部中断1触发(不好意思忘更新了),这部分直接写到主要模块了。

//键盘函数中断版
void KeymodeINTER()
{ 
        
	switch(modeflag)
	{ 
        
		case 0:  displaySTATUS();
				 Lcd1602_Write_Cmd(0x01);  //清屏
		break;
		//当前值
		case 1: 			 
				displayNOW();  				 	         
				Lcd1602_Write_Cmd(0x01);    //清屏 
		break;
				 
		//平均值
		case 2:   				
				displayAVE();
				Lcd1602_Write_Cmd(0x01);    //清屏 
				 
		break;
		//最大值
		case 3:   
				 	         
				 displayMAX();	
				 Lcd1602_Write_Cmd(0x01);    //清屏 
		break;
		
		case 4:  
				 displayBight();	
				 Lcd1602_Write_Cmd(0x01);    //清屏 
		break;
		
		case 5:  
				 displayBight1();
				 modeflag = 0;	
				 Lcd1602_Write_Cmd(0x01);    //清屏 
		break;
	}	
}

主要模块

初始化

淦定义了好多变量,大家可以看一下代码的注释 这里有一点,,最后只好把一个二维数组改成一维的,放弃储存一些数据。

/********************************************************************************* * 【编写时间】: 2021年3月22日 * 【作 者】: 手动打码,滑稽 * 【版 本】: 1.7 * 【编译环境】: Keil μVisio5 * 【程序功能】: * 【版本更新】: 21.10:00 添加外部中断按键消抖,优化部分代码,略微提高速度,可实现功能1.1要求 解决了切屏后温度不实时更新的问题 21.18:07 完成任务1.3 21.22:00 1.2最大值部分调试成功 22.9:26 1.2最大值可实现无缝记录,开机到显示的最大值一直有效。 22.10:28 1.2单平均值串口测量成功 22.11:16 1.2多平均值实时lcd、串口测量成功 22.15:30 1.1显示实时值刷新率提高 * 【预期改动】:1.使用定时器0按键消抖,使用定时器1定时发送串口数据(可拓展为1.2平均值问题)--------失败 2.不用数组储存数据,直接累加!!!解决问题1.2----------成功 **********************************************************************************/

#include <reg52.h>
#include <intrins.h>
#include <math.h>
#include <stdio.h>
#include "LCD.h"
#include "key.h"
#include <string.h>

#define uchar unsigned char
#define uint unsigned int

#define N 5 //平均值计算的组数
/******************************************************************************* * 实验名 :温度显示程序 * 使用的IO : P2^0;P2^1; : *******************************************************************************/

sbit Temp_data =P2^0; //
sbit Temp_data1=P2^1;
sbit flag   = P3^3;//中断启动位

uchar modeflag = 0;//键盘模式切换

uchar status1 = 0;//DHT11状态
uchar status  = 0;//DHT11状态

//函数定义
void Delayms(unsigned int ms);

void DHT11_delay_us(unsigned char n);
void DHT11_delay_ms(unsigned int z);

void DHT11_start();

uchar DHT11_rec_byte();
uchar DHT11_rec_byte1();

void DHT11_receive();
void DHT11_receive1();
void InitUART(void);

void displaySTATUS();
void displayNOW();
void displayAVE();
void displayMAX();

void manage_math();
void max_math();
void avr_math();

unsigned int rec_dat[8]={ 
        0,0,0,0,0,0,0,0};//温度初始数组


double dat_manage[4]={ 
         0, 0, 0, 0};//实时数据储存数组
double dat_max[4]={ 
        0,0,0,0};//最大值储存数组
double dat_avr[4]={ 
        0,0,0,0};//平均值储存数组

double S[4] = { 
        0,0,0,0};      //累加和
double C[4] = { 
        0,0,0,0};      //本次采样值
double A[4] = { 
        0,0,0,0};      //平均值

//第一路传感器
unsigned char rec_dat_lcd0[6];
unsigned char rec_dat_lcd1[6];
unsigned char rec_dat_lcd2[6];
unsigned char rec_dat_lcd3[6];

//第二路传感器
unsigned char rec_dat_lcd4[6];
unsigned char rec_dat_lcd5[6];
unsigned char rec_dat_lcd6[6];
unsigned char rec_dat_lcd7[6];

//最大值平均值字符串中转函数
unsigned char dat_max_lcd0[6];
unsigned char dat_max_lcd1[6];
unsigned char dat_max_lcd2[6];
unsigned char dat_max_lcd3[6];


DHT11驱动

我们将DHT11接受到的数据储存在rec_dat[ ]数组中,并记录判断位,为第三问求做准备。 我将错误设置成校验位与传输数据不符,当然DHT11没毛病这种错误一定不会出现。。。

//DHT11起始信号1

void DHT11_start()	
{ 
        
	Temp_data=1;
	
	DHT11_delay_us(2);
	
	Temp_data=0;
	
	DHT11_delay_ms(20);
	
	Temp_data=1;
	
	DHT11_delay_us(13);
	

}

//DHT11起始信号2

void DHT11_start1()	
{ 
        
	Temp_data1=1;//
	
	DHT11_delay_us(2);
	
	Temp_data1=0;//
	
	DHT11_delay_ms(20);
	
	Temp_data1=1;//
	
	DHT11_delay_us(13);
	

}
//接收一个字节通道1


unsigned char DHT11_rec_byte()
{ 
        
	
	unsigned char i,dat;

	
	for(i=0;i<8;i++)
	{ 
        
			while(!Temp_data);
		  DHT11_delay_us(8);
			dat<<=1;
			if(Temp_data==1)
			{ 
        
				dat+=1;
			}
			while(Temp_data);
	}

	return dat;

	
}
//接收一个字节通道2


unsigned char DHT11_rec_byte1()
{ 
        
	
	unsigned char i,dat1;
	
	for(i=0;i<8;i++)
	{ 
        
			while(!Temp_data1);
			DHT11_delay_us(8);
			dat1<<=1;
			if(Temp_data1==1)
			{ 
        
				dat1+=1;
			}
			while(Temp_data1);
	}

	return dat1;
	
}

//接收温湿度数据通道1
void DHT11_receive()
{ 
        
	unsigned int R_H,R_L,T_H,T_L;
	unsigned char RH,RL,TH,TL,revise;
	
	DHT11_start();
	Temp_data=1;
	
	
	if(Temp_data==0)
	{ 
        
					
		status=Temp_data;//此时为0,准备好嘞 
		while(Temp_data==0);   //等待拉高 
        DHT11_delay_us(40);  //拉高后延时80us
		
        R_H=DHT11_rec_byte();    //接收湿度高八位 
        R_L=DHT11_rec_byte();    //接收湿度低八位 
        T_H=DHT11_rec_byte();    //接收温度高八位 
        T_L=DHT11_rec_byte();    //接收温度低八位
        revise=DHT11_rec_byte(); //接收校正位

        DHT11_delay_us(25);    //结束

        if((R_H+R_L+T_H+T_L)==revise)      //校正
        { 
        
            RH=R_H;
            RL=R_L;
            TH=T_H;
            TL=T_L;
	
        } 
		else
		{ 
        
			status = 2;//此时为2,数据有误
		}
        /*数据处理,方便显示*/
        rec_dat[0]=RH;
        rec_dat[1]=RL;
        rec_dat[2]=TH;
        rec_dat[3]=TL;

	}
		else
	{ 
        
		status = 1;//此时为1,DHT11断线
	}
}

//接收温湿度数据通道2
void DHT11_receive1()
{ 
        
	uint R_H1,R_L1,T_H1,T_L1;
	uchar RH1,RL1,TH1,TL1,revise1;
	
	DHT11_start1();
	
	Temp_data1=1;	
	
	
	if(Temp_data1==0)
	{ 
        
		status1=Temp_data1;//此时为0,准备好嘞
		
		while(Temp_data1==0);   //等待拉高 
        DHT11_delay_us(40);  //拉高后延时80us
		
        R_H1=DHT11_rec_byte1();    //接收湿度高八位 
        R_L1=DHT11_rec_byte1();    //接收湿度低八位 
        T_H1=DHT11_rec_byte1();    //接收温度高八位 
        T_L1=DHT11_rec_byte1();    //接收温度低八位
        revise1=DHT11_rec_byte1(); //接收校正位

        DHT11_delay_us(25);    //结束

        if((R_H1+R_L1+T_H1+T_L1)==revise1)      //校正
        { 
        
            RH1=R_H1;
            RL1=R_L1;
            TH1=T_H1;
            TL1 

标签: s3壁挂型温湿度传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台