1.引脚介绍
从左到右引脚依次为:
2.接线
1.单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。(在第3章节.通信协议里讲)
2.从图中还可以看出要共地
3.通信协议
dht11采用单总线通信,是非常简单的主从通信模式。
由于只有一条数据线,并且还是双向的,所以说必须规定谁先发数据,主机应该发什么样子的波形(应该是先拉低一段时间,因为平时是高电平),然后从机看到是双方规定好的波形,该我发数据了,把温湿度以规定好的波形发给主机,主机看懂后就知道温湿度多少了。
具体主机发什么波形,从机发什么呢,先大概看一下波形:
可以看出并不是高电平为1,低电平为0,而是根据拉高的时间,从波形上看1比0宽一点,这是我们区分数据的关键
主机先拉低(起始信号)拉高(释放总线),从机也拉低(响应)拉高(响应),之后发送40位数据(可以转化为实际的温湿度),最后还有一个拉低(dht11结束信号)。
具体时间内对应下表:
4.代码
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
//DATA引脚 GPIOG,GPIO_Pin_11 注意:只用修改下方
#define dht11GPIOX GPIOB
#define dht11GPIO_Pin_X GPIO_Pin_6
#define RCC_APB2Periph_GPIO RCC_APB2Periph_GPIOB
typedef struct{
uint8_t Tem;
uint8_t Hum;
}DHT11_DATA;
extern DHT11_DATA dht11;
void DHT11_Config(void);
uint8_t DHT11_ReadData(void);//获取温湿度数据到结构体dht11里,成功返回0,超时返回1,数据校验失败返回2
#endif
#include "dht11.h"
#include "delay.h"
DHT11_DATA dht11={0};
#define DHT11_High() GPIO_SetBits(dht11GPIOX,dht11GPIO_Pin_X)
#define DHT11_Low() GPIO_ResetBits(dht11GPIOX,dht11GPIO_Pin_X)
#define DHT11_Read() GPIO_ReadInputDataBit(dht11GPIOX,dht11GPIO_Pin_X)
void DHT11_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct={0};
//1,开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO,ENABLE);
//2,配置GPIO
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏模式
GPIO_InitStruct.GPIO_Pin = dht11GPIO_Pin_X;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(dht11GPIOX,&GPIO_InitStruct);
//3,默认拉高
DHT11_High();
}
//读取DHT11数据
uint8_t DHT11_ReadData(void)
{
uint16_t cnt=0,i=0;
uint8_t data[5]={0};//前8位,保存在data[0]
//1,起始信号
DHT11_High();
DHT11_Low();
Delay_ms(20);
DHT11_High();
//2,等待从机响应信号
while(DHT11_Read() == 1) //等待低电平到来
{
cnt++;
Delay_us(1);
if(cnt>100)
return 1;//通信超时
}
cnt=0;//下次使用之前先清零
while(DHT11_Read() == 0) //等待高电平到来
{
cnt++;
Delay_us(1);
if(cnt>100)
return 1;//通信超时
}
//3,接收数据
for(i=0;i<40;i++) //循环接收40位数据
{
cnt=0;
while(DHT11_Read() == 1) //等待低电平到来
{
cnt++;
Delay_us(1);
if(cnt>100)
return 1;//通信超时
}
cnt=0;//下次使用之前先清零
while(DHT11_Read() == 0) //等待高电平到来
{
cnt++;
Delay_us(1);
if(cnt>100)
return 1;//通信超时
}
Delay_us(30);//延时区分接收到的是0还是1
if(DHT11_Read() == 1)
{
data[i/8] |= 1<<(7-i%8);
}else
{
data[i/8] &= ~(1<<(7-i%8));
}
}
//4,判断数据是否准确
if(data[0]+data[1]+data[2]+data[3] == data[4])
{
dht11.Tem = data[2];
dht11.Hum = data[0];
if((data[3] & 1<<7) != 0)//判断温度是否是零下
{
dht11.Tem = -dht11.Tem;
}
return 0;
}else
{
//printf("数据校验失败\r\n");
return 2;
}
}
前提条件是有delay函数stm32f10x延时函数