STM32操纵DHT11湿度传感器

网上的例子不是说不能用,而是各种坑爹引用,搞得想移植都要改半天。现贴出一份经过Sandeepin精心整理的、清晰明了的代码供大家直观学习。

其实DHT11传感器不仅可测湿度,温度也能测,所以代码中包括了两种数据。

不多废话,直接上代码:

#include "stm32f10x.h"

#include "stdio.h"



#define HIGH  1

#define LOW   0

#define DHT11_CLK     RCC_APB2Periph_GPIOC

#define DHT11_PIN     GPIO_Pin_2

#define DHT11_PORT    GPIOC

#define DHT11_DATA_IN()   GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2) //读取引脚的电平

//带参宏,可以像内联函数一样使用,输出高电平或低电平

#define DHT11_DATA_OUT(a)  if (a)  \

                    GPIO_SetBits(GPIOC,GPIO_Pin_2);\

                    else        \

                    GPIO_ResetBits(GPIOC,GPIO_Pin_2)

        

u32 TimingDelay;



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;



void Delay_us(u32 ntimes)

{

    u32 flag;

    SysTick->LOAD=9*ntimes; //时间加载

    SysTick->VAL=0; //清空计数器

    SysTick->CTRL=0x00000001; //bit2清空,选择外部时钟HCLK/8, bit0位清空,开启倒计时

    do

    {

        flag=SysTick->CTRL;

    }

    while(flag&0x01&&!(flag&(1<<16)));//等待时间到达 

    SysTick->CTRL=0;//关闭计数器

}



int fputc(int ch, FILE *f)//重定向c库函数printf到USART1

{

    USART_SendData(USART1, (unsigned char) ch);//将Printf内容发往串口

    while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);

    return (ch);

}



void USART1_Config(unsigned int bound)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = bound;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    USART_InitStructure.USART_StopBits = USART_StopBits_1;

    USART_InitStructure.USART_Parity = USART_Parity_No;

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART1, &USART_InitStructure);

    USART_Cmd(USART1, ENABLE);

}



void DHT11_GPIO_Config(void)//DHT11的GPIO配置

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(DHT11_CLK, ENABLE);

    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);

    GPIO_ResetBits(DHT11_PORT, GPIO_Pin_2);  

}



static void DHT11_Mode_IPU(void)//使DHT11-DATA引脚变为上拉输入模式

{

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);

}



static void DHT11_Mode_Out_PP(void)//使DHT11-DATA引脚变为推挽输出模式

{

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);

}



static uint8_t Read_Byte(void)//从DHT11读取一个字节,MSB先行

{

    uint8_t i, temp=0;

    for(i=0;i<8;i++)    

    {

        while(DHT11_DATA_IN()==Bit_RESET);//每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束

        //DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,

        //通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时

        Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可

        if(DHT11_DATA_IN()==Bit_SET)// x us后仍为高电平表示数据“1”

        {

            while(DHT11_DATA_IN()==Bit_SET);//等待数据1的高电平结束

            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;

}



uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)//一次完整的数据传输为40bit,高位先出,8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和

{ 

    DHT11_Mode_Out_PP();

    

    DHT11_DATA_OUT(LOW);//主机拉低

    Delay_us(18000);//延时18ms

    DHT11_DATA_OUT(HIGH); //总线拉高 主机延时30us

    Delay_us(30);   //延时30us

    DHT11_Mode_IPU();//主机设为输入 判断从机响应信号

    if(DHT11_DATA_IN()==Bit_RESET)//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行

    {

        while(DHT11_DATA_IN()==Bit_RESET);//轮询直到从机发出 的80us 低电平响应信号结束

        while(DHT11_DATA_IN()==Bit_SET);//轮询直到从机发出的 80us 高电平 标置信号结束

        DHT11_Data->humi_int= Read_Byte();//开始接收数据

        DHT11_Data->humi_deci= Read_Byte();

        DHT11_Data->temp_int= Read_Byte();

        DHT11_Data->temp_deci= Read_Byte();

        DHT11_Data->check_sum= Read_Byte();

        DHT11_Mode_Out_PP();//读取结束,引脚改为输出模式

        DHT11_DATA_OUT(HIGH);//主机拉高

        //检查读取的数据是否正确

        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;

    }   

}



DHT11_Data_TypeDef DHT11_Data;

int main(void)

{

    USART1_Config(9600);

    DHT11_GPIO_Config();

    while(1){//调用Read_DHT11读取温湿度,若成功则输出该信息

        if( Read_DHT11(&DHT11_Data)==SUCCESS)

        {

            printf("Relative Humidity: %d.%d  Temperature: %d.%d \r\n",\

                DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);

            Delay_us(500000);

        }

        else

        {

            printf("Read DHT11 ERROR! \r\n");

            Delay_us(500000);

        }

    }

}

实现效果:在PC2接湿度传感器,通过串口1打印出湿度值、温度值。