单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)

一、项目功能概述 1、通过DHT11温湿度模块检测温湿度
2、通过MQ-2烟雾传感器检测烟雾
3、通过光敏电阻模块检测光照强度
4、oled液晶屏显示实时检测到的数据
5、超限蜂鸣器报警
源码下载地址:基于STM32的DHT11、MQ-2、光照强度检测
二、材料选择 1、主控 STM32F103C8T6
本人是自己制作的最小系统版,主要目的省钱!!!!
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

2、DHT11温湿度模块
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

3、MQ-2烟雾传感器模块
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

4、光敏电阻模块
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

5、0.96 OLED液晶屏
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

6、蜂鸣器模块
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

三、原理图设计 1、DHT11连接图
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

2、OLED液晶模块连接图
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

3、MQ-2硬件连接图
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

4、光敏电阻模块硬件连接图
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

5、蜂鸣器模块硬件连接图
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

四、成品展示 1、上电界面
由于相机刷新率比较快,拍屏幕会有闪!!!
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

2、开来台灯后,光照强度数值明显提升!!!
单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)
文章图片

剩下的温湿度和烟雾浓度就不贴图片了,没法直观表示数据更新!!!
五、源码设计 OLED.c

#include "oled.h" #include "codetab.h" #include "main.h" #include "string.h" #include "i2c.h" #include "./usart/bsp_debug_usart.h" #include "dht11.h" #include "key.h" #include "bsp_led.h" #define IIC_SCK_0GPIOA->BRR=0X0080// 设置sck接口到PA7置零 #define IIC_SCK_1GPIOA->BSRR=0X0080//置位 #define IIC_SDA_0GPIOB->BRR=0X0001// 设置SDA接口到PB0置零 #define IIC_SDA_1GPIOB->BSRR=0X0001// 复位char mStrVol[20]; char mStrCul[20]; char mStrtemp[20]; char mStrhum[20]; char mStrSpeed[20]; char mStrDirec[20]; uint16_t mVolValue; uint16_t mCulValue; extern uint8_t shidu ; extern uint8_t wendu; extern uint16_t value1; extern uint16_t value2; unsigned int GetDeltaTicks(unsigned int tickcount) { unsigned int now = GetTickCount(); returnnow >= tickcount ? (now - tickcount) : (0xFFFFFFFF - tickcount + now); } void I2C_GPIO_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStructure.Pin = GPIO_PIN_7 ; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); //SCL引脚初始化 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7 ,GPIO_PIN_SET); GPIO_InitStructure.Pin = GPIO_PIN_0 ; HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); //SDA引脚初始化 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0 ,GPIO_PIN_SET); }void delay_us(unsigned int _us_time) { unsigned char x=0; for(; _us_time>0; _us_time--) { x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; x++; } }void delay_ms(unsigned int _ms_time) { unsigned int i,j; for(i=0; i<_ms_time; i++) { for(j=0; j<900; j++) {; } } }const unsigned charOLED_init_cmd[25]= { /*0xae,0X00,0X10,0x40,0X81,0XCF,0xff,0xa1,0xa4, 0xA6,0xc8,0xa8,0x3F,0xd5,0x80,0xd3,0x00,0XDA,0X12, 0x8d,0x14,0xdb,0x40,0X20,0X02,0xd9,0xf1,0xAF*/ 0xAE,//关闭显示 0xD5,//设置时钟分频因子,震荡频率 0x80,//[3:0],分频因子; [7:4],震荡频率0xA8,//设置驱动路数 0X3F,//默认0X3F(1/64) 0xD3,//设置显示偏移 0X00,//默认为0 0x40,//设置显示开始行 [5:0],行数. 0x8D,//电荷泵设置 0x14,//bit2,开启/关闭 0x20,//设置内存地址模式 0x02,//[1:0],00,列地址模式; 01,行地址模式; 10,页地址模式; 默认10; 0xA1,//段重定义设置,bit0:0,0->0; 1,0->127; 0xC8,//设置COM扫描方向; bit3:0,普通模式; 1,重定义模式 COM[N-1]->COM0; N:驱动路数 0xDA,//设置COM硬件引脚配置 0x12,//[5:4]配置 0x81,//对比度设置 0xEF,//1~255; 默认0X7F (亮度设置,越大越亮) 0xD9,//设置预充电周期 0xf1,//[3:0],PHASE 1; [7:4],PHASE 2; 0xDB,//设置VCOMH 电压倍率 0x30,//[6:4] 000,0.65*vcc; 001,0.77*vcc; 011,0.83*vcc; 0xA4,//全局显示开启; bit0:1,开启; 0,关闭; (白屏/黑屏) 0xA6,//设置显示方式; bit0:1,反相显示; 0,正常显示 0xAF,//开启显示 }; /***************************************** 字节数据发送函数 函数原型:void IIC_write(unsigned char date); 功能:将数据date发送出去,可以是地址,也可以是数据 ******************************************/ void IIC_write(unsigned char date) { unsigned char i, temp; temp = date; for(i=0; i<8; i++)//传送数据长度为8位 { IIC_SCK_0; if ((temp&0x80)==0)//判断发送位 IIC_SDA_0; else IIC_SDA_1; temp = temp << 1; delay_us(1); IIC_SCK_1; delay_us(1); } IIC_SCK_0; delay_us(1); IIC_SDA_1; delay_us(1); IIC_SCK_1; delay_us(1); IIC_SCK_0; delay_us(1); }/************************************************************************* 功能:启动I2C总线,即发送I2C起始条件。SCL为高电平期间,SDA出现下降沿 **************************************************************************/ void IIC_start() { IIC_SDA_1; delay_us(1); IIC_SCK_1; delay_us(1); //所有操作结束释放SCL IIC_SDA_0; delay_us(3); IIC_SCK_0; IIC_write(0x78); }/************************************************************************* 功能:结束I2C总线,即发送I2C结束条件。SCL为高电平期间,SDA出现上升沿 **************************************************************************/ void IIC_stop() { IIC_SDA_0; delay_us(1); IIC_SCK_1; delay_us(3); IIC_SDA_1; }void OLED_send_cmd(unsigned char o_command) { IIC_start(); IIC_write(0x00); IIC_write(o_command); IIC_stop(); }void OLED_send_data(unsigned char o_data) { IIC_start(); IIC_write(0x40); IIC_write(o_data); IIC_stop(); } void Column_set(unsigned char column) { OLED_send_cmd(0x10|(column>>4)); //设置列地址高位 OLED_send_cmd(0x00|(column&0x0f)); //设置列地址低位} void Page_set(unsigned char page) { OLED_send_cmd(0xb0+page); }void OLED_clear(void) { unsigned char page,column; for(page=0; page<8; page++)//page loop { Page_set(page); Column_set(0); for(column=0; column<128; column++) //column loop { OLED_send_data(0x00); } } }void OLED_full(void) { unsigned char page,column; for(page=0; page<8; page++)//page loop { Page_set(page); Column_set(0); for(column=0; column<128; column++) //column loop { OLED_send_data(0xff); } } }void OLED_init(void) { unsigned char i; for(i=0; i<25; i++) { OLED_send_cmd(OLED_init_cmd[i]); } OLED_clear(); // OLED_Chinese16x16Str(0,0,Chinese_WEN_F16X16); // OLED_Chinese16x16Str(2,0,Chinese_DU_F16X16); // OLED_Chinese16x16Str(0,1,Chinese_SHII_F16X16); // OLED_Chinese16x16Str(2,1,Chinese_DU_F16X16); // OLED_Chinese16x16Str(0,4,Chinese_GUANG_F16X16); // OLED_Chinese16x16Str(2,4,Chinese_ZHAO_F16X16); // // OLED_Chinese16x16Str(0,6,Chinese_YAN_F16X16); // OLED_Chinese16x16Str(2,6,Chinese_WU_F16X16); // OLED_Chinese16x16Str(3,2,Chinese_YE_F16X16); // OLED_Chinese16x16Str(4,2,Chinese_SHE_F16X16); // OLED_Chinese16x16Str(5,2,Chinese_JII_F16X16); ////HAL_Delay(1000); //// OLED_clear(); // // OLED_Chinese16x16Str(1,0,Chinese_Liu_F16X16); // OLED_Chinese16x16Str(2,0,Chinese_Tang_F16X16); // OLED_Chinese16x16Str(3,0,Chinese_CHONG_F16X16); // OLED_Chinese16x16Str(4,0,Chinese_WU_F16X16); // OLED_Chinese16x16Str(5,0,Chinese_WEI_F16X16); // OLED_Chinese16x16Str(6,0,Chinese_SHI_F16X16); // OLED_Chinese16x16Str(7,0,Chinese_QI_F16X16); }void Picture_display(const unsigned char *ptr_pic) { unsigned char page,column; for(page=0; page<(64/8); page++)//page loop { Page_set(page); Column_set(0); for(column=0; column<128; column++) //column loop { OLED_send_data(*ptr_pic++); } } }void Picture_ReverseDisplay(const unsigned char *ptr_pic) { unsigned char page,column,data; for(page=0; page<(64/8); page++)//page loop { Page_set(page); Column_set(0); for(column=0; column<128; column++) //column loop { data=https://www.it610.com/article/*ptr_pic++; data=~data; OLED_send_data(data); } } }void OLED_Set_Pos(uint8_t x, uint8_t y) { OLED_send_cmd(0xb0+y); OLED_send_cmd(((x&0xf0)>>4)|0x10); OLED_send_cmd((x&0x0f)|0x01); } void OLED_Chinese16x16Str(uint8_t x,uint8_t y,const uint8_t * ch) { uint8_t i; uint8_t j,k =0; j = x<<4; //列 0~7该字符占2*8bits k = y<<1; //行 0~4 该字符占2*8bits OLED_Set_Pos(j,k); for(i=0; i<16; i++) OLED_send_data(*(ch+i)); OLED_Set_Pos(j,k+1); for(i=16; i<32; i++) OLED_send_data(*(ch+i)); }void OLED_OneByte(uint8_t x,uint8_t y,uint8_t k) { uint8_t c=0,i=0,z =0; z = x*6; //获取起始位置 c =k-32; if(z>126){z=0; y++; } OLED_Set_Pos(z,y); //设置地址 /*一个ascii显示需要6个8bit数据*/ for(i=0; i<6; i++) OLED_send_data(F6x8[c][i]); } void OLED_P6x8Str(uint8_t x,uint8_t y,int8_t ch[]) { uint8_t c=0,i=0,j=0,z =0; z = x*6; // while (ch[j]!='\0') { c =ch[j]-32; if(z>126){z=0; y++; } OLED_Set_Pos(z,y); for(i=0; i<6; i++) OLED_send_data(F6x8[c][i]); z+=6; j++; } } void OLED_P8x16Str(uint8_t x,uint8_t y,uint8_t *chr) { uint8_t j=0; uint8_t c = 0, i = 0; while (chr[j]!='\0') { c = chr[j] - ' ' ; OLED_Set_Pos(x,y); for(i=0; i<8; i++) OLED_send_data(F8X16[c*16+i]); OLED_Set_Pos(x,y+1); for(i=0; i<8; i++) OLED_send_data(F8X16[c*16+i+8]); x+=8; if(x>120){x=0; y+=2; } j++; } }

