1、使用方法
- 模块描述
- 原理图
- 引脚
- 串行接口
DATA引脚用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:
- 一次完整的数据传输为40bit,高位先出。
- 数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
- 数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。
- 通讯过程
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集,采集数据后转换到低速模式。
如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
- 通讯开始
总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号。主机发送开始信号结束后,延时等待20-40us后,读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。
- 数据0与数据1
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1。格式见下面图示。
数据0
数据1
2、代码
- dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
/************************** DHT11 数据类型定义********************************/
typedef struct
{
uint8_t humi_int; //湿度的整数部分
uint8_t humi_deci; //湿度的小数部分
uint8_t temp_int; //温度的整数部分
uint8_t temp_deci; //温度的小数部分
uint8_t check_sum; //校验和
} DHT11_Data_TypeDef;
/************************** DHT11 连接引脚定义********************************/
#define DHT11_Dout_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
#define DHT11_Dout_GPIO_CLK RCC_APB2Periph_GPIOE
#define DHT11_Dout_GPIO_PORT GPIOE
#define DHT11_Dout_GPIO_PIN GPIO_Pin_6
/************************** DHT11 函数宏定义********************************/
#define DHT11_Dout_0 GPIO_ResetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
#define DHT11_Dout_1 GPIO_SetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
#define DHT11_Dout_IN() GPIO_ReadInputDataBit(DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
/************************** DHT11 函数声明 ********************************/
void DHT11_Init( void );
uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef * DHT11_Data );
#endif /* __DHT11_H */
- dht11.c
#include "./dht11/bsp_dht11.h"
#include "./SysTick/bsp_SysTick.h"
//#include "./dht11/core_delay.h"
/* 可以在下面的宏定义中把后面的延时函数替换换SysTick的延时函数,就是想用那个就换成那个的 */
//#define DHT11_DELAY_US(us) CPU_TS_Tmr_Delay_US(us)
//#define DHT11_DELAY_MS(ms) CPU_TS_Tmr_Delay_MS(ms)
#define DHT11_DELAY_US(us) SysTick_Delay_Us(us)
#define DHT11_DELAY_MS(ms) SysTick_Delay_Ms(ms)
static void DHT11_GPIO_Config( void );
static void DHT11_Mode_IPU( void );
static void DHT11_Mode_Out_PP( void );
static uint8_t DHT11_ReadByte( void );
/**
* @brief DHT11 初始化函数
* @param 无
* @retval 无
*/
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
DHT11_Dout_1; // 拉高GPIOPE6
}
/*
* 函数名:DHT11_GPIO_Config
* 描述 :配置DHT11用到的I/O口
* 输入 :无
* 输出 :无
*/
static void DHT11_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启DHT11_Dout_GPIO_PORT的外设时钟*/
DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
}
/*
* 函数名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引脚变为上拉输入模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为上拉输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:DHT11_Mode_Out_PP
* 描述 :使DHT11-DATA引脚变为推挽输出模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 从DHT11读取一个字节,MSB先行
*/
static uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(DHT11_Dout_IN()==Bit_RESET);
/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
*/
DHT11_DELAY_US(40); //延时x us 这个延时需要大于数据0持续的时间即可
if(DHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
{
/* 等待数据1的高电平结束 */
while(DHT11_Dout_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}
else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
/*
* 一次完整的数据传输为40bit,高位先出
* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
DHT11_Dout_0;
/*延时18ms*/
DHT11_DELAY_MS(18);
/*总线拉高 主机延时30us*/
DHT11_Dout_1;
DHT11_DELAY_US(30); //延时30us
/*主机设为输入 判断从机响应信号*/
DHT11_Mode_IPU();
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(DHT11_Dout_IN()==Bit_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(DHT11_Dout_IN()==Bit_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(DHT11_Dout_IN()==Bit_SET);
/*开始接收数据*/
DHT11_Data->humi_int= DHT11_ReadByte();
DHT11_Data->humi_deci= DHT11_ReadByte();
DHT11_Data->temp_int= DHT11_ReadByte();
DHT11_Data->temp_deci= DHT11_ReadByte();
DHT11_Data->check_sum= DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_Dout_1;
/*检查读取的数据是否正确*/
if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
return ERROR;
}
/*************************************END OF FILE******************************/
- main.c
#include "stm32f10x.h"
#include "./systick/bsp_SysTick.h"
#include "./dht11/bsp_dht11.h"
#include "./usart/bsp_usart.h"
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
DHT11_Data_TypeDef DHT11_Data;
/* 初始化系统定时器 */
SysTick_Init();
USART_Config();//初始化串口1
printf("\r\n***野火STM32 dht11 温湿度传感器实验***\r\n");
/*初始化DTT11的引脚*/
DHT11_Init ();
while(1)
{
/*调用DHT11_Read_TempAndHumidity读取温湿度,若成功则输出该信息*/
if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS)
{
printf("\r\n读取DHT11成功!\r\n\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",\
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
else
{
printf("Read DHT11 ERROR!\r\n");
}
Delay_ms(2000);
}
}
/*********************************************END OF FILE**********************/
- 调试