STM32
直播中

申换换

8年用户 1563经验值
私信 关注
[问答]

如何去实现基于DHT11和DS18B20模块的显示实时温湿度报警设计呢

如何去实现基于DHT11和DS18B20模块的显示实时温湿度报警设计呢?

回帖(2)

李华

2021-11-25 14:54:02
功能介绍:


1、LED0约2秒一闪,表示程序运行中。
2、LCD和串口显示实时的温湿度,2秒一循环。上面一个temp是DS18B20,下面的是DHT11。%RH 相对湿度, CEL 摄氏度(ps:不接入DS18B20的话会循环等待)
3、按键都会翻转LED1,KEY1 开启报警模式,KEY0关闭报警模式。(按键10ms一巡检)
4、报警模式下:当温度不低于85摄氏度或者湿度不低于90%RH,蜂鸣器报警。可以通过按下KEY0关闭报警模式。(报警串口会有打印,LCD也会有提示)
接线

DS18B20

VCC -》 3.3V
DQ -》 PG11
GND -》 GN
DHT11
VCC -》 3.3V
DATA -》 PB10
GND -》 GND

效果图

普通环境

普通版main.c
升级版


哈热气

普通版

我这哈了3下




然后持续手扇风





ok,温湿度降下来了。
升级版






搓手捂热

手有汗,湿度也上来了




最后本来应该整个打火机的,可惜没有。夹咯吱窝下(仅DHT11 旧图)





最后来个鼻息





核心代码

普通版main.c


#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "bsp_dht11.h"
#include "ds18b20.h"


DHT11_Data_TypeDef DHT11_Data;


/*
        DS18B20
        供电电压:3 - 5.5V
        接线:DQ -》 PG11 (IO口)
       
        DHT11
        供电电压:3.3 - 5V
        接线:DATA -》 PB10 (IO口)
*/


int main(void)
{
        u8 str[100] = {0};
        // DS18B20用变量
        short temperature;
        delay_init();                     //延时函数初始化          
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        uart_init(115200);                 //串口初始化为115200
        LED_Init();                             //LED端口初始化
        LCD_Init();                                 // LCD初始化
        DHT11_GPIO_Config();     // 初始化DTT11的引脚 DATA -> PB10
        LED0 = 0;
        POINT_COLOR = WHITE;
        BACK_COLOR = BLACK;
        LCD_Clear(BLACK);
        while(DS18B20_Init())        //DS18B20初始化       
        {
                LCD_ShowString(10,70,200,16,16,"DS18B20 Error");
                delay_ms(200);
                LCD_Fill(10,70,239,130+16,WHITE);
                delay_ms(200);
        }
        LCD_ShowString(10,90,200,16,16,"Temp:   . CEL");
          while(1)
        {
                POINT_COLOR = WHITE;
               
                // DS18B20
                temperature = DS18B20_Get_Temp();       
                if(temperature < 0)
                {
                        LCD_ShowChar(10+40, 90, '-', 16, 0);                        //显示负号
                        temperature = -temperature;                                            //转为正数
                }else LCD_ShowChar(10+40,90,' ', 16, 0);                        //去掉负号
                LCD_ShowNum(10+40+8, 90, temperature/10, 2, 16);        //显示正数部分            
                LCD_ShowNum(10+40+32, 90,temperature%10, 1, 16);        //显示小数部分
                printf("温度为 %u.%u℃ rn",temperature/10, temperature%10);
               
                // DHT11
                // 调用Read_DHT11读取温湿度,若成功则输出该信息
                if( Read_DHT11(&DHT11_Data) == SUCCESS)
                {
                        printf("湿度为%d.%d %RH ,温度为 %d.%d℃ rn", DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci);
                        sprintf((char*)str, "HUM: %d.%d%%RH  ", DHT11_Data.humi_int, DHT11_Data.humi_deci);
                        LCD_ShowString(10,130,200,24,24, str);
                        sprintf((char*)str, "TEMP: %d.%dCEL ", DHT11_Data.temp_int, DHT11_Data.temp_deci);
                        LCD_ShowString(10,170,200,24,24, str);
                        //printf("rn 湿度:%d,温度:%d rn" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
                }
                else
                {
                        printf("Read DHT11 ERROR!rn");
                }
                LED0 = !LED0;
                // 采样周期不得低于1秒,否则会读取失败
                delay_ms(1000);
                delay_ms(1000);
        }
}




升级版main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "bsp_dht11.h"
#include "ds18b20.h"
#include "key.h"
#include "beep.h"


DHT11_Data_TypeDef DHT11_Data;