【单片机|STM32项目设计(基于STM32的DHT11、MQ-2、光照强度检测)】DHT11.c
#include "dht11.h" #include "main.h" #include "oled.h"void delay_uss(unsigned int us) { uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us); while(delay--) { ; } } void DHT11_Rst(void) { DHT11_IO_OUT(); //SET OUTPUT DHT11_DQ_OUT=0; //拉低DQ HAL_Delay(25); //拉低至少18ms DHT11_DQ_OUT=1; //DQ=1 delay_uss(30); //主机拉高20~40us }//等待DHT11的回应 //返回1:未检测到DHT11的存在 //返回0:存在 u8 DHT11_Check(void) { u8 retry=0; DHT11_IO_IN(); //SET INPUT while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us { retry++; delay_uss(1); }; if(retry>=100)return 1; else retry=0; while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us { retry++; delay_uss(1); }; if(retry>=100)return 1; return 0; } //从DHT11读取一个位 //返回值:1/0 u8 DHT11_Read_Bit(void) { u8 retry=0; while(DHT11_DQ_IN&&retry<100)//等待变为低电平 { retry++; delay_uss(1); } retry=0; while(!DHT11_DQ_IN&&retry<100)//等待变高电平 { retry++; delay_uss(1); } delay_us(40); //等待40us if(DHT11_DQ_IN)return 1; else return 0; } //从DHT11读取一个字节 //返回值:读到的数据 u8 DHT11_Read_Byte(void) { u8 i,dat; dat=0; for (i=0; i<8; i++) { dat<<=1; dat|=DHT11_Read_Bit(); } return dat; } //从DHT11读取一次数据 //temp:温度值(范围:0~50°) //humi:湿度值(范围:20%~90%) //返回值:0,正常; 1,读取失败 u8 DHT11_Read_Data(u8 *temp,u8 *humi) { u8 buf[5]; u8 i; DHT11_Rst(); if(DHT11_Check()==0) { for(i=0; i<5; i++)//读取40位数据 { buf[i]=DHT11_Read_Byte(); } if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]) { *humi=buf[0]; *temp=buf[2]; } }else return 1; return 0; } //初始化DHT11的IO口 DQ 同时检测DHT11的存在 //返回1:不存在 //返回0:存在 u8 DHT11_Init(void) { GPIO_InitTypeDefGPIO_InitStructure; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStructure.Pin = GPIO_PIN_11; //PG11端口配置 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; //GPIO_InitStructure.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO口 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11 ,GPIO_PIN_SET); //PG11 输出高 DHT11_Rst(); //复位DHT11 return DHT11_Check(); //等待DHT11的回应 }

    推荐阅读