温湿度传感器DHT11的使用
程序员文章站
2022-07-13 17:15:54
...
DHTDAT和单片机引脚相连。
1、VDD 供电3.3~5.5V DC
2、DATA 串行数据,单总线
3、NC 空脚
4、GND 接地,电源负极
单总线传送数据位定义
DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次传送40位数据,高位先出。
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位。
注:其中湿度小数部分为0。
校验位数据定义
“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”8bit校验
位等于所得结果的末8位。
Timing图:
从上图可以看出上电开始时主机信号要保持高电平,可以看出,由上拉电阻拉高。然后主机发送一个低电平信号作为起始信号,根据数据手册,低电平时间为18-30ms,之后微处理器将电平拉高等待传感器发送低电平响应信号,响应信号结束后传感器输出一段时间的高电平准备输出数据,从图中可以看出,输出数据0或者数据1的区别在于输出高电平的时间不同,而在表示数据位的高电平之前均输出相同时间低电平,查询数据手册可以得出高电平时间为23-27us表示数据位0,68-74us表示数据位1,因此可以在输出数据位之前的低电平结束术后延时30us,通过读取此时数据总线的状态,来判断输出的是0还是1。
Proteus仿真图
程序
MAIN.H
#ifndef _MAIN_H
#define _MAIN_H
/*--------------------------------------------*/
#include "iodefine.h" //自定义内容
/*--------------------------------------------*/
#define DHT11
#define interruptInit //在DHT文件中
#define DELAY
//#define _TEST_CHANGE_
/*--------------------------------------------*/
#ifdef DHT11
void start_DHT11();
void time_Tgo(); //主机释放总线时间,13us
//void time_Trel(); //DHT11响应低电平时间,83us
//void time_Treh(); //DHT11响应高电平时间,87us
/*void time_Tlow_en(); //信号 0 1 低电平时间 = 传感器释放总线时间,54us
void time_Th0(); //信号0高电平时间,24us
void time_Th1(); //信号1高电平时间,71us
*/
void time_delay30us();
uchar getDHT11_byte(); //获得一个字节数据
void getDHT11_allData(); //获得所有40位数据,存放在sensor_DATA[4]中
void DHT_seg7diplay(); //前两位显示湿度 百分比,后两位显示温度 摄氏度
#endif
/*--------------------------------------------*/
#ifdef DELAY
#define DELAY_MS_US
void delay_ms(uint xms);
void delay_us(uint Xus);
#endif
/*--------------------------------------------*/
#ifdef interruptInit
void interrupt_Init(void);
#endif
/*--------------------------------------------*/
#endif
IODEF.H
#ifndef _IODEF_H_
#define _IODEF_H_
#include<REG52.H>
#include <INTRINS.H>
#include <ABSACC.H>
#define uchar unsigned char
#define uint unsigned int
/*
#define seg70 P2_0 //湿度十位数//ADC千位
#define seg71 P2_1 //湿度个位数//ADC百位
#define seg72 P2_2 //温度十位数//ADC十位
#define seg73 P2_3 //温度个位数//ADC个位
*/
#define segA P1_4
#define segB P1_5 //用74HC139节省IO资源
#define flagled P1_1 //DTH11校验正确显示灯
sbit P0_0 = P0^0;
sbit P0_1 = P0^1;
sbit P0_2 = P0^2;
sbit P0_3 = P0^3;
sbit P0_4 = P0^4;
sbit P0_5 = P0^5;
sbit P0_6 = P0^6;
sbit P0_7 = P0^7;
sbit P1_0 = P1^0;
sbit P1_1 = P1^1;
sbit P1_2 = P1^2;
sbit P1_3 = P1^3;
sbit P1_4 = P1^4;
sbit P1_5 = P1^5;
sbit P1_6 = P1^6;
sbit P1_7 = P1^7;
sbit P2_0 = P2^0;
sbit P2_1 = P2^1;
sbit P2_2 = P2^2;
sbit P2_3 = P2^3;
sbit P2_4 = P2^4;
sbit P2_5 = P2^5;
sbit P2_6 = P2^6;
sbit P2_7 = P2^7;
sbit P3_0 = P3^0;
sbit P3_1 = P3^1;
sbit P3_2 = P3^2;
sbit P3_3 = P3^3;
sbit P3_4 = P3^4;
sbit P3_5 = P3^5;
sbit P3_6 = P3^6;
sbit P3_7 = P3^7;
#endif
DELAY.C
#include"main.h"
#ifdef DELAY_MS_US
void delay_ms(uint xms)
{
uint loop;
for (loop = 0; loop < xms; loop++)
{
/* 1ms_code 误差 +0.306315ms/2000ms */
uchar i, j;
_nop_();
i = 2;
j = 195;
do
{
while (--j);
} while (--i);
}
}
/*--------------------------*/
void delay_us(uint Xus)
{
uint i,j;
for(i=0;i<8;i++){
for(j=0;j<Xus;j++){
_nop_();
}
}
}
#endif
DHT11.C
#include"main.h"
#ifdef DHT11
#define DATA_DHT11 P3_5 //DHTDAT
uchar data sensor_DATA[4]={0x0,0x0,0x0,0x0};
uchar num; //数组第几个
uchar code SEG7_yin[] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
};
#ifdef _TEST_CHANGE_
void testChange()
{
uchar i = 0x56;
sensor_DATA[2] = i;
}
#endif
void start_DHT11()
{
DATA_DHT11 = 1;
_nop_();_nop_();_nop_();_nop_();
DATA_DHT11 = 0;
delay_ms(20);
DATA_DHT11 = 1; //微处理器的I/O设置为输入状态,由上拉电阻拉高
time_Tgo(); //释放总线,13us,等待回应时间应大于proteus上的时间30us
time_Tgo();
time_Tgo(); //3*13us
//DATA_DHT11 = 1;
}
void time_Tgo()
{
uchar i;
_nop_();
i = 3;
while (--i);
}
/*
void time_Trel()
{
uchar i;
_nop_();
i = 35;
while (--i);
}
void time_Treh()
{
uchar i;
_nop_();
i = 37;
while (--i);
}
void time_Tlow_en()
{
uchar i;
i = 11;//22 == 54us
while (--i);
}
*/
/*
void time_Th0()
{
unchar i;
_nop_();
i = 8;
while (--i);
}
void time_Th1()
{
unchar i;
i = 30;
while (--i);
}
*/
void time_delay30us()
{
uchar i;
i = 11;
while (--i);
}
uchar getDHT11_byte()
{
uchar i,dat,temp;
for ( i = 0; i < 8; i++)
{
//time_Tlow_en();//先过54us
while(!DATA_DHT11);//先过54us,低电平
time_delay30us();
temp = 0;
if(DATA_DHT11 == 1)
{
temp = 1;
}
while(DATA_DHT11);
dat <<= 1;
dat = dat|temp;
}
return dat;
}
void getDHT11_allData()
{
uchar RH,RL,TH,TL,revise;
start_DHT11();
if(DATA_DHT11 == 0) //接收83us的应答信号,
{
while(DATA_DHT11 == 0); //等待拉高现在data为0
while(DATA_DHT11); //退出通知单片机接受信号,等87us
RH=getDHT11_byte(); //接收湿度高八位
RL=getDHT11_byte(); //接收湿度低八位
TH=getDHT11_byte(); //接收温度高八位
TL=getDHT11_byte(); //接收温度低八位
revise=getDHT11_byte(); //接收校正位
//time_Tlow_en(); //结束
if((RH+RL+TH+TL)==revise) //校正
{
flagled = 1;
sensor_DATA[0] = RH;
sensor_DATA[1] = RL;
sensor_DATA[2] = TH;
sensor_DATA[3] = TL;
}
}
}
void DHT_seg7diplay()
{
P0 = 0;
P0 = SEG7_yin[sensor_DATA[0]/10];
segB = 0;
segA = 0;
delay_us(100);
P0 = 0;
P0 = SEG7_yin[sensor_DATA[0]%10];
segB = 0;
segA = 1;
delay_us(100);
P0 = 0;
P0 = SEG7_yin[sensor_DATA[2]/10];
segB = 1;
segA = 0;
delay_us(100);
P0 = 0;
P0 = SEG7_yin[sensor_DATA[2]%10];
segB = 1;
segA = 1;
delay_us(100);
}
/*************************************************/
#ifdef interruptInit
void interrupt_Init(void)
{
EA = 1;
IT0 = 1; //下降沿触发
EX0 = 1; //INT0 P3.2
PX0 = 0;
IT1 = 1;
EX1 = 1;
PX1 = 1;
}
#endif
/*************************************************/
#endif
MAIN.C
#include "main.h"
#define led P1_0
void main()
{
interrupt_Init();
delay_ms(1000);
flagled = 0;
while(1)
{
led = ~led;
DHT_seg7diplay();
}
}
void interrupt_getDHT11_Data() interrupt 0 //EXTERNAL INT 0 0003h
{
getDHT11_allData(); //19.75694ms
delay_us(100);
getDHT11_allData(); //连续获取两次以获得实时数据
}
^^Crystal