/*
        DS18B20
        供电电压:3 - 5.5V
        接线:DQ -》 PG11 (IO口)
       
        DHT11
        供电电压:3.3 - 5V
        接线:DATA -》 PB10 (IO口)
*/


int main(void)
{
        u8 str[100] = {0};
        // 蜂鸣器报警标志位
        u8 flag = 0;
        // 报警模式
        u8 mode = 0;
        vu8 key = 0;
        // 循环计数
        u8 time = 0;
        // DS18B20用变量
        short temperature;
        delay_init();                     //延时函数初始化          
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        uart_init(115200);                  //串口初始化为115200
        LED_Init();                             //LED端口初始化
        LCD_Init();                                 // LCD初始化
        KEY_Init();                                 // KEY初始化
        BEEP_Init();                         // BEEP初始化
        DHT11_GPIO_Config();     // 初始化DTT11的引脚 DATA -> PB10
        LED0 = 0;
        LED1 = 0;
        POINT_COLOR = WHITE;
        BACK_COLOR = BLACK;
        LCD_Clear(BLACK);
        while(DS18B20_Init())        //DS18B20初始化       
        {
                LCD_ShowString(10,70,200,16,16,"DS18B20 Error");
                delay_ms(200);
                LCD_Fill(10,70,239,130+16, BLACK);
                delay_ms(200);
        }
        LCD_ShowString(10,90,200,16,16,"Temp:   . CEL");
        LCD_ShowString(10,220,220,12,12,"TOUCH KEY0 CLOSE ALARM MODE");
        LCD_ShowString(10,240,220,12,12,"TOUCH KEY1 OPEN ALARM MODE");
        POINT_COLOR = RED;
        LCD_ShowString(10,260,100,12,12,"ALARM MODE: OFF");
        POINT_COLOR = WHITE;
          while(1)
        {
                flag = 2;
                POINT_COLOR = WHITE;
               
                key = KEY_Scan(0); //得到键值
                if (key)
                {
                        switch (key)
                        {
                                case WKUP_PRES:
                                        LED1 = !LED1;
                                        break;
                                // KEY1 按下 开启报警模式
                                case KEY1_PRES:
                                        mode = 1;
                                        LED1 = !LED1;
                                        LCD_ShowString(80,260,100,12,12,"ON  ");
                                        printf("开启报警模式rn");
                                        break;
                                // KEY1 按下 关闭报警模式
                                case KEY0_PRES:
                                        mode = 0;
                                        LED1 = !LED1;
                                        LCD_ShowString(80,260,100,12,12,"OFF ");
                                        printf("关闭报警模式rn");
                                        break;
                        }
                }
               
                // 约2秒一次
                if(time % 200 == 0)
                {
                        // DS18B20
                        temperature = DS18B20_Get_Temp();       
                        if(temperature < 0)
                        {
                                LCD_ShowChar(10+40, 90, '-', 16, 0);                        //显示负号
                                temperature = -temperature;                                            //转为正数
                        }else LCD_ShowChar(10+40,90,' ', 16, 0);                        //去掉负号
                        LCD_ShowNum(10+40+8, 90, temperature/10, 2, 16);        //显示正数部分            
                        LCD_ShowNum(10+40+32, 90,temperature%10, 1, 16);        //显示小数部分
                        printf("温度为 %u.%u℃ rn",temperature/10, temperature%10);
                       
                        // DHT11
                        // 调用Read_DHT11读取温湿度,若成功则输出该信息 采样周期不得低于1秒,否则会读取失败
                        if( Read_DHT11(&DHT11_Data) == SUCCESS)
                        {
                                printf("湿度为%d.%d %RH ,温度为 %d.%d℃ rn", DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci);
                                sprintf((char*)str, "HUM: %d.%d%%RH  ", DHT11_Data.humi_int, DHT11_Data.humi_deci);
                                LCD_ShowString(10,130,200,24,24, str);
                                sprintf((char*)str, "TEMP: %d.%dCEL ", DHT11_Data.temp_int, DHT11_Data.temp_deci);
                                LCD_ShowString(10,170,200,24,24, str);
                                //printf("rn 湿度:%d,温度:%d rn" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
                        }
                        else
                        {
                                printf("Read DHT11 ERROR!rn");
                        }
                       
                        // 判断温度是否不低于85摄氏度
                        if(temperature >= 850 || DHT11_Data.temp_int >= 85)
                        {
                                printf("温度过高!!!rn");
                                flag++;
                        }
                        else
                        {
                                flag--;
                        }
                       
                        // 判断湿度是否高于90%RH
                        if(DHT11_Data.humi_int >= 90)
                        {
                                printf("湿度过高!!!rn");
                                flag++;
                        }
                        else
                        {
                                flag--;
                        }
                       
                        // 判断是否需要报警
                        if(flag >= 2 && mode == 1)
                        {
                                LCD_ShowString(10,200,200,16,16,"BEEP!!!(>__<)");
                                printf("BEEP!!!(>__<)rn");
                                BEEP = 1;
                        }
                       
                        if(flag < 2)
                        {
                                LCD_ShowString(10,200,200,16,16,"     (- v -)    ");
                                BEEP = 0;
                        }
                       
                        // 重新置零
                        time = 0;
                       
                        LED0 = !LED0;
                }
               
                if(mode == 0)
                {
                        LCD_ShowString(10,200,200,16,16,"     (- v -)    ");
                        BEEP = 0;
                }
               
                time++;
                delay_ms(10);
        }
}


bsp_dht11.h
#ifndef __DHT11_H
#define        __DHT11_H


#include "stm32f10x.h"
#include "delay.h"


#define HIGH  1
#define LOW   0


#define DHT11_CLK     RCC_APB2Periph_GPIOB
#define DHT11_PIN     GPIO_Pin_10                  
#define DHT11_PORT                GPIOB


//带参宏,可以像内联函数一样使用,输出高电平或低电平
#define DHT11_DATA_OUT(a)        if (a)       
                                        GPIO_SetBits(GPIOB,GPIO_Pin_10);
                                        else               
                                        GPIO_ResetBits(GPIOB,GPIO_Pin_10)
//读取引脚的电平
#define  DHT11_DATA_IN()           GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)


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 DHT11_GPIO_Config(void);
static void DHT11_Mode_IPU(void);
static void DHT11_Mode_Out_PP(void);
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);
static uint8_t Read_Byte(void);


#endif /* __DHT11_H */


bsp_dht11.c
#include "bsp_dht11.h"


/*
* 函数名:DHT11_GPIO_Config
* 描述  :配置DHT11用到的I/O口
* 输入  :无
* 输出  :无
*/
void DHT11_GPIO_Config(void)
{               
        /*定义一个GPIO_InitTypeDef类型的结构体*/
        GPIO_InitTypeDef GPIO_InitStructure;


        /*开启DHT11_PORT的外设时钟*/
        RCC_APB2PeriphClockCmd(DHT11_CLK, ENABLE);


        /*选择要控制的DHT11_PORT引脚*/                                                                                                                          
          GPIO_InitStructure.GPIO_Pin = DHT11_PIN;       


        /*设置引脚模式为通用推挽输出*/
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   


        /*设置引脚速率为50MHz */   
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


        /*调用库函数,初始化DHT11_PORT*/
          GPIO_Init(DHT11_PORT, &GPIO_InitStructure);                  


        /* 拉高GPIOB10        */
        GPIO_SetBits(DHT11_PORT, GPIO_Pin_10);         
}


/*
* 函数名:DHT11_Mode_IPU
* 描述  :使DHT11-DATA引脚变为上拉输入模式
* 输入  :无
* 输出  :无
*/
static void DHT11_Mode_IPU(void)
{
          GPIO_InitTypeDef GPIO_InitStructure;


                  /*选择要控制的DHT11_PORT引脚*/       
          GPIO_InitStructure.GPIO_Pin = DHT11_PIN;


           /*设置引脚模式为浮空输入模式*/
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;


          /*调用库函数,初始化DHT11_PORT*/
          GPIO_Init(DHT11_PORT, &GPIO_InitStructure);         
}


/*
* 函数名:DHT11_Mode_Out_PP
* 描述  :使DHT11-DATA引脚变为推挽输出模式
* 输入  :无
* 输出  :无
*/
static void DHT11_Mode_Out_PP(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;


                 /*选择要控制的DHT11_PORT引脚*/                                                                                                                          
          GPIO_InitStructure.GPIO_Pin = DHT11_PIN;       


        /*设置引脚模式为通用推挽输出*/
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   


        /*设置引脚速率为50MHz */   
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


        /*调用库函数,初始化DHT11_PORT*/
          GPIO_Init(DHT11_PORT, &GPIO_InitStructure);                  
}


/*
* 从DHT11读取一个字节,MSB先行
*/
static uint8_t Read_Byte(void)
{
        uint8_t i, temp=0;


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


                /*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
                 *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
                 */
                delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可                     


                if(DHT11_DATA_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
                {
                        /* 等待数据1的高电平结束 */
                        while(DHT11_DATA_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 Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{  
        /*输出模式*/
        DHT11_Mode_Out_PP();
        /*主机拉低*/
        DHT11_DATA_OUT(LOW);
        /*延时18ms*/
        delay_ms(18);


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


        delay_us(30);   //延时30us


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


        /*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   
        if(DHT11_DATA_IN() == Bit_RESET)     
        {
                /*轮询直到从机发出 的80us 低电平 响应信号结束*/  
                while(DHT11_DATA_IN()==Bit_RESET);


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


                /*开始接收数据*/   
                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;
        }   
}
举报

李开心

2021-11-25 14:54:06
ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "sys.h"   
//         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//DS18B20驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved                                                                          
//


//IO方向设置
#define DS18B20_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
IO操作函数                                                                                          
#define        DS18B20_DQ_OUT PGout(11) //数据端口        PA0
#define        DS18B20_DQ_IN  PGin(11)  //数据端口        PA0
          
u8 DS18B20_Init(void);//初始化DS18B20
short DS18B20_Get_Temp(void);//获取温度
void DS18B20_Start(void);//开始温度转换
void DS18B20_Write_Byte(u8 dat);//写入一个字节
u8 DS18B20_Read_Byte(void);//读出一个字节
u8 DS18B20_Read_Bit(void);//读出一个位
u8 DS18B20_Check(void);//检测是否存在DS18B20
void DS18B20_Rst(void);//复位DS18B20   
#endif


ds18b20.c
#include "ds18b20.h"
#include "delay.h"       
//         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//DS18B20驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved                                                                          
//
  




//复位DS18B20
void DS18B20_Rst(void)          
{                 
        DS18B20_IO_OUT();         //SET PG11 OUTPUT
    DS18B20_DQ_OUT=0;         //拉低DQ
    delay_us(750);            //拉低750us
    DS18B20_DQ_OUT=1;         //DQ=1
        delay_us(15);             //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)           
{   
        u8 retry=0;
        DS18B20_IO_IN();        //SET PG11 INPUT         
    while (DS18B20_DQ_IN&&retry<200)
        {
                retry++;
                delay_us(1);
        };         
        if(retry>=200)return 1;
        else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
        {
                retry++;
                delay_us(1);
        };
        if(retry>=240)return 1;            
        return 0;
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void)          
{
    u8 data;
        DS18B20_IO_OUT();        //SET PG11 OUTPUT
    DS18B20_DQ_OUT=0;
        delay_us(2);
    DS18B20_DQ_OUT=1;
        DS18B20_IO_IN();        //SET PG11 INPUT
        delay_us(12);
        if(DS18B20_DQ_IN)data=1;
    else data=0;         
    delay_us(50);           
    return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)     
{        
    u8 i,j,dat;
    dat=0;
        for (i=1;i<=8;i++)
        {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }                                                    
    return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)     
{            
    u8 j;
    u8 testb;
        DS18B20_IO_OUT();        //SET PG11 OUTPUT;
    for (j=1;j<=8;j++)
        {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb)
        {
            DS18B20_DQ_OUT=0;        // Write 1
            delay_us(2);                           
            DS18B20_DQ_OUT=1;
            delay_us(60);            
        }
        else
        {
            DS18B20_DQ_OUT=0;        // Write 0
            delay_us(60);            
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}
//开始温度转换
void DS18B20_Start(void)
{                                                                 
    DS18B20_Rst();          
        DS18B20_Check();         
    DS18B20_Write_Byte(0xcc);        // skip rom
    DS18B20_Write_Byte(0x44);        // convert
}


//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在             
u8 DS18B20_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);         //使能PORTG口时钟
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                                //PORTG.11 推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                   
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOG, &GPIO_InitStructure);


        GPIO_SetBits(GPIOG,GPIO_Pin_11);    //输出1


        DS18B20_Rst();


        return DS18B20_Check();
}  
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
        short tem;
    DS18B20_Start ();                          // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();         
    DS18B20_Write_Byte(0xcc);        // skip rom
    DS18B20_Write_Byte(0xbe);        // convert            
    TL=DS18B20_Read_Byte();         // LSB   
    TH=DS18B20_Read_Byte();         // MSB  
                      
    if(TH>7)
    {
        TH=~TH;
        TL=~TL;
        temp=0;                                        //温度为负  
    }else temp=1;                                //温度为正                    
    tem=TH;                                         //获得高八位
    tem<<=8;   
    tem+=TL;                                        //获得底八位
    tem=(float)tem*0.625;                //转换     
        if(temp)return tem;                 //返回温度值
        else return -tem;   
}


参考用图

DHT11





















DS18B20























举报

更多回帖

发帖
×
20
完善资料,
赚取积分