找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 472|回复: 10
打印 上一主题 下一主题
收起左侧

求助:dht11温湿度检测器一直检测不到温湿度

[复制链接]
回帖奖励 2 黑币 回复本帖可获得 2 黑币奖励! 每人限 1 次(中奖概率 50%)
跳转到指定楼层
楼主
dht11.h
#ifndef __DHT11_H
#define __DHT11_H

#include "stm32f10x.h"

#define DHT11_GPIO_PORT       GPIOC
#define DHT11_GPIO_CLK        RCC_APB2Periph_GPIOC
#define DHT11_GPIO_PIN        GPIO_Pin_15

#define DHT11_OUT_H           GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN)
#define DHT11_OUT_L           GPIO_ResetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN)
#define DHT11_IN              GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN)

void DHT11_Init(void);
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity);
uint8_t DHT11_Read_Byte(void);

#endif

dht11.c
#include "dht11.h"
#include "Delay.h"

void DHT11_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
   
    RCC_APB2PeriphClockCmd(DHT11_GPIO_CLK, ENABLE);
   
    GPIO_InitStructure.GPIO_Pin = DHT11_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStructure);
   
    DHT11_OUT_H;
}

uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity)
{
    uint8_t buf[5];
    uint8_t i;
   
    DHT11_OUT_L;
    Delay_ms(18);
    DHT11_OUT_H;
    Delay_us(30);
   
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DHT11_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStructure);
   
    if(DHT11_IN == 0)
    {
        while(!DHT11_IN);
        while(DHT11_IN);
        
        for(i=0; i<5; i++)
        {
            buf[i ] = DHT11_Read_Byte();
        }
        
        while(DHT11_IN == 0);
        
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStructure);
        DHT11_OUT_H;
        
        if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4])
        {
            *humidity = buf[0];
            *temperature = buf[2];
            return 1;
        }
    }
   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStructure);
    DHT11_OUT_H;
    return 0;
}

uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, temp = 0;
   
    for(i=0; i<8; i++)
    {
        while(!DHT11_IN);
        Delay_us(40);
        
        if(DHT11_IN == 1)
        {
            while(DHT11_IN);
            temp |= (1 << (7-i));
        }
        else
        {
            temp &= ~(1 << (7-i));
        }
    }
    return temp;
}

main.c
#include "stm32f10x.h"
#include "stdio.h"
#include "led.h"
#include "key.h"
#include "LCD1602.h"
#include "tim.h"
#include "delay.h"
#include "dht11.h"
#include "buzzer.h"
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "stm32f1xx_hal_msp.h"

// 全局变量
int time_able=0;          // 系统总控制,0-停止 1-运行
int time_set = 10;        // 倒计时默认设定值(秒)
int time_ing_down = 10;    // 倒计时剩余值(秒)
int time_ing_up = 0;      // 正计时累计值(秒)
int time_lms = 0;         // 毫秒累计,1ms+1次
int time_led = 0;         // LED闪烁定时(毫秒)
int up_run_flag = 0;      // 正计时启停标志,0-停止 1-运行
int down_run_flag = 0;    // 倒计时启停标志,0-停止 1-运行

// 温湿度相关变量
u8 temperature = 0;                 // 温度值(℃)
u8 humidity = 0;                    // 湿度值(%)
u32 dht11_read_timer = 0;           // DHT11读取计时器(1ms递增)
u32 dht11_last_read_time = 0;       // 上次读取DHT11的时间戳
char display_buffer[17];            // 显示缓冲区

// 中断测试变量
volatile u32 interrupt_count = 0;  // 中断计数器

// LED和蜂鸣器控制变量
volatile u32 alarm_countdown = 0;  // 蜂鸣器倒计时
volatile u8 alarm_triggered = 0;   // 蜂鸣器触发标志

// 按键3相关变量
volatile u8 key3_pressed = 0;       // 按键3按下标志
volatile u32 key3_hold_time = 0;     // 按键3按住时间(ms)
volatile u32 key3_last_change = 0;   // 上次改变倒计时值的时间(ms)

