STM32学习笔记【38.DHT11实验】

📅 2026/7/16 3:49:14
STM32学习笔记【38.DHT11实验】
文章目录模块介绍DHT11温湿度传感器1. DHT11介绍1.1 DHT11型号介绍1.2 DHT11工作参数及引脚介绍2. DHT11工作原理2.1 正常工作验证2.2 DHT11工作时序【与I2C类似】2.2.1 DHT11整体工作时序2.2.2 DHT11起始【复位】及响应信号2.2.3 读时序2.3 DHT11数据格式3. DHT11编程实战1. 搭建框架2. 填写输入输出口函数内容3. 起始信号4. 读取一个字节和所有数据的函数5. 主函数6. 代码展示7. 实验结果模块介绍DHT11温湿度传感器生活中经常使用温湿度数据比如天气预报、智能家居、智能大屏等等。这些数据可以通过温湿度传感器进行获取。在嵌入式开发中温湿度传感器是一种十分常用的传感器。1. DHT11介绍DHT11数字温湿度传感器为3或4针单排引脚封装连接方便。具有品质卓越、超快响应、抗干扰能力强、性价比高、超小体积、极低功耗的优点使其称为在测温、测湿应用在苛刻应用场合的不错选择。DHT11内置一个电阻式感湿元件和一个NTC测温元件并与一个单片机相连接DHT11内部。每个DHT11都在极为精确的湿度校验室中进行校准校准系数以程序的形式存在传感器中传感器内部在检测信号的处理过程中要调用这些校准系数。DHT11采用简易快捷的单线制串行接收方便系统集成。1.1 DHT11型号介绍DHT11有3脚和4脚两款在使用上没有差别接线都一样主要接三根四脚的款式有一脚悬空。四脚款接杜邦线会有点不稳只能插面包板上建议直接买三脚的。同样可以测量温湿度的还有DHT20、DHT22等都是大同小异。DHT11虽然可以同时测量温湿度但是测量范围没有专业测温传感器范围大。比如DS18B20专业测量温度的温度范围是-55℃~-125℃而DHT11只有0 ~ 50 ℃。1.2 DHT11工作参数及引脚介绍DHT11工作参数湿度测量范围20 ~ 90%RH湿度测量精度±5%RH温度测量范围0 ~ 50℃温度测量精度±2℃工作电压 DC 3.3V/5V接线如下正负极如果接反会烧坏传感器DHT11STM32VCC3.3V/5VDATA任意一个GPIO口GNDGNDDHT11采用单总线协议也就是使用一根DATA线进行数据的收发。DHT11的DATA线一次通讯时间4ms左右数据分整数部分、小数部分和校验位具体为8bit湿度整数数据 8bit温度小数数据 8bit校验位。2. DHT11工作原理2.1 正常工作验证上电后【电源指示灯/POWER】红灯亮表示上电成功正常工作。2.2 DHT11工作时序【与I2C类似】2.2.1 DHT11整体工作时序DHT11整体工作时序为主机发送开始信号、DHT11响应输出、主机输出40bit数据湿度数据温度数据校验值结束信号可选。具体过程如下总线空闲状态为高电平主机拉低总线等待DHT11响应主机把总线拉低必须大于18ms保证DHT11能检测到起始信号主机发送开始信号结束后拉高总线电平并延时等待20 ~ 40us后读取DHT11的响应信号DHT11接收到主机的开始信号后等待微处理器开始信号结束发送80us低电平响应信号DHT11发送80us高电平准备发送数据DHT11发送40bit数据湿度数据温度数据校验值2.2.2 DHT11起始【复位】及响应信号首先主机拉低总线至少18ms然后再拉高总线延时20 ~ 40us此时起始信号有时也叫复位信号发送完毕。DHT11检测到复位信号触发一次采样并拉低总线80us表示响应信号告诉主机数据已经准备好了。DHT11之后拉高总线80us然后开始传输数据。如果检测到响应信号为高电平则DHT11初始化失败请检查线路是否连接正常。2.2.3 读时序DHT11开始传输数据。每1 bit数据都以50us低电平开始告诉主机开始传输一位数据了。DHT11以高电平的长短定义数据位是0还是1当50us低电平过后拉高总线高电平持续26 ~ 28us表示0高电平持续70us表示数据1。当最后1 bit数据传送完毕后DHT11拉低总线50us表示数据传输完毕随后总线由上拉电阻拉高进入空闲状态。位数据0表示方式以50us低电平开始高电平持续26 ~ 28 us表示0。位数据1表示方式以50us低电平开始高电平程序70us表示1。50us时是低电平图中画的不太准。2.3 DHT11数据格式DHT11的DATA传输一次完整的数据为40bit按照高位在前低位在后的顺序传输。数据格式为8bit湿度整数数据 8bit湿度小数数据 8bit温度整数数据 8bit温度小数数据 8bit校验位一共5字节40bit数据。校验位 前面几个bit数据加起来放到校验位。正常情况下前四个字节的和刚好与校验位相等通过这种机制可以保证数据传输的准确性。判断如果前面几个bit数据加起来等于校验位说明数据传输正确。3. DHT11编程实战1. 搭建框架在串口打印功能实验基础上做在BSP文件夹下建立dht11文件夹以及.c和.h文件将dht11文件加载进来以及头文件加载。DHT11无初始化函数因为DHT11只有一个IO口既要作为输入口也要作为输出口dht11.c// 配置输入口voiddht11_gpio_input(void){}// 配置输出口voiddht11_gpio_output(void){}// 时序起始信号voiddht11_start(void){}// 读数据, 读一个字节uint8_tdht11_read_byte(void){}// 触发一次转换读取所有数据voiddht11_read(uint8_t*result){}dht11.h#defineDHT11_PORTGPIOA#defineDHT11_PINGPIO_PIN_5#defineDHT11_CLK_ENABLE()__HAL_RCC_GPIOA_CLK_ENABLE()#defineDHT11_DQ_OUT(x)do{x?\HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_SET):\HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_RESET);\}while(0)#defineDHT11_DQ_INHAL_GPIO_ReadPin(DHT11_PORT,DHT11_PIN)2. 填写输入输出口函数内容// 配置输入口voiddht11_gpio_input(void){// 打开时钟DHT11_CLK_ENABLE();引脚FHT11_PIN 模式是输入 无上拉或下拉 高速HAL_GPIO_Init(DHT11_PORT,gpio_initstruct);}// 配置输出口voiddht11_gpio_output(void){// 打开时钟DHT11_CLK_ENABLE();引脚DHT11_PIN 模式是推挽输出 无上拉或下拉 高速HAL_GPIO_Init(DHT11_PORT,gpio_initstruct);}3. 起始信号voiddht11_start(void){dht11_gpio_output();//引脚为输出模式DHT11_DQ_OUT(1/0);//表示高低电平先是高电平 拉低delay_ms(20);// 拉低至少18ms拉高但不用管20~40us// 主机拉高等待从机主动权交给从机dht11_gpio_input();// 输入模式// 等待dht11总线拉低电平while(DHT11_DQ_IN);// 等待DHT11拉高电平while(!DHT11_DQ_IN);// 等待dht11总线拉低电平while(DHT11_DQ_IN);}4. 读取一个字节和所有数据的函数逻辑上数据0从高电平拉低50us再拉高26 ~ 28 us数据1从高电平拉低50us再拉高70 us等待上升沿之后再等待50us判断是数据0还是150us是高电平表示数据1如果是低电平表示数据0chardht11_data[5]{0};uint8_tdht11_read_byte(void){uint8_ttemp0;uint8_ti0;// 定义一个数据将8位保存起来uint8_tread_data0;for(i0;i8;i){// 一个字节是8位读8次while(!DHT11_DQ_IN);delay_us(50);if(DHT11_DQ_IN1){temp1;while(DHT11_DQ_IN);}elsetemp0;// 先移位再把读到的数据插进去read_dataread_data1;read_data|temp;}returnread_data;}voiddht11_read(uint8_t*result){uint8_ti0;// 1.起始响应信号dht11_start();// 2.读数据输入模式// 3. 循环读入5个数据,40bit数据for(i0;i5;i)dht11_data[i]dht11_read_byte();// 校验读出数据是否准确if(dht11_data[0]dht11_data[1]dht11_data[2]dht11_data[3]dht11_data[4]){// 将4个字节拷贝到resultmemcpy(result,dht11_data,4);printf(湿度%d.%dRH,,dht11_data[0],dht11_data[1]);printf(温度%d.%d℃,,dht11_data[2],dht11_data[3]);}delay_ms(2000);}5. 主函数main.cuint8_tdht11_result[4];while(1){// 为了避免数据冲突数据要清空memset(dht11_result,0,4);dht11_read(dht11_result);}6. 代码展示dht11.c#includedht11.h#includedelay.h#includestring.h#includestdio.hchardht11_data[5]{0};voiddht11_gpio_input(void){GPIO_InitTypeDef gpio_initstruct;// 打开时钟DHT11_CLK_ENABLE();// 调用GPIO初始化函数gpio_initstruct.PinDHT11_PIN;gpio_initstruct.ModeGPIO_MODE_INPUT;gpio_initstruct.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(DHT11_PORT,gpio_initstruct);}voiddht11_gpio_output(void){GPIO_InitTypeDef gpio_initstruct;// 打开时钟DHT11_CLK_ENABLE();// 调用GPIO初始化函数gpio_initstruct.PinDHT11_PIN;gpio_initstruct.ModeGPIO_MODE_OUTPUT_PP;gpio_initstruct.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(DHT11_PORT,gpio_initstruct);}// 起始及响应信号voiddht11_start(void){dht11_gpio_output();DHT11_DQ_OUT(1);DHT11_DQ_OUT(0);delay_ms(20);DHT11_DQ_OUT(1);// 响应信号等待拉高/拉低dht11_gpio_input();// 输入模式while(DHT11_DQ_IN);// 等待DHT11拉低电平while(!DHT11_DQ_IN);// 等待DHT11拉高电平while(DHT11_DQ_IN);// 等待DHT11总线拉低电平}// 读时序[读取每个字节]uint8_tdht11_read_byte(void){uint8_ttemp0;uint8_ti0;// 定义一个数据将8位保存起来uint8_tread_data0;// 读时序读数据for(i0;i8;i){while(!DHT11_DQ_IN);// 期待变成上升沿delay_us(50);if(DHT11_DQ_IN1)// 如果是高电平1{temp1;// 数据1while(DHT11_DQ_IN);// 50us后等待下降沿拉低电平}elsetemp0;// 先移位再把读到的数据插进去read_dataread_data1;// 左移1位右边空出1位read_data|temp;}returnread_data;}// 读取每个数据,要有返回值接收voiddht11_read(uint8_t*result){uint8_ti0;// 1. 起始响应信号dht11_start();// 2. 读数据输入模式dht11_gpio_input();// 3. 循环读入5个数据40bit数据for(i0;i5;i)dht11_data[i]dht11_read_byte();// 校验读出数据是否准确if(dht11_data[0]dht11_data[1]dht11_data[2]dht11_data[3]dht11_data[4]){// 将4个字节拷贝到resultmemcpy(result,dht11_data,4);printf(湿度%d.%dRH,,dht11_data[0],dht11_data[1]);printf(温度%d.%d℃,,dht11_data[2],dht11_data[3]);}delay_ms(2000);}dht11.h#ifndef__DHT11_H__#define__DHT11_H__#includesys.h#defineDHT11_PORTGPIOA#defineDHT11_PINGPIO_PIN_5#defineDHT11_CLK_ENABLE()__HAL_RCC_GPIOA_CLK_ENABLE()// 输出口IO口拉高拉低#defineDHT11_DQ_OUT(x)do{x?\HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_SET):\HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_RESET);\}while(0)// 输入口#defineDHT11_DQ_INHAL_GPIO_ReadPin(DHT11_PORT,DHT11_PIN)voiddht11_read(uint8_t*result);#endifmain.c#includesys.h#includedelay.h#includeled.h#includeuart1.h#includedht11.h#includestring.huint8_ti0;intmain(void){HAL_Init();/* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);/* 设置时钟, 72Mhz */led_init();uart1_init(115200);printf(hello world! \r\n);uint8_tdht11_result[4];while(1){// 为了避免数据冲突数据要清空memset(dht11_result,0,4);dht11_read(dht11_result);}}7. 实验结果如果用手捂住DHT11传感器温湿度会变化。