一、项目功能概述 1、通过DHT11温湿度模块检测温湿度
2、通过MQ-2烟雾传感器检测烟雾
3、通过光敏电阻模块检测光照强度
4、oled液晶屏显示实时检测到的数据
5、超限蜂鸣器报警
源码下载地址:基于STM32的DHT11、MQ-2、光照强度检测
二、材料选择 1、主控 STM32F103C8T6
本人是自己制作的最小系统版,主要目的省钱!!!!
文章图片
2、DHT11温湿度模块
文章图片
3、MQ-2烟雾传感器模块
文章图片
4、光敏电阻模块
文章图片
5、0.96 OLED液晶屏
文章图片
6、蜂鸣器模块
文章图片
三、原理图设计 1、DHT11连接图
文章图片
2、OLED液晶模块连接图
文章图片
3、MQ-2硬件连接图
文章图片
4、光敏电阻模块硬件连接图
文章图片
5、蜂鸣器模块硬件连接图
文章图片
四、成品展示 1、上电界面
由于相机刷新率比较快,拍屏幕会有闪!!!
文章图片
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的回应
}
推荐阅读
- proteus|基于51单片机计算器设计
- 基于STM32的恒流源设计
- 单片机|基于51单片机HX711的电子秤称重计价proteus仿真程序设计
- 8吋产能供应吃紧情况下灵动微电子12寸晶圆单片机有哪些()
- 《C语言程序设计》(谭浩强第五版) 第5章 循环结构程序设计 习题解析与答案
- C语言进阶|【C语言进阶7——数组和指针的练习(1) - 学习sizeof 和 strlen,看完这一篇就够了】
- 笔记|C语言进阶——3.二维指针
- c|指针进阶——字符指针、指针数组和数组指针如何辨别和判断
- C语言进阶|【C语言进阶6——指针的进阶(3)-总结数组和指针】