材料
简答记录一下自己学32的过程,这次介绍的是基于STM32的火灾报警系统,用到了面板板,MQ5烟雾传感器,温湿度传感器,0.96寸OLED屏幕,火焰传感器,4个插座式按键,一个STM32F103单片机。
简单介绍
单片机上电,OLED可以显示温度湿度,可以通过两个按键调节温度阈值(本实验中的四个按键分别用K0 K1 K2 K3来表示,这里的两个按键为K1 K2用于调节阈值的),当温度超过阈值时,OLED会提示危险。一秒后会提示重新设置温度阈值,当设置的阈值还是小于当前温度时,会提示当前温度大于设置的阈值,跳回设置阈值界面,重新设置阈值。
当火焰传感器检测到火焰时,OLED显示着火了。
通过按键K0来切换OLED界面从而显示烟雾传感器的数值,当OLED页面显示的烟雾传感器的数值时可以通过K1 K2来设置烟雾的阈值,当超过阈值时,单片机的led灯被点亮。当OLED页面显示的是温湿度传感器的值时,则K1 K2设置的是温度阈值
关键代码
DHT.c
#include "DHT.h"
#include "delay.h"
//DHT11初始化函数
//DHT11 DATA---PB3
void Dht11_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct;
//开B组时钟和AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);
//初始化IO口
//定义结构体变量
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //配置为开漏输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; //选定管脚3
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度为2MHZ
GPIO_Init( GPIOB, &GPIO_InitStruct);
GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET);
delay_ms(1000); //延时1s越过不稳定状态
}
/*
* 函数名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引脚变为上拉输入模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/*设置引脚模式为上拉输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*调用库函数,初始化DHT11_PORT*/
GPIO_Init(GPIOB, &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 = GPIO_Pin_0;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_PORT*/
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//MCU发送开始信号函数
void Mcu_Send_Start_Sign(void)
{
DHT11_Mode_Out_PP();
GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_RESET);
delay_ms(18); //拉低总线18ms以上
GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET); //拉高总线等待DHT11响应
DHT11_Mode_IPU();
}
//等待DHT11响应函数
//返回值 1---响应失败 0-----响应成功
u8 Dht11_Ack(void)
{
u8 i = 0;
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1)
{
i++;
delay_us(1);
if(i>50)
{
return 1; //Dht11响应失败
}
}
//代码运行到这里代表DHT11响应成功
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0);//跳过DHT11响应时间
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1);//跳过DHT11测量时间
return 0; //DHT11响应成功
}
//读DHT11测到的数据
u8 Read_Dht11_Data(void)
{
u8 i,data = 0;
for(i=0;i<8;i++)
{
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0);//跳过数据的1bit低电平开始位
delay_us(40);
// data = data<<1;
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1) //数据1
{
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1);//跳过数据'1'的剩余高电平时间
// data |= 1;
data|=(uint8_t)(0x01<<(7-i));
}
else{
data&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return data;
}
u8 Mcu_Control_Dht11(u8 *p)
{
u8 ret;
Mcu_Send_Start_Sign(); //发送开始信号
ret = Dht11_Ack();
if(ret)
{
return 1; //测量失败
}
p[0] = Read_Dht11_Data(); //湿度整数数据
p[1] = Read_Dht11_Data(); //湿度小数数据
p[2] = Read_Dht11_Data(); //温度整数数据
p[3] = Read_Dht11_Data(); //温度小数数据
p[4] = Read_Dht11_Data(); //8bit校验和
// for(int i=0;i<4;i++)
// {
// *p=Read_Dht11_Data();
// p++;
// }
if(p[0]+p[1]+p[2]+p[3] != p[4])
{
return 1; //测量失败
}
return 0; //测量成功
}
DHT.h
#ifndef __DHT_H
#define __DHT_H
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"
static void DHT11_Mode_IPU(void);
static void DHT11_Mode_Out_PP(void);
void Dht11_Init(void);
u8 Mcu_Control_Dht11(u8 *p);
#endif
key_exit.c
#include "key_exit.h"
//PC14 increase增加 PC15 reduce减少 PB5 确定
uint16_t flag=29,temp=0,menu=0,Smokeflag=300;
void key_exit_Init()
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStrcut;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource14);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource15);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);
EXTI_InitStruct.EXTI_Line=EXTI_Line14|EXTI_Line15;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
EXTI_InitStruct.EXTI_Line=EXTI_Line5|EXTI_Line6;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStrcut.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_InitStrcut.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStrcut.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStrcut.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStrcut);
NVIC_InitStrcut.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStrcut.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStrcut.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStrcut.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStrcut);
}
void EXTI15_10_IRQHandler()
{
delay_ms(20);
if(EXTI_GetITStatus(EXTI_Line14))//K1被按下(K1为GPIOC的P14引脚)K1用于加阈值
{
if(menu==0)//当前OLED界面为显示温湿度数值的界面
flag++;//此标志位为标志温度阈值,flag++则表示阈值加一
else Smokeflag++;//当当前OLED界面显示的是烟雾传感器的值且K1被按下时,则增加的是烟雾的阈值
printf("11");
EXTI_ClearITPendingBit(EXTI_Line14);
}
if(EXTI_GetITStatus(EXTI_Line15))//K2被按下(K2为GPIOC的P15引脚)K2用于减阈值
{
if(menu==0)//当前OLED界面为显示烟雾数值的界面
flag--;//flag++则表示阈值减一
else Smokeflag--;//当当前OLED界面显示的是烟雾传感器的值且K1被按下时,则减少的是烟雾的阈值
EXTI_ClearITPendingBit(EXTI_Line15);
}
}
void EXTI9_5_IRQHandler()
{
delay_ms(20);
if(EXTI_GetITStatus(EXTI_Line5))//PB5即K3,K3被按下表示温度阈值确定设置为此值
{
if(temp==0)//temp此时初始化为0
temp=1;//标志位置1,temp=1则表示设置为当前选定的温度阈值
else temp=0;//当要重新设置阈值时,temp=0,表示设置为此温度阈值
EXTI_ClearITPendingBit(EXTI_Line5);
}
if(EXTI_GetITStatus(EXTI_Line6))//K0即PB6切换界面
{
if(menu==1)//切换到温湿度界面
menu=0;
else menu=1;
EXTI_ClearITPendingBit(EXTI_Line6);
}
}
key_exit.h
#ifndef __key_exit_H
#define __key_exit_H
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"
void key_exit_Init();
#endif
main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "DHT.h"
#include "OLED.h"
#include "MQ.h"
#include "usart2.h"
#include "key_exit.h"
#include "MQ_fire_in.h"
extern uint16_t Get_adcValue;
float Get_daValue=0;
extern float tureValue;
extern uint16_t buff;
extern uint16_t data[2];
extern uint16_t usart2_RX;
extern uint8_t OLED_yuzhiF8x16[][28];
extern uint8_t OLED_zhaohuoF8x16[][28];
extern uint8_t OLED_keranqitiF14x16[][28];
extern uint8_t OLED_keranqiyuzhiF14x16[][28];
extern uint8_t OLED_CurrentF14x16[][28];
extern uint8_t OLED_SetyuzhiF14x16[][28];
extern uint8_t OLED_Chargeyuzhi[][28];
extern uint16_t menu;
extern uint16_t flag;
extern uint16_t temp;
extern uint16_t Smokeflag;
u8 t[5]={0};
uint16_t Value=0;
//uint16_t Flag=29;
//uint16_t temp=29;
float SmokeValue=0;
int main(void)
{
u8 t[5]=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
OLED_Init();
Dht11_Init();
MQ_Init();
usart2_DMA_Init(9600);
key_exit_Init();
MQ_fire_Init();
while(1)
{
MQ
Get_daValue=data[1]*99/4096;
printf("%f\r\n",Get_daValue);
//温湿度
// printf("%d\r\n",Mcu_Control_Dht11(t));
Mcu_Control_Dht11(t);
// printf("湿度%d.%d\r\n",t[0],t[1]);
// printf("温度%d.%d\r\n",t[2]),t[3];
Show_Chain_wenshi(1,1,0);
Show_Chain_wenshi(1,2,1);
OLED_ShowNum(1,5,t[0],2);
Show_Chain_wenshi(2,1,2);
Show_Chain_wenshi(2,2,3);
OLED_ShowNum(2,5,t[2],2);
Show_Chain(3,1,OLED_yuzhiF8x16,4);
OLED_ShowNum(3,8,flag,2);
if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1))//检测着火了输出0
{
while(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1))
{
OLED_Clear();
Show_Chain(1,1,OLED_zhaohuoF8x16,3);
printf("着火了");
}
}
printf("%f\r\n",(tureValue/4096*3.3)*210+10);
if(temp==1)
{
Value=flag;
if(t[2]>Value)
{
OLED_Clear();
Show_Chain_weixian(1,1,0);
Show_Chain_weixian(1,2,1);
Mcu_Control_Dht11(t);
Show_Chain_wenshi(2,1,0);
Show_Chain_wenshi(2,2,1);
OLED_ShowNum(2,5,t[2],2);
OLED_ShowNum(3,1,Value,2);
delay_ms(100000);
OLED_Clear();
while(t[2]>Value)//实际温度超过阈值
{
while(temp==1)//重新设置阈值
{
Mcu_Control_Dht11(t);
Show_Chain(1,1,OLED_CurrentF14x16,5);
OLED_ShowNum(1,10,t[2],2);
Show_Chain(2,1,OLED_SetyuzhiF14x16,9);
OLED_ShowNum(3,1,flag,2);
Value=flag;
}
Mcu_Control_Dht11(t);
if(t[2]>Value)//实际的温度还是超过了刚才设置的阈值,会提示重新设置阈值
{
temp=1;//便于重新进入while(temp==1)里
OLED_Clear();
Show_Chain(1,1,OLED_Chargeyuzhi,12);
delay_ms(100000);
}
OLED_Clear();
}
// Mcu_Control_Dht11(t);
// OLED_Clear();
}
}
if(menu==1)//切换到烟雾界面
{
OLED_Clear();
while(menu==1)
{
Show_Chain(1,1,OLED_keranqitiF14x16,4);
Show_Chain(3,1,OLED_keranqiyuzhiF14x16,5);
SmokeValue=(tureValue/4096*3.3)*210+10;
OLED_ShowFNum(2,1,SmokeValue);
OLED_ShowNum(3,10,Smokeflag,3);
if(SmokeValue>Smokeflag)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
}
OLED_Clear();
}
}
}