文章目录
- DHT11模块简介
- DHT11数据传输
- DHT11通信时序
- 代码实现
- 相关引脚初始化
- 复位模块
- 判断响应模块
- 读取数据包模块
DHT11模块简介
DHT11数字温湿度传感器,用来测量环境的温度和湿度,而且传输的数据是数字信号,这与DS18B20传输的模拟采集的数据不一样,相比DS18B20而言DHT11的数据采集的处理更加精确,而且驱动也更加方便。
DHT11传感器包括一个电阻式测湿元件和一个NTC测温元件,而且传感器中嵌入一个8位单片机。传感元件测量到数据后经过内嵌MCU处理后,能够直接输出处理好的数据。
DHT11与单片机之间采用单总线通信,只需要初始化一个I/O口即可实现温湿度的实时测量。
其相关参数如下:
DHT11数据传输
DHT11数据传输是单总线通信方式,即通过一个IO口完成数据的双向输入输出,DHT11每一次向单片机传输数据是传输40Bit的数据包,40Bit的数据包中包含如下内容:
- (32-39)湿度的整数部分
- (24-31)湿度的小数部分
- (16-23)温度的整数部分
- (8-15)温度的小数部分
- (0-7)数据校验部分,前四部分的和
例如:
湿度为:45.0
温度为:28.0
校验为:73=45+28(数据正确)
DHT11通信时序
由于DHT11和单片机是单总线通信的,所以数据的双向传输就依靠严格的时序规定了,DHT11和单片机通信的时序有三部分:
- 单片机向DHT11发送复位信号
- DHT11响应单片机的信号
- DHT11向单片机传输数据包
总的时序图如示:
第一步:发送复位信号,此时引脚应模式为推挽输出。拉低数据线,持续t1(至少18ms)时间;然后拉高数据线,持续t2(20~40us)时间。
第二步:读取相应,此时引脚应模式为浮空输入。DHT11会先拉低数据线,持续t3(40~50us)时间,作为相应信号;然后DHT11拉高数据线,持续t4(40 ~50us)时间,开始传输数据包。
第三步:传输数据包。传输“1”时,12 ~14us低电平+116 ~118us高电平;传输“0”时,12 ~14us低电平+26 ~28us高电平。
这三步就完成了一次完整的数据传输,然后就单片机是对接收到的数据包进行处理显示就好了。
代码实现
驱动代码主要实现如下几个模块:
- 相关引脚初始化
- 复位模块
- 判断响应模块
- 读取数据包模块
- 显示模块
相关引脚初始化
由于是一个IO口,要满足输出和检测电平,所以我写了俩个函数来切换引脚的模式,可以使引脚在推挽输出和浮空输入之间切换:
/* 相关引脚的配置,DHT是单通道通信,所以一个引脚就够了 */
void DHT_GPIO_Config_Output( void )
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = DHT_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT_PORT, &GPIO_InitStruct);
}
/* 同一个引脚 要在输入和输出的时候进行切换引脚模式 */
void DHT_GPIO_Config_Input( void )
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = DHT_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT_PORT, &GPIO_InitStruct);
}
在初始化的时候会开启时钟,所以这俩个模块就不用开启时钟
复位模块
void DHT11_Rst( void )
{
DHT_GPIO_Config_Output();
DHT11_L;
Delay_ms( 20 );
DHT11_H;
Delay_us( 30 );
}
判断响应模块
uint8_t DHT11_Check( void )
{
uint8_t t;
/* 浮空输入,判断引脚输入电平 */
DHT_GPIO_Config_Input();
while( DHT11_Value_L && t<100 )
{
t++;
Delay_us(1);
}
if( t>100 ) return 1;
t=0;
while( DHT11_Value_H && t<100 )
{
t++;
Delay_us(1);
}
if( t>100 ) return 1;
return 0;
}
读取数据包模块
void DHT11_Read_Data( uint8_t *temp, uint8_t *humi )
{
uint8_t i,t;
uint9_t data[5];
DHT_GPIO_Config_Input();
/* 执行40次读取位数据,data指向数据包 */
for( i=0;i<40;i++ )
{
/* 开始低电平 */
while( DHT11_Value_L && t<100 )
{
t++;
Delay_us(1);
}
t=0;
/* 开始高电平 */
while( DHT11_Value_H && t<100 )
{
t++;
Delay_us(1);
}
Delay_us(40);
/* 判断高电平持续时间 */
if( DHT11_Value_H )
{
data[i/8] |= 0x01;
data[i/8] = data[i/8]<<(i%8);
}
else
data[i/8] = data[i/8]<<(i%8);
}
/* 将数据地址传出去 */
*humi = data[0];
*temp = data[2];
}