七、Proteus817中实现51单片机DHT11多点温湿度读取

前言

本文讲了使用51单片机和DHT11实现多点温湿度读取,只讲使用,不讲原理,快速上手。

一、绘制仿真

1、新建仿真和添加器件

主要就是DHT11,也可以把前几次的那个仿真复制一份。

2、绘制仿真图布线

(1)引脚连接

DHT11(1-3)

VCC-------VCC

DATA1----P20

DATA2----P21

DATA3----P22

GND------GND

(2)布线

注意添加上拉电阻

(3)添加串口

(4)设置时钟频率

双击芯片更改

二、编写代码

这个多个器件的代码我直接做成封装版。

注意:三个DHT11器件本可以用一个代码和不同的宏定义实现,但是对于Proteus仿真中,这样会导致时序不完整,影响读取。

所以我们对于每新增一个器件,我们就要新增一个c文件,但是可以共用一个h文件。

我们新建三个DHT11的C文件,命名不同的名字,再新建一个h文件即可。

1、第一个DHT11

DHT11.c

c 复制代码
#include "reg52.h"
#include "DHT11.h"
#include "uart.h"
sbit DHT11_Data_Line = P2^0;//器件数据引脚
void Delay20ms()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 36;
	j = 217;
	do
	{
		while (--j);
	} while (--i);
}
 
void Delay25us()		//@11.0592MHz
{
	unsigned char i;
 
	i = 9;
	while (--i);
}

void DHT11_Start(void)
{
	DHT11_Data_Line=0;     
	Delay20ms();		 
	DHT11_Data_Line=1;		 
	Delay25us();		 
}
 

uchar DHT11_Check(void)
{
	uchar flag=0;
	while(DHT11_Data_Line&&(flag<100))    //DHT11_Data_Line:等待低电平到来,flag<100防止陷入        
    {flag++;}                             //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。
	if(flag>=100)return 1;                //未接收到DHT11的响应信号
	else flag=0;                          //flag清零
	while(!DHT11_Data_Line&&(flag<100))  //DHT11_Data_Line:等待高电平到来,flag<100防止陷入
    {flag++;}                            //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。                                      
	if(flag>=100)return 1;               //未接收到DHT11的响应信号
	else return 0;                       //接收到DHT11的响应信号
}

// ---- 读取 1 字节 ----
uchar DHT11_Read_Byte(void)
{
    uchar i, dat = 0;
    dat = 0;
    for(i = 0; i < 8; i++)      // 循环8次,接收一个字节的数据
    {
        // 等待低电平结束,进入高电平
        while(!DHT11_Data_Line);

        // 延时约 35~40us,保证采样在高电平中间
        Delay25us();

        dat <<= 1;                 // dat 左移一位
        if(DHT11_Data_Line)         // 高电平判定为 1
        {
            dat |= 1;
        }

        // 等待高电平结束,准备下一位
        while(DHT11_Data_Line);
    }
    return dat;
}


// ---- 读取温湿度 ----
unsigned char DHT11_Read_Data(uchar *temp, uchar *humi)//返回值为读取数据状态
{
    uchar dat[5]={0,0,0,0,0};
    unsigned char i;

    DHT11_Start();
    if(DHT11_Check()==0)
    {
		while(DHT11_Data_Line);
        dat[0] = DHT11_Read_Byte(); // 湿度整数
        dat[1] = DHT11_Read_Byte(); // 湿度小数
        dat[2] = DHT11_Read_Byte(); // 温度整数
        dat[3] = DHT11_Read_Byte(); // 温度小数
        dat[4] = DHT11_Read_Byte(); // 校验和

        // ---- 打印原始字节 ---便于自行检测校验数据
        UART_SendString("Raw: ");
        for(i=0;i<5;i++)
        {
            UART_SendDec(dat[i]);
            UART_SendChar(' ');
        }
        UART_SendString("\r\n");
				
        *humi = dat[0];
        *temp = dat[2];

        if((dat[0]+dat[1]+dat[2]+dat[3])==dat[4])//校验和
        {
            return 2;
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
}

2、第二个DHT11

c 复制代码
#include "reg52.h"
#include "DHT11.h"
#include "uart.h"
sbit DHT11_Data_Line2 = P2^1;//器件数据引脚
void Delay20ms_DHT11_2()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 36;
	j = 217;
	do
	{
		while (--j);
	} while (--i);
}
 
void Delay25us_DHT11_2()		//@11.0592MHz
{
	unsigned char i;
 
	i = 9;
	while (--i);
}

void DHT11_Start2(void)
{
	DHT11_Data_Line2=0;     
	Delay20ms_DHT11_2();		 
	DHT11_Data_Line2=1;		 
	Delay25us_DHT11_2();		 
}
 

unsigned char DHT11_Check2(void)
{
	uchar flag=0;
	while(DHT11_Data_Line2&&(flag<100))    //DHT11_Data_Line2:等待低电平到来,flag<100防止陷入        
    {flag++;}                             //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。
	if(flag>=100)return 1;                //未接收到DHT11的响应信号
	else flag=0;                          //flag清零
	while(!DHT11_Data_Line2&&(flag<100))  //DHT11_Data_Line2:等待高电平到来,flag<100防止陷入
    {flag++;}                            //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。                                      
	if(flag>=100)return 1;               //未接收到DHT11的响应信号
	else return 0;                       //接收到DHT11的响应信号
}

// ---- 读取 1 字节 ----
unsigned char DHT11_Read_Byte2(void)
{
    uchar i, dat = 0;
    dat = 0;
    for(i = 0; i < 8; i++)      // 循环8次,接收一个字节的数据
    {
        // 等待低电平结束,进入高电平
        while(!DHT11_Data_Line2);

        // 延时约 35~40us,保证采样在高电平中间
        Delay25us_DHT11_2();

        dat <<= 1;                 // dat 左移一位
        if(DHT11_Data_Line2)         // 高电平判定为 1
        {
            dat |= 1;
        }

        // 等待高电平结束,准备下一位
        while(DHT11_Data_Line2);
    }
    return dat;
}


// ---- 读取温湿度 ----
unsigned char DHT11_Read_Data2(uchar *temp, uchar *humi)//返回值为读取数据状态
{
    uchar dat[5]={0,0,0,0,0};
    unsigned char i;

    DHT11_Start2();
    if(DHT11_Check2()==0)
    {
		while(DHT11_Data_Line2);
        dat[0] = DHT11_Read_Byte2(); // 湿度整数
        dat[1] = DHT11_Read_Byte2(); // 湿度小数
        dat[2] = DHT11_Read_Byte2(); // 温度整数
        dat[3] = DHT11_Read_Byte2(); // 温度小数
        dat[4] = DHT11_Read_Byte2(); // 校验和

        // ---- 打印原始字节 ---便于自行检测校验数据
        UART_SendString("Raw: ");
        for(i=0;i<5;i++)
        {
            UART_SendDec(dat[i]);
            UART_SendChar(' ');
        }
        UART_SendString("\r\n");
				
        *humi = dat[0];
        *temp = dat[2];

        if((dat[0]+dat[1]+dat[2]+dat[3])==dat[4])//校验和
        {
            return 2;
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
}

3、第三个DHT11

c 复制代码
#include "reg52.h"
#include "DHT11.h"
#include "uart.h"
sbit DHT11_Data_Line3 = P2^2;//器件数据引脚
void Delay20ms_DHT11_3()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 36;
	j = 217;
	do
	{
		while (--j);
	} while (--i);
}
 
void Delay25us_DHT11_3()		//@11.0592MHz
{
	unsigned char i;
 
	i = 9;
	while (--i);
}

void DHT11_Start3(void)
{
	DHT11_Data_Line3=0;     
	Delay20ms_DHT11_3();		 
	DHT11_Data_Line3=1;		 
	Delay25us_DHT11_3();		 
}
 

uchar DHT11_Check3(void)
{
	uchar flag=0;
	while(DHT11_Data_Line3&&(flag<100))    //DHT11_Data_Line3:等待低电平到来,flag<100防止陷入        
    {flag++;}                             //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。
	if(flag>=100)return 1;                //未接收到DHT11的响应信号
	else flag=0;                          //flag清零
	while(!DHT11_Data_Line3&&(flag<100))  //DHT11_Data_Line3:等待高电平到来,flag<100防止陷入
    {flag++;}                            //while死循环,当一定时间flag=100后还未检测到低电平则跳出循环。                                      
	if(flag>=100)return 1;               //未接收到DHT11的响应信号
	else return 0;                       //接收到DHT11的响应信号
}

// ---- 读取 1 字节 ----
uchar DHT11_Read_Byte3(void)
{
    uchar i, dat = 0;
    dat = 0;
    for(i = 0; i < 8; i++)      // 循环8次,接收一个字节的数据
    {
        // 等待低电平结束,进入高电平
        while(!DHT11_Data_Line3);

        // 延时约 35~40us,保证采样在高电平中间
        Delay25us_DHT11_3();

        dat <<= 1;                 // dat 左移一位
        if(DHT11_Data_Line3)         // 高电平判定为 1
        {
            dat |= 1;
        }

        // 等待高电平结束,准备下一位
        while(DHT11_Data_Line3);
    }
    return dat;
}


// ---- 读取温湿度 ----
unsigned char DHT11_Read_Data3(uchar *temp, uchar *humi)//返回值为读取数据状态
{
    uchar dat[5]={0,0,0,0,0};
    unsigned char i;

    DHT11_Start3();
    if(DHT11_Check3()==0)
    {
		while(DHT11_Data_Line3);
        dat[0] = DHT11_Read_Byte3(); // 湿度整数
        dat[1] = DHT11_Read_Byte3(); // 湿度小数
        dat[2] = DHT11_Read_Byte3(); // 温度整数
        dat[3] = DHT11_Read_Byte3(); // 温度小数
        dat[4] = DHT11_Read_Byte3(); // 校验和

        // ---- 打印原始字节 ---便于自行检测校验数据
        UART_SendString("Raw: ");
        for(i=0;i<5;i++)
        {
            UART_SendDec(dat[i]);
            UART_SendChar(' ');
        }
        UART_SendString("\r\n");
				
        *humi = dat[0];
        *temp = dat[2];

        if((dat[0]+dat[1]+dat[2]+dat[3])==dat[4])//校验和
        {
            return 2;
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
}

4、DHT11.h

c 复制代码
#ifndef _DHT11_H
#define _DHT11_H

#define uchar unsigned char
#define uint  unsigned int

unsigned char DHT11_Read_Data(unsigned char *temp, unsigned char *humi);//返回值为读取数据状态
unsigned char DHT11_Read_Data2(unsigned char *temp, unsigned char *humi);//返回值为读取数据状态
unsigned char DHT11_Read_Data3(unsigned char *temp, unsigned char *humi);//返回值为读取数据状态

#endif

5、main.c

c 复制代码
#include "intrins.h"
#include "reg52.h"
#include "string.h"
#include "DHT11.h"
#include "uart.h"

void Delay1000ms(void)	//@11.0592MHz
{
	unsigned char data i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	unsigned char humi,temp;
	unsigned char humi2,temp2;
	unsigned char humi3,temp3;
	UART_Init(9600);
	while(1)
	{
        DHT11_Read_Data(&temp,&humi);//读取第一个DHT11
		DHT11_Read_Data2(&temp2,&humi2);//读取第二个DHT11
		DHT11_Read_Data3(&temp3,&humi3);//读取第三个DHT11
		UART_SendString("Temp1=");
		UART_SendDec(temp);
		UART_SendString("C, Humi1=");
		UART_SendDec(humi);
		UART_SendString("%\r\n");
		
		UART_SendString("Temp2=");
		UART_SendDec(temp2);
		UART_SendString("C, Humi2=");
		UART_SendDec(humi2);
		UART_SendString("%\r\n");
		
		UART_SendString("Temp3=");
		UART_SendDec(temp3);
		UART_SendString("C, Humi3=");
		UART_SendDec(humi3);
		UART_SendString("%\r\n");

        UART_SendString("--------\r\n");
        
        // 延迟一段时间后再读取
        Delay1000ms();
        Delay1000ms(); // 总共延迟2秒	
	}
}

6、串口代码

串口代码只需要借鉴之前的封装代码即可,或者去第一章添加。一键传送

三、功能测试

1、编译文件和导入文件

编译成功后,将hex文件导入仿真。

双击芯片,导入文件。

2、运行仿真测试

可以看到数据和器件一一对应

四、总结

本章讲了51单片机和DHT11多点温湿度读取,如需新增更多的DHT11,只需要新增c文件,然后修改c文件中函数名字不要重复,可以参考我的命名规则。然后将读取函数放到h文件声明。