使用DHT11获取环境温湿度
ESP32提供了RMT可用于读取红外脉冲,此外设也可用于DHT11这类单总线通信传感器,这里采用引脚模拟时序的方法读取数据。
DHT11简介
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。
我们直接移植正点原子的STM32例程
一、先了解DHT11的通信时序
◎单总线说明 DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏枀开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。 ◎单总线传送数据位定义 DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。 数据格式: 8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。 注:其中湿度小数部分为 0。 ◎校验位数据定义 “8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于所得结果的末 8 位。
注意:起始信号 微处理器把数据总线(SDA)拉低一段时间至少 18ms(最大不得超过 30ms),通知传感器准备数据。
注意DHT11的温湿度范围: DHT11: 测量范围:20-90% RH 0-50℃ 测湿精度:±5% RH 测温精度:±2℃ 其中湿度的小数位为0;
二、编写驱动
1.初始化、检查、复位
uint8_t DHT11_Init(void)
{
gpio_set_direction(DHT11_PIN_NUM, GPIO_MODE_OUTPUT);
gpio_set_pull_mode(DHT11_PIN_NUM, GPIO_PULLUP_ONLY);
gpio_set_level(DHT11_PIN_NUM, 1);
DHT11_Reset();
return DHT11_Check();
}
uint8_t DHT11_Check(void)
{
uint8_t retry = 0;
gpio_set_direction(DHT11_PIN_NUM, GPIO_MODE_INPUT);
while (gpio_get_level(DHT11_PIN_NUM) && retry < 100)
{
retry++;
usleep(1);
};
if (retry >= 100)
return 1;
else
retry = 0;
while (!gpio_get_level(DHT11_PIN_NUM) && retry < 100)
{
retry++;
usleep(1);
};
if (retry >= 100)
return 1;
return 0;
}
void DHT11_Reset(void)
{
gpio_set_direction(DHT11_PIN_NUM, GPIO_MODE_OUTPUT);
gpio_set_level(DHT11_PIN_NUM, 0);
vTaskDelay(20 / portTICK_RATE_MS);
gpio_set_level(DHT11_PIN_NUM, 1);
usleep(30);
}
2.读数据
uint8_t DHT11_ReadBit(void)
{
uint8_t retry = 0;
while (gpio_get_level(DHT11_PIN_NUM) && retry < 100)
{
retry++;
usleep(1);
}
retry = 0;
while (!gpio_get_level(DHT11_PIN_NUM) && retry < 100)
{
retry++;
usleep(1);
}
usleep(40);
if (gpio_get_level(DHT11_PIN_NUM))
return 1;
else
return 0;
}
uint8_t DHT11_ReadByte(void)
{
uint8_t i, dat;
dat = 0;
for (i = 0; i < 8; i++)
{
dat <<= 1;
dat |= DHT11_ReadBit();
}
return dat;
}
uint8_t DHT11_ReadData(void)
{
uint8_t buf[5];
DHT11_Reset();
if (DHT11_Check() == 0)
{
for (int i = 0; i < 5; i++)
{
buf[i] = DHT11_ReadByte();
}
if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
{
DHT11_Data.Humi_Int = buf[0];
DHT11_Data.Humi_Deci = buf[1];
DHT11_Data.Temp_Int = buf[2];
DHT11_Data.Temp_Deci = buf[3];
}
}
else
return 1;
return 0;
}
验证
我们使用LCD来显示所获取到的温度和湿度,顺便把ADC实验的数据也显示出来:
void app_main(void)
{
int read_raw;
BACK_COLOR = WHITE;
ESP_LOGI(TAG, "APP Start......");
ESP_ERROR_CHECK(nvs_flash_init());
Lcd_Init();
Lcd_Clear(WHITE);
ADC_Init();
DHT11_Init();
vTaskDelay(1000 / portTICK_RATE_MS);
Lcd_ShowString(10, 20, (uint8_t *)"Humi: ", 24, BLACK);
Lcd_ShowString(10, 50, (uint8_t *)"Temp: ", 24, BLACK);
Lcd_ShowString(10, 80, (uint8_t *)"Voltage: ", 24, BLACK);
Lcd_ShowChar(10 + 72 + 72, 20, '%', 24, BLACK);
Lcd_ShowChar(10 + 72 + 72, 50, 'C', 24, BLACK);
Lcd_ShowString(10 + 108 + 60, 80, (uint8_t *)"mV", 24, BLACK);
while (1)
{
DHT11_ReadData();
read_raw = adc1_get_raw(ADC_TEST_CHANNEL);
Lcd_ShowfloatNum(10 + 72, 20, DHT11_Data.Humi_Int, 4, 24, BLACK);
Lcd_ShowfloatNum(10 + 72, 50, DHT11_Data.Temp_Int + (float)DHT11_Data.Temp_Deci / 10, 4, 24, BLACK);
Lcd_ShowNum(10 + 108, 80, read_raw * 2600 / 8191, 4, 24, BLACK);
vTaskDelay(10 / portTICK_RATE_MS);
}
}
最后烧录验证:
|