// 定时器2中断服务函数,1ms执行一次
void TIM2_IRQHandler(void)
{
    // 清除并检查定时器2更新中断标志,继续
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
        time_lms++;
        dht11_read_timer++;  // DHT11读取计时器累加
        interrupt_count++;   // 中断计数器累加
        // 系统总控制启动时的计时逻辑
        if(time_able == 1)
        {
            // ---------------- 倒计时逻辑 ----------------
            if(down_run_flag == 1 && time_ing_down > 0)
            {
                if(time_lms >= 10) // 累计1000ms=1秒
                {
                    time_lms = 0;
                    time_ing_down--;
                    // 倒计时结束,启动LED和蜂鸣器提醒
                    if(time_ing_down == 0)
                    {
                        time_led = 10; // LED亮100ms(0.1秒)
                        alarm_triggered = 1; // 触发蜂鸣器标志
                        alarm_countdown = 14; // 蜂鸣器响1.4秒(3次)
                        down_run_flag = 0; // 倒计时停止
                        time_ing_down=10;
                    }
                }
            }
                                                         

            // ---------------- 正计时逻辑 ----------------
            if(up_run_flag == 1)
            {
                if(time_lms >= 10) // 累计1000ms=1秒
                {
                    time_lms = 0;
                    time_ing_up++;
                    if(time_ing_up >= 10) time_ing_up = 99; // 上限保护
                }
            }
        }
        else
        {
            // 系统停止时,毫秒计数器清零,防止残留
            time_lms = 0;
                                          up_run_flag = 0;
            down_run_flag = 0;
            time_ing_up = 0;
            time_ing_down = 10;
            time_led = 0;
            LED_OFF();
        }

        // LED闪烁逻辑
        if(time_led > 0)
        {
            LED_ON();  // time_led>0时LED亮
            time_led--;
        }
        else
        {
            LED_OFF(); // time_led=0时LED灭
        }

        // 蜂鸣器提醒逻辑(非阻塞)
        if(alarm_countdown > 0)
        {
            alarm_countdown--;
            // 每40ms为一个周期:前20ms响,后20ms停
            if(alarm_countdown % 4 < 2)
            {
                BUZZER_ON();
            }
            else
            {
                BUZZER_OFF();
            }
        }
        else
        {
            BUZZER_OFF();
            // 重置标志
            if(time_led == 0)
            {
                alarm_triggered = 0;
            }
        }

        // 清除中断标志,继续
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

int main(void)
{

    // 外设初始化
    delay_init();              // 延时函数初始化
    KEY_Init();                // 按键初始化
    LED_Init();                // LED初始化
    Buzzer_Init();             // 蜂鸣器初始化
    LCD_init();                // LCD初始化
    DHT11_Init();              // DHT11初始化
    tim2_init(100, 7200-1);       // 定时器2初始化,1ms中断

    // LCD初始化显示
    LCD1602_showstring(0, 1, "T:00 C H:00 %");  // 第一行:温湿度
    LCD1602_showstring(0, 0, "UP:000s DN:010s"); // 第二行:计时

    while (1)
    {
        // ---------------- 按键处理逻辑 ----------------
        // 按键1:系统全局启停控制,启停
        if(KEY1 == 0)
        {
            Delay_ms(20); // 消抖
            if(KEY1 == 0)
            {
                time_able = !time_able; // 切换启停状态
                if(time_able == 0) // 停止时,清零所有状态
                {
                    up_run_flag = 0;
                    down_run_flag = 0;
                    time_ing_up = 0;
                    time_ing_down = 10;
                    time_led = 0;
                    LED_OFF();
                }
                while(KEY1 == 0); // 等待按键释放
            }
        }

        // 按键2:正计时启停,系统运行时才有效
        if(KEY2 == 0 && time_able == 1)
        {
            Delay_ms(20); // 消抖
            if(KEY2 == 0)
            {
                up_run_flag = !up_run_flag; // 切换正计时启停
                if(up_run_flag == 1 && time_ing_up == 0)
                {
                    time_ing_up = 0; // 正计时重置为0
                }
                while(KEY2 == 0); // 等待按键释放
            }
        }

        // 按键3:长按调节倒计时时间,松开开始倒计时,系统运行时才有效
        if(KEY3 == 0 && time_able == 1)
        {
            Delay_ms(20); // 消抖
            if(KEY3 == 0)
            {
                if(key3_pressed == 0) // 刚按下
                {
                    key3_pressed = 1;
                    key3_hold_time = 0;
                    key3_last_change = 0;
                    down_run_flag = 0; // 暂停倒计时
                }
            }
        }

        // 按键3处理逻辑
        if(key3_pressed == 1)
        {
            // 在主循环中按键按住时间每10ms增加一次
            key3_hold_time += 10;

            // 长按每秒增加倒计时时间
            if(key3_hold_time - key3_last_change >= 100) // 每秒增加
            {
                key3_last_change = key3_hold_time;
                time_set++;
                if(time_set > 99) time_set = 99; // 上限999秒
                time_ing_down = time_set; // 更新显示值
            }

            // 按键释放检测
            if(KEY3 == 1)
            {
                if(key3_hold_time < 50) // 短按(小于500ms)
                {
                    // 如果倒计时正在运行,则暂停;如果暂停,则开始
                    if(down_run_flag == 1)
                    {
                        down_run_flag = 0; // 暂停倒计时
                    }
                    else
                    {
                        down_run_flag = 1; // 开始倒计时
                        time_ing_down = time_set; // 使用当前设定值
                    }
                }
                else // 长按(大于500ms),松开开始倒计时
                {
                    down_run_flag = 1; // 开始倒计时
                    time_ing_down = time_set; // 使用当前设定值
                }

                // 重置按键状态
                key3_pressed = 0;
                key3_hold_time = 0;
                key3_last_change = 0;
            }
        }


        // ---------------- LCD显示逻辑 ----------------
        if(time_able == 1)
        {
            // 正计时显示,第一行,列3
            LCD1602_shownum(3, 0, time_ing_up, 3);
            // 倒计时显示,第一行,列11
            LCD1602_shownum(11, 0, time_ing_down, 3);
        }

        // ---------------- DHT11温湿度读取逻辑(每2秒读取一次)----------------
        if(dht11_read_timer - dht11_last_read_time >= 20) // 2000ms = 2秒
        {
            dht11_last_read_time = dht11_read_timer;
            u8 temp, humi;
            if(DHT11_Read_Data(&temp, &humi)) // 读取成功
            {
                temperature = temp;
                humidity = humi;
                // 使用sprintf格式化显示字符串
             //   sprintf(display_buffer, "T:%2dC H:%2d%%", temperature, humidity);
             //   LCD1602_showstring(0, 1, display_buffer);
                                                          LCD1602_shownum(2, 1, temperature, 2);
                                              LCD1602_shownum(8, 1, humidity, 2);
            }
            // 如果读取失败,保留上次的值,不更新显示
        }
        // 同时在time_able==1时也更新温湿度显示(确保显示不消失)
        if(time_able == 1)
        {
          //  sprintf(display_buffer, "T:%2dC H:%2d%%", temperature, humidity);
          //  LCD1602_showstring(0, 1, display_buffer);
                                          LCD1602_shownum(2, 1, temperature, 2);
                                          LCD1602_shownum(9, 1, humidity, 2);
        }

        Delay_ms(5); // 减少CPU占用,提高响应速度

      
    }
}

屏幕截图 2025-12-25 213844.png (116.7 KB, 下载次数: 0)

屏幕截图 2025-12-25 213844.png

mmexport1766655304441.png (287.77 KB, 下载次数: 0)

mmexport1766655304441.png

01.7z

209.18 KB, 下载次数: 0

keil和proteus

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:584814 发表于 2025-12-26 12:09 | 只看该作者
本坛内搜索“DHT11 仿真”即可。
回复

使用道具 举报

板凳
ID:592807 发表于 2025-12-27 11:16 | 只看该作者
你怎么判断01数据,你说怎么判断uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, temp = 0;
   
    for(i=0; i<8; i++)
    {
        while(!DHT11_IN);
        Delay_us(40);
        
        if(DHT11_IN == 1)
        {
            while(DHT11_IN);
            temp |= (1 << (7-i));
        }
        else
        {
            temp &= ~(1 << (7-i));
        }
    }
    return temp;
}
回复

