一:简述
硬件:硬件为ESP-LAUNCHER开发板(使用GPIO5口)。
模块:DHT11
需求:8266SDK开发,读取DHT11数据,串口打印(这次操作,只读取了温湿度的整数位)
二:简单认识DHT11
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。
引脚说明:
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位。
DHT11时序图:(用户主机(MCU)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始
信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信采集。)
8266读取DHT11的步骤:
步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:
8266的GPIO5设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),8266的GPIO5设置为输入状态,由于上拉电阻,8266的GPIO5即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。发送信号如图示:
步骤三:
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据,8266的GPIO5此时处于输入状态,检测到I/O有低电平(DHT11回应信号)后,等待87微秒的高电平后的数据接收,发送信号如图所示:
步骤四:
由DHT11的DATA引脚输出40位数据,8266的GPIO5电平的变化接收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。位数据“0”、“1”格式信号如图所示:
结束信号:
DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
DHT11的信号特性:
三:程序解密
GPIO初始化:
void DHT11_PUT(uint8 val)//设置输出的IO口
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5); //将GPIO5设为IO口
GPIO_OUTPUT_SET(GPIO_ID_PIN(5), val);//主机发送高低电平
}
void DHT11_IN()//设置输入的IO口
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5); // GPIO5设为IO口
GPIO_DIS_OUTPUT(GPIO_ID_PIN(5));
}
读取数据:
int ICACHE_FLASH_ATTR dht11_init(void)
{
int counter = 0;//计数标志
uint32 i;
int bit = 0;//所收到的数据位的个数
int check = 0;//校验标志
int ret= 0;//标志量
DHT11_PUT(1);//dht11的GPIO5先设为高
delay_ms(10);
DHT11_PUT(0);//dht11的GPIO5设为低
delay_ms(20);//延时20毫秒,大于18毫秒
DHT11_IN();
os_delay_us(30);//等待DHT11做出响应
//等待dht11响应电平,此时电平应变为0
while(GPIO_INPUT_GET(GPIO_ID_PIN(5)) == 1 && i < DHT_NUM)
{
if(i >= DHT_NUM)
{
return ret = 1;
os_printf("DHT11未响应\n");
}
os_delay_us(1);
i++;
}
for(i=0;i<MAX_NUM;i++)
{
counter = 0;
while(GPIO_INPUT_GET(GPIO_ID_PIN(5)) == state)
{
counter++;
os_delay_us(1);
if(counter == 1000)
{
break;
}
}
state = GPIO_INPUT_GET(GPIO_ID_PIN(5));
if(counter == 1000)
{
break;
}
//若是代表0、1数据的脉冲,就读取值,少于DHT11定义的时长为0,大于为1,通过位操作将收到的5组8位数据分别存入data0至4中,分别代表湿度整数、湿度小数、温度整数、温度小数及校验和的值
//因为在响应信号为低电平的时候,i由0变为1,拉高准备输出的时候变为2,信号低电平时变为3,高电平时变为4,所以(i > 3) && (i % 2 == 0)
if((i >3) && (i % 2 == 0))
{
DHT_DATA[bit / 8] <<= 1;//不管是0还是1,先左移一位补个0,后边是1就或1,不是则不再处理
if(counter > 30)//高电平大于30us,认为是1
{
DHT_DATA[bit / 8] |= 1;
}
bit++;
}
}
if(bit < 40)//检测是否收到40位数据
{
return ret = 2;
os_printf("读取失败\n");
}
//进行校验
check = (DHT_DATA[0] + DHT_DATA[1] + DHT_DATA[2] + DHT_DATA[3]);// & 0xFF
if(DHT_DATA[4] != check)
{
return ret = 3;
}
tem = (uint8)DHT_DATA[2];
hum = (uint8)DHT_DATA[0];
return ret = 3;
}
效果显示:
希望各位前辈大佬,多多指正。