STM32 DHT11温湿度检测模块输出一直为0,不清楚哪里有问题

stm32 dht11模块数据输出一直都是0,无论温度还是湿度
相关代码:

#include "stm32f4xx.h"
#include "sys.h"
#include 

static GPIO_InitTypeDef         GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;

struct __FILE { int handle; /* Add whatever you need here */ };//确保printf函数在串口中的可用
FILE __stdout;
FILE __stdin;

int fputc(int ch, FILE *f) 
{
    USART_SendData(USART1,ch);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);     //获取串口标志位数据,看缓冲区标志位是否为空。如果为空则会输出set,和reset不等,跳出while    
    return ch;
}


void delay_ms(uint32_t n)
{
    while(n--)                  //系统定时器有个最大定时时间不能超过(2^24-1)/168000000=99ms,超过99ms的话如果没有while运行不了
    {
        SysTick->CTRL = 0;         // Disable SysTick关闭系统定时器
        SysTick->LOAD = (168000)-1;         // 配置计数值,现在是1ms
        SysTick->VAL = 0;         // Clear current value as well as count flag,如果为0 ,则清零那个计数标志位,计数标志位为0则为还在计数当中
        SysTick->CTRL = 5;         // Enable SysTick timer with processor clock
        while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待countflag标志位置1,意思为计数结束
    }
    SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
}

void delay_us(uint32_t n)
{
        SysTick->CTRL = 0;         // Disable SysTick关闭系统定时器
        SysTick->LOAD = (168*n)-1;         // 配置计数值,现在是1ms
        SysTick->VAL = 0;         // Clear current value as well as count flag,如果为0 ,则清零那个计数标志位,计数标志位为0则为还在计数当中
        SysTick->CTRL = 5;         // Enable SysTick timer with processor clock
        while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待countflag标志位置1,意思为计数结束
        SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
}

void usart1_init(uint32_t baud)
{
    
    //打开pa硬件时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    //打开串口1硬件时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    //配置PA9和PA10为复用功能模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;  //9根引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能模式,该引脚交给其他硬件自动管理
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //决定io口响应速度,100mhz是高速响应
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //没有使能上下拉电阻
    
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //将PA9和PA10引脚连接到串口1的硬件
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
    
    //配置串口1相关参数:波特率、无校验位、8位数据位,1位停止位
    USART_InitStructure.USART_BaudRate = baud;                                    //配置波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //配置为8位数据位 
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                        //配置为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;                //配置为支持收(Rx)发(Tx)数据
    USART_Init(USART1, &USART_InitStructure);                                    //串口初始化
    
    //配置串口1的中断触发方法:接收一个字节触发中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    //配置串口1的中断优先级
     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;                    //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                            //响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    //使能串口1工作
    USART_Cmd(USART1, ENABLE);
}

void dht11_init(void)
{
    //端口B硬件时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
    
    //配置PB6为输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  //9根引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //决定io口响应速度,100mhz是高速响应
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //没有使能上下拉电阻
    GPIO_Init(GPIOG,&GPIO_InitStructure);
    
    //PG9初始状态为高电平,看时序图得知
    PGout(9)=1;
}

int32_t dht11_read (uint8_t *pbuf)  //看时序图
{
    uint32_t t=0;
    int32_t i=0,j=0;
    uint8_t d=0;
    uint8_t *p=pbuf;
    uint32_t check_sum;
    
    //PG9设置为输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  //9根引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //决定io口响应速度,100mhz是高速响应
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //没有使能上下拉电阻
    GPIO_Init(GPIOG,&GPIO_InitStructure);
    
    PGout(9)=0;
    delay_ms(20);
    
    PGout(9)=1;
    delay_us(30);
    
    //PG9设置为输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  //9根引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //复用功能模式,该引脚交给其他硬件自动管理
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //决定io口响应速度,100mhz是高速响应
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //没有使能上下拉电阻
    GPIO_Init(GPIOG,&GPIO_InitStructure);
    
    //等待低电平出现
    while(PGin(9))                //如果引脚一直字啊高电平,则报错,避免超时的情况
    {
        t++;
        delay_us(1);
        
        if(t>=4000)                //因为一次的通讯时间是4ms,如果超过了4ms还没有低电平出现的话,说明出现了错误
            return -1;
    }
    
    t=0;
    //测量低电平的合法性
    while(PGin(9)==0)                //使用超时方法进行测量 
    {
        t++;
        delay_us(1);
        
        if(t>=1000)                    //响应信号一般为80us,要设置大于80us
            return -2;
    }
    
    t=0;
    //测量高电平的合法性
    while(PGin(9))
    {
        t++;
        delay_us(1);
        
        if(t>=1000)
            return -3;
    }
    
    for(j=0;j<5;j++)        //(这里有5个数据,数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。)
    {
        d=0;
        //一个字节接收,从最高有效位进行接收
        for(i=7;i>=0;i--)        //i=7,i--是为了保证高位先出(一个数据有8个字节)
        {
            //等待温湿度数据0和数据1的前置低电平持续完毕
            t=0;
            //测量低电平的合法性
            while(PGin(9)==0)
            {
                t++;
                delay_us(1);
        
                if(t>=100)
                    return -4;
            }
        }
    
        //延迟40us
        delay_us(40);
    
        //判断当前pg9是否为高电平还是低电平
        //若是高电平,则为数据1;因为数据1的高电平持续时间是70us,所以延迟40us后还是高电平
        //若是低电平,则为数据0;因为数据0的高电平持续时间是26-28us,所以延迟40us后是低电平
        if(PGin(9))
        {
            PFout(9) =1;
            d|=1<//将变量d对应的比特位置1,如i=7,就是将变量d的bit7置1
            
            t=0;
            //等待高电平持续完毕
            while(PGin(9))
            {
                t++;
                delay_us(1);
        
                if(t>=100)
                    return -5;
            }
        }
        
        p[j]=d;
    }
    
    //判断检验和
    check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
    
    if(p[4]!=check_sum)
    {
        return -6;
    }
    
    return 0;
}



int main(void)
{
    int32_t rt=0;
    uint8_t    buf[5]={0};
    
    //使能端口F的硬件时钟,对F供电
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
    
        usart1_init(115200);
    
    //初始化gpio引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  //9根引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //决定io口响应速度,100mhz是高速响应
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //没有使能上下拉电阻
    
    GPIO_Init(GPIOF,&GPIO_InitStructure);
    
    //将PF9引脚连接到定时器14
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
    
    PFout(9) =1;
    
    //温湿度模块初始化
    dht11_init();
    
    
    while(1)
    {    
        //温湿度模块的数据读取
        rt =dht11_read(buf);
        
        if(rt==0)            //从dhtll_read那里获取的返回值,如果为0,则没有问题
        {
            printf("温度T:%d.%d,湿度:%d.%d\r\n",buf[2],buf[3],buf[0],buf[1]);
        }
        
        else
        {
            printf("dht11_read 's error code is    %d\r\n",rt);
        }
        
        delay_ms(6000);
    }
}

void USART1_IRQHandler(void)
{
    uint8_t d;
    
    //检测标志位
    if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
    {
        //接收数据
        d=USART_ReceiveData(USART1);
        
        
        
        //清空标志位
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
        
    }
    

}


输出结果

img

把GPIO配成上拉输入,如果浮空输入则在外部加10K上拉电阻。

这是传感器的时序图,

img


img

请问解决了吗,我也是一样的问题

你好,请问解决了嘛,我也遇到同样的问题了