使用道具 举报

地板
ID:469589 发表于 2025-12-27 18:41 | 只看该作者
简单问题复杂化了,简单抄一个,一定好用,然后移植。
回复

使用道具 举报

5#
ID:349276 发表于 2025-12-28 09:39 来自触屏版 | 只看该作者
你仿真里,引脚都没有连上它
回复

使用道具 举报

6#
ID:1152570 发表于 2025-12-28 10:14 | 只看该作者
黄youhui 发表于 2025-12-27 11:16
你怎么判断01数据,你说怎么判断uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, temp = 0;

我不太懂欸,没怎么学明白
回复

使用道具 举报

7#
ID:1152570 发表于 2025-12-28 10:15 | 只看该作者
万家灯火51 发表于 2025-12-28 09:39
你仿真里,引脚都没有连上它

你指的是哪个引脚哇,PC15吗
回复

使用道具 举报

8#
ID:1152570 发表于 2025-12-28 10:15 | 只看该作者
GlenXu 发表于 2025-12-27 18:41
简单问题复杂化了,简单抄一个,一定好用,然后移植。

我试试,其实这个也是移植过来的
回复

使用道具 举报

9#
ID:1152570 发表于 2025-12-28 16:36 | 只看该作者
我又新找了一个代码实现了,谢谢大家啦
回复

使用道具 举报

10#
ID:469589 发表于 2025-12-29 09:03 | 只看该作者
滚雪球:
下作一个功能甚至一个I/O,不要直接做个系统。特别是不要从“通讯”开始。
有的专业认识很多年都没搞清楚怎么作通讯。通讯确实很简单,但不适合入手。
回复

使用道具 举报

11#
ID:1160531 发表于 2026-1-5 15:23 | 只看该作者
一般来说,多数不能正确读取数据的原因在于延时的准确性,这个需要先测试验证好,然后程序的控制逻辑方面,严格按照时序要求就行。换了个程序成功了,还是要认真分析下自己所遇问题的根本原因是什么,祝你不断进步。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表