基于STM32的温湿度检监测报警系统


前言

  温度是一项非常重要的参数,无论是农业还是工业都要对温度进行监测。目前大部分温度监测还在使用传统的温度计进行温度测星,这种测量方式即浪费人力和时间还不能对温度进行实时监测。如果采用远程监控设备对温度进行实时监测将会大大减少人工成本,还会降低由温度骤变造成的损失。

(文末附完整程序下载链接)

一、设计任务

  1.可以通过温度传感器对环境温度进行采集,并用实时显示在LCD液晶屏上;
  2.可以设定一个固定的报警温度值显示在液晶屏上;
  3.环境温度超过报警温度后报警,报警形式包括:蜂鸣器声音响,LCD上显示的环境温度值显示红色;
  4.能够通过按键动态修改报警温度阈值;
  5.通过DS18B20数字温度传感器进行温度采集;

二、系统硬件设计

1.元器件选用

  1、STM32f103VET6单片机一块
  2、ESP8266一块
(此项目使用野火指南者,指南者自带ESP8266,其他型号单片机杜邦线自连即可)
  3、DHT11温湿度监测模块
  4、3.2寸LCD显示器(若无,传课输出部分信息,其他部分printf补全即可)
  5、杜邦线3根
连接WiFi、服务器
在这里插入图片描述

2.系统模型设计

  按键1设置温度阈值,按键2设置湿度阈值,DHT11监测温度和湿度的值。当检测的温度大于温度阈值时LCD显示警告、蜂鸣器报警、红灯闪烁、串口输出警告;当检测的湿度大于湿度阈值时LCD显示温度超出警告、蜂鸣器报警、蓝灯闪烁、串口输出湿度超出警告。
温度超出警告
湿度超出警告

3.硬件连接

  1、本系统使用野火指南者,由于该单片机自带ESP8266,因此无需连接。如果使用其他型号单片机,根据ESP8266用户手册连接即可。
  2、DHT11的VCC、GND连接单片机的+5V和GND,DHT11的DATA连接单片机PE6。

二、系统程序设计

1.程序流程

  用户使用按键设置温度阈值和湿度阈值,系统采集当前环境温度和湿度。系统将当前环境温湿度与温湿度阈值比较,当检测的温度大于温度阈值时,LCD显示警告、蜂鸣器报警、红灯闪烁、串口输出警告;当检测的湿度大于湿度阈值时LCD显示温度超出警告、蜂鸣器报警、蓝灯闪烁、串口输出湿度超出警告。
程序流程图

2.主程序

main.c

#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "./lcd/bsp_ili9341_lcd.h"
#include "bsp_usart.h"
#include "bsp_SysTick.h"
#include "bsp_esp8266.h"
#include "bsp_esp8266_test.h"
#include "bsp_beep.h"
#include "bsp_dht11.h"
#include "bsp_led.h"  
#include "key.h"
#include "./dwt_delay/core_delay.h"
#include "stm32f10x_exti.h"

extern uint16_t lcdid;
char set_t_char[10],set_p_char[10];
char get_t_char[10],get_p_char[10];
u8 set_t=31,set_p=45;                   //温湿度阈值设置
int get_t,get_p;

void LCD_show(void);
void ESP8266_SendDHT11DataTest(void);
DHT11_Data_TypeDef DHT11_Data;

int main()
{
	/* 初始化 */
    USART_Config ();    //初始化串口1
    CPU_TS_TmrInit();   //初始化DWT计数器,用于延时函数
    LED_Init();         //初始化RGB彩灯
	EXTI_Key_Config();  //KEY中断初始化
	BEEP_GPIO_Config();
	ESP8266_Init();    //初始化WiFi模块使用的接口和外设
	DHT11_Init();      //初始化DHT11
	ILI9341_Init();     //LCD 初始化  
	SysTick_Init();
	
	ILI9341_GramScan(6);     //配置 SysTick 为 10ms 中断一次,在中断里读取传感器数据
	ESP8266_StaTcpClient_Unvarnish_ConfigTest();   //对ESP8266进行配置
	
	LCD_SetFont(&Font8x16);
	LCD_SetColors(WHITE,BLACK);
    ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);	/* 清屏,显示全黑 */
	LCD_show();
	
  while (1)
  {
    if( read_dht11_finish ) // read_dht11_finish == 1 or read_dht11_finish == -1
    {
      ESP8266_SendDHT11DataTest(); // ESP8266 发送一次温湿度数据	
      read_dht11_finish = 0;       // 清零标志位
    } 
  }
}



void ESP8266_SendDHT11DataTest(void)
{
  char cStr[100]={0};
	char aaa[100];
	uint8_t ucStatus;

  if( 1 == read_dht11_finish ){
    sprintf ( cStr, "\r\n\r\n读取DHT11成功!\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 );
     
		get_t = DHT11_Data.temp_int;
		get_p = DHT11_Data.humi_int;
		
		/* 显示温度 */
		if(get_t <= set_t){                 //当前温度一栏显示绿色
			LCD_ClearLine(LINE(16));
			LCD_SetTextColor(GREEN);
			sprintf(aaa,"        当前温度: %d.%d℃",DHT11_Data.temp_int, DHT11_Data.temp_deci);
			LCD_ClearLine(LINE(9));	/* 清除单行文字 */
			ILI9341_DispStringLine_EN_CH(LINE(9),aaa);
			PBout(5)=1;
			BEEP( OFF );                 //灯灭、蜂鸣器关
		} else{                             //当前温度超过阈值时颜色变红
			LCD_SetTextColor(RED);
			sprintf(aaa,"        当前温度: %d.%d℃",DHT11_Data.temp_int, DHT11_Data.temp_deci);
			LCD_ClearLine(LINE(9));	/* 清除单行文字 */
			ILI9341_DispStringLine_EN_CH(LINE(9),aaa);
			ILI9341_DispStringLine_EN_CH(LINE(16),"     !!!WARRING !!!   ");
			printf("!!!温度超出阈值!!!");         //串口输出
			PBout(5)=0;
			BEEP( ON );                 //灯亮、蜂鸣器开
		}
		
		/* 显示湿度 */
		if(get_p <= set_p){                 //当前湿度一栏显示绿色
			LCD_ClearLine(LINE(17));
			LCD_SetTextColor(GREEN);
			sprintf(aaa,"        当前湿度:%d.%d%%",DHT11_Data.humi_int, DHT11_Data.humi_deci);
			LCD_ClearLine(LINE(10));	/* 清除单行文字 */
			ILI9341_DispStringLine_EN_CH(LINE(10),aaa);
			PBout(1)=1;
			BEEP( OFF );           //灯灭、蜂鸣器关
		} else{                             //当前湿度超过阈值时颜色变蓝
			LCD_SetTextColor(BLUE);
			sprintf(aaa,"        当前湿度:%d.%d%%",DHT11_Data.humi_int, DHT11_Data.humi_deci);
			LCD_ClearLine(LINE(10));	/* 清除单行文字 */
			ILI9341_DispStringLine_EN_CH(LINE(10),aaa);
			ILI9341_DispStringLine_EN_CH(LINE(17),"     !!!WARRING !!!   ");
			printf("!!!湿度超出阈值!!!");         //串口输出
			PBout(1)=0;
			BEEP( ON );						//灯亮、蜂鸣器开
		}
	}
  else
		sprintf ( cStr, "Read DHT11 ERROR!\r\n" );
  
  printf ( "%s", cStr );                                             //打印读取 DHT11 温湿度信息
  ESP8266_SendString ( ENABLE, cStr, 0, Single_ID_0 );               //发送 DHT11 温湿度信息到网络调试助手
  
  if ( ucTcpClosedFlag )                                             //检测是否失去连接
  {
    ESP8266_ExitUnvarnishSend ();                                    //退出透传模式
    do ucStatus = ESP8266_Get_LinkStatus ();                         //获取连接状态
    while ( ! ucStatus );
    if ( ucStatus == 4 )                                             //确认失去连接后重连
    {
      printf ( "\r\n正在重连热点和服务器 ......\r\n" );
      while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );  
      while ( !	ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
      printf ( "\r\n重连热点和服务器成功\r\n" );
    }
    while ( ! ESP8266_UnvarnishSend () );		
  }
}

//按键1中断     按键1调节温度阈值
void KEY1_IRQHandler(void)
{
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)      //确保是否产生了EXTI Line中断
	{
			set_t++;
			if(set_t >= 36){ 
				set_t = 15;
			}
			
			LCD_ClearLine(LINE(6));              //温度阈值数据随按键发生改变  第6行
			LCD_SetTextColor(GREEN);             //设置绿色
			sprintf(set_t_char,"        温度阈值:%d℃ ",set_t);
			LCD_ClearLine(LINE(6));
			ILI9341_DispStringLine_EN_CH(LINE(6),set_t_char); 
			//清除中断标志位
			EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);  
		}  
}

//按键2中断
void KEY2_IRQHandler(void)
{
	if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)   //确保是否产生了EXTI Line中断
	{
			set_p++;
			if(set_p >= 45){ 
				set_p = 20;
			}

			LCD_ClearLine(LINE(7));
			LCD_SetTextColor(GREEN);
			sprintf(set_p_char,"        湿度阈值:%dRH ",set_p);
			LCD_ClearLine(LINE(7));
			ILI9341_DispStringLine_EN_CH(LINE(7),set_p_char);
			//清除中断标志位
			EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
	}   
} 
  
void LCD_show(void)
{
  ILI9341_DispStringLine_EN_CH(LINE(3),"       GPRS监测报警系统   ");
	
	LCD_SetTextColor(GREEN);
	sprintf(set_t_char,"        温度阈值:%d℃ ",set_t);
    LCD_ClearLine(LINE(6));
	ILI9341_DispStringLine_EN_CH(LINE(6),set_t_char);                    
	
	LCD_SetTextColor(GREEN);
	sprintf(set_p_char,"        湿度阈值:%dRH ",set_p);
    LCD_ClearLine(LINE(7));
	ILI9341_DispStringLine_EN_CH(LINE(7),set_p_char); 
	
	LCD_SetTextColor(GREEN);
	sprintf(get_t_char,"        当前温度:%d℃ ",get_t);
    LCD_ClearLine(LINE(9));
	ILI9341_DispStringLine_EN_CH(LINE(9),get_t_char);                    
	
	LCD_SetTextColor(GREEN);
	sprintf(get_p_char,"        当前湿度:%dRH ",get_p);
    LCD_ClearLine(LINE(10));
	ILI9341_DispStringLine_EN_CH(LINE(10),get_p_char); 
	
	LCD_ClearLine(LINE(13));
}

esp8266_test.c

#include "bsp_esp8266_test.h"
#include "bsp_esp8266.h"
#include "./dwt_delay/core_delay.h"
#include <stdio.h>  
#include <string.h>  
#include <stdbool.h>
#include "bsp_dht11.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./lcd/bsp_ili9341_lcd.h"
#include "bsp_SysTick.h"
#include "stm32f10x.h"

#define LED_CMD_NUMBER   8
char *ledCmd[8] = { "LED_RED","LED_GREEN","LED_BLUE","LED_YELLOW","LED_PURPLE","LED_CYAN","LED_WHITE","LED_RGBOFF" };
volatile uint8_t ucTcpClosedFlag = 0;

void ESP8266_StaTcpClient_Unvarnish_ConfigTest(void)
{
	
	LCD_SetFont(&Font8x16);
	LCD_SetColors(WHITE,BLACK);
	
    printf( "\r\n正在配置 ESP8266 ......\r\n" );
    printf( "\r\n使能 ESP8266 ......\r\n" );
	ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);	/* 清屏,显示全黑 */
    ILI9341_DispStringLine_EN_CH(LINE(1),"正在配置 ESP8266 ......");
	ILI9341_DispStringLine_EN_CH(LINE(2),"使能 ESP8266 ......");
	
	macESP8266_CH_ENABLE();
	while( ! ESP8266_AT_Test() );
    while( ! ESP8266_DHCP_CUR () );  
    printf( "\r\n正在配置工作模式 STA ......\r\n" );
	
	while( ! ESP8266_Net_Mode_Choose ( STA ) );

    printf( "\r\n正在连接 WiFi ......\r\n" );
	ILI9341_DispStringLine_EN_CH(LINE(8),"正在连接WiFi...... ");
    while( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid,   macUser_ESP8266_ApPwd ) );	
	ILI9341_DispStringLine_EN_CH(LINE(9),"WiFi 连接...... 成功");
	
    printf( "\r\n禁止多连接 ......\r\n" );
	while( ! ESP8266_Enable_MultipleId ( DISABLE ) );
	ILI9341_DispStringLine_EN_CH(LINE(10),"多连接禁止 ......  成功");
	
    printf( "\r\n正在连接 Server ......\r\n" );
	ILI9341_DispStringLine_EN_CH(LINE(11),"正在连接Server ......  ");
	while( !	ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
	ILI9341_DispStringLine_EN_CH(LINE(12),"Server 连接......  成功");
	
    printf( "\r\n进入透传发送模式 ......\r\n" );
	while( ! ESP8266_UnvarnishSend () );
	ILI9341_DispStringLine_EN_CH(LINE(13),"进入透传发送模式");
	
	printf( "\r\n配置 ESP8266 完毕\r\n" );
	ILI9341_DispStringLine_EN_CH(LINE(14),"配置 ESP8266 完毕");
    ILI9341_DispStringLine_EN_CH(LINE(15),"读取DHT11成功!");
}

3.配置

led.c + led.h

led.c:
#include "bsp_led.h"
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "bsp_SysTick.h"


void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
	
	RCC_APB2PeriphClockCmd(LED1_PORT_RCC|LED2_PORT_RCC|LED3_PORT_RCC,ENABLE);
	GPIO_InitStructure.GPIO_Pin=LED1_PIN;  //选择你要设置的IO口
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;	 //设置推挽输出模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	  //设置传输速率
	GPIO_Init(LED1_PORT,&GPIO_InitStructure); 	   /* 初始化GPIO */
	GPIO_SetBits(LED1_PORT,LED1_PIN);   //将LED端口拉高,熄灭所有LED
	
	GPIO_InitStructure.GPIO_Pin=LED2_PIN;  //选择你要设置的IO口
	GPIO_Init(LED2_PORT,&GPIO_InitStructure); 	   /* 初始化GPIO */
	GPIO_SetBits(LED2_PORT,LED2_PIN);   //将LED端口拉高,熄灭所有LED
	
	GPIO_InitStructure.GPIO_Pin=LED3_PIN;  //选择你要设置的IO口
	GPIO_Init(LED3_PORT,&GPIO_InitStructure); 	   /* 初始化GPIO */
	GPIO_SetBits(LED3_PORT,LED3_PIN);   //将LED端口拉高,熄灭所有LED	
}


led.h
#ifndef _gpio_H
#define _gpio_H

#include "system.h"
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "bsp_SysTick.h"

//led
/*  LED时钟端口、引脚定义 */
#define LED1_PORT 			GPIOB   
#define LED1_PIN 			GPIO_Pin_5
#define LED1_PORT_RCC		RCC_APB2Periph_GPIOB

#define LED2_PORT 			GPIOA   
#define LED2_PIN 			GPIO_Pin_0
#define LED2_PORT_RCC		RCC_APB2Periph_GPIOB

#define LED3_PORT 			GPIOB
#define LED3_PIN 			GPIO_Pin_1
#define LED3_PORT_RCC		RCC_APB2Periph_GPIOB

void LED_Init(void);
void delays(uint32_t time);
void TIM3_Int_Init(u16 arr,u16 psc);

#endif

beep.c + beep.h

beep.c:
#include "bsp_beep.h"   

void BEEP_GPIO_Config(void)
{		
		/*定义一个GPIO_InitTypeDef类型的结构体*/
		GPIO_InitTypeDef GPIO_InitStructure;

		/*开启控制蜂鸣器的GPIO的端口时钟*/
		RCC_APB2PeriphClockCmd( BEEP_GPIO_CLK, ENABLE); 

		/*选择要控制蜂鸣器的GPIO*/															   
		GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;	

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

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

		/*调用库函数,初始化控制蜂鸣器的GPIO*/
		GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);			 
    
        /* 关闭蜂鸣器*/
		GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);	 
}


beep.h:
#ifndef __BEEP_H
#define	__BEEP_H

#include "stm32f10x.h"

/* 定义蜂鸣器连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的蜂鸣器引脚 */
#define BEEP_GPIO_PORT    	GPIOA			              /* GPIO端口 */
#define BEEP_GPIO_CLK 	    RCC_APB2Periph_GPIOA		/* GPIO端口时钟 */
#define BEEP_GPIO_PIN		  GPIO_Pin_8			        /* 连接到蜂鸣器的GPIO */

/* 高电平时,蜂鸣器响 */
#define ON  1
#define OFF 0

/* 带参宏,可以像内联函数一样使用 */
#define BEEP(a)	if (a)	\
					GPIO_SetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);\
					else		\
					GPIO_ResetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN)

void BEEP_GPIO_Config(void);
					
#endif /* __BEEP_H */

按键中断配置

key.c:
#include "key.h"  
#include "stm32f10x_exti.h"

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 配置NVIC为优先级组1 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* 配置中断源:按键1 */
  NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
  /* 配置抢占优先级 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  /* 配置中断源:按键2,其他使用上面相关配置 */  
  NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
  NVIC_Init(&NVIC_InitStructure);
}

void EXTI_Key_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure;

	/*开启按键GPIO口的时钟*/
	RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
    RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK,ENABLE);
												
	/* 配置 NVIC 中断*/
	NVIC_Configuration();
	
/*--------------------------KEY1配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;  //	按键1 PA0
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE); 
  EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
		
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 上升沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  	//按键按下开启中断
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
	
  /*--------------------------KEY2配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;			//按键2 PC13
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); 
  EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
	
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 下降沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}



key.h:
#ifndef __EXTI_H
#define	__EXTI_H

#include "stm32f10x.h"

//引脚定义
#define KEY1_INT_GPIO_PORT         GPIOA 					//按键1 PA0
#define KEY1_INT_GPIO_CLK          (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN          GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE    GPIO_PinSource0
#define KEY1_INT_EXTI_LINE         EXTI_Line0
#define KEY1_INT_EXTI_IRQ          EXTI0_IRQn

#define KEY1_IRQHandler            EXTI0_IRQHandler

#define KEY2_INT_GPIO_PORT         GPIOC					//按键2 PC13
#define KEY2_INT_GPIO_CLK          (RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO)
#define KEY2_INT_GPIO_PIN          GPIO_Pin_13

#define KEY2_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE    GPIO_PinSource13
#define KEY2_INT_EXTI_LINE         EXTI_Line13
#define KEY2_INT_EXTI_IRQ          EXTI15_10_IRQn

#define KEY2_IRQHandler            EXTI15_10_IRQHandler

#define KEY_ON	1
#define KEY_OFF	0

void EXTI_Key_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

#endif /* __EXTI_H */

dht11.c + dht11.h

dht11.c:
#include "bsp_dht11.h"
#include "./dwt_delay/core_delay.h"

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 );

void DHT11_Init ( void )
{
	DHT11_GPIO_Config ();
	macDHT11_Dout_1;               // 拉高GPIOB10
}


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

	/*开启macDHT11_Dout_GPIO_PORT的外设时钟*/
  macDHT11_Dout_SCK_APBxClock_FUN ( macDHT11_Dout_GPIO_CLK, ENABLE );	
	/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/															   
  	GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;	
	/*设置引脚模式为通用推挽输出*/
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
	/*设置引脚速率为50MHz */   
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
  	GPIO_Init ( macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure );		  
}

/*
 * 函数名:DHT11_Mode_IPU
 * 描述  :使DHT11-DATA引脚变为上拉输入模式
 * 输入  :无
 * 输出  :无
 */
static void DHT11_Mode_IPU(void)
{
 	  GPIO_InitTypeDef GPIO_InitStructure;
	  /*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/	
	  GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;
	  /*设置引脚模式为浮空输入模式*/ 
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; 
	  /*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
	  GPIO_Init(macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure);	 
}

/*
 * 函数名:DHT11_Mode_Out_PP
 * 描述  :使DHT11-DATA引脚变为推挽输出模式
 * 输入  :无
 * 输出  :无
 */
static void DHT11_Mode_Out_PP(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
	/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/															   
  	GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;	
	/*设置引脚模式为通用推挽输出*/
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
	/*设置引脚速率为50MHz */   
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
  	GPIO_Init(macDHT11_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(macDHT11_Dout_IN()==Bit_RESET);
		/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
		 *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时 
		 */
		Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可	   	  
		if(macDHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
		{
			/* 等待数据1的高电平结束 */
			while(macDHT11_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();
	/*主机拉低*/
	macDHT11_Dout_0;
	/*延时18ms*/
	Delay_ms(18);
	/*总线拉高 主机延时30us*/
	macDHT11_Dout_1; 
	Delay_us(30);   //延时30us
	/*主机设为输入 判断从机响应信号*/ 
	DHT11_Mode_IPU();
	/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   
	if(macDHT11_Dout_IN()==Bit_RESET)     
	{
		/*轮询直到从机发出 的80us 低电平 响应信号结束*/  
		while(macDHT11_Dout_IN()==Bit_RESET);
		/*轮询直到从机发出的 80us 高电平 标置信号结束*/
		while(macDHT11_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();
		/*主机拉高*/
		macDHT11_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;
}


dht11.h:
#ifndef __DHT11_H
#define	__DHT11_H

#include "stm32f10x.h"

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;

#define      macDHT11_Dout_SCK_APBxClock_FUN              RCC_APB2PeriphClockCmd
#define      macDHT11_Dout_GPIO_CLK                       RCC_APB2Periph_GPIOE

#define      macDHT11_Dout_GPIO_PORT                      GPIOE
#define      macDHT11_Dout_GPIO_PIN                       GPIO_Pin_6

/************************** DHT11 函数宏定义********************************/
#define      macDHT11_Dout_0	                            GPIO_ResetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 
#define      macDHT11_Dout_1	                            GPIO_SetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 

#define      macDHT11_Dout_IN()	                          GPIO_ReadInputDataBit ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 

/************************** DHT11 函数声明 ********************************/
void                     DHT11_Init                      ( void );
uint8_t                  DHT11_Read_TempAndHumidity      ( DHT11_Data_TypeDef * DHT11_Data );
;
#endif /* __DHT11_H */

总结

  基于ESP8266的温湿度检监测报警系统是一个适合初学者的STM32设计,本系统设计包含了GPIO的配置、ESP8266的配置与使用、传感器DHT11的使用、按键中断、串口发送信息、LCD显示等的使用。本系统主要部分即温湿度采集和WiFi数据传输,比较适合初学者学习理论知识后对知识的总结和融会贯通。
  LCD的应用对于本系统是非必要的,一般来讲串口输出调试信息即可作为程序反馈,但谁又能拒绝一块看起来科技感十足的显示器呢(QVQ)。对于初学者来说如果想要走物联网这条线,本系统难度适中可以作为一个的炼手的例程,当然作为课程设计也是蛮不错的选择。

下载

链接: http://cloud.taospace.top/基于stm32的温湿度检监测报警系统的设计/

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