前言
本文讲了使用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文件声明。