MQ2工作原理:MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。处于2000~3000摄氏度时,二氧化锡表面吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当烟雾颗粒进入传感器时,他们会与敏感元件表明的金属氧化物(如二氧化锡发生化学反应)。这种反应会改变晶粒间的势垒,进而引起表面导电率的变化。烟雾浓度增加,导电率也会增大,导致传感器的输出电阻降低。这种电阻的变化是传感器检测烟雾浓度的关键。
主要应用在于家庭跟工厂的气体泄漏监测装置,适宜于液化气、丁烷、丙烷、甲烷、酒精、氢气、烟雾等的探测
1. 烟雾检测
当可燃气体浓度小于指定的阈值时,DO输出高电平,大于指定的阈值时则输出低电平。
2. 阈值调节
模块中蓝色的电位器是用于调节阀值,顺时针旋转,阈值会越大,逆时针越小。
3. 使用AO接口
与DO不同,AO会输出模拟信号,因此需要与单片机的ADC采样通道连接。单片机可以通过此模拟信号来获取可燃气体浓度大小。
采集MQ2烟雾输出的电压换算位烟雾浓度0~100
RS:元件在不同气体,不同浓度下的电阻值。
R0:元件在接近空气下的电阻值
转换公式
ppm = 613.9f * pow(RS/R0, -2.074f)
ppm:为可燃气体的浓度。
VRL:电压输出值。
Rs:器件在不同气体,不同浓度下的电阻值。
R0:器件在洁净空气中的电阻值。
RL:负载电阻阻值。
ADC.C
#include "ADC.h"
#include "math.h"
#define CAL_PPM 20 // 校准环境中PPM值
#define RL 5 // RL阻值
static float R0; // 元件在洁净空气中的阻值
void Adc_Init(void)//初始化函数
{
GPIO_InitTypeDef GPIO_Initstructre;
ADC_InitTypeDef ADC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);//使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能io口
GPIO_Initstructre.GPIO_Mode=GPIO_Mode_AIN;
GPIO_Initstructre.GPIO_Pin=GPIO_Pin_2;
GPIO_Initstructre.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructre);
GPIO_SetBits(GPIOA,GPIO_Pin_3);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//保证不超过14M
ADC_DeInit(ADC1);//复位ADC1
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//不使能连续扫描
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//软件触发
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;//不使用扫描模式
ADC_Init(ADC1,&ADC_InitStruct);
ADC_Cmd(ADC1,ENABLE);//使能指定的ADC1
ADC_ResetCalibration(ADC1);//使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1);//开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}
u16 Get_Adc(u8 ch)
{
ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5);//ADC1,通道1,配置采集周期
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件复位
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//状态发生改变
return ADC_GetConversionValue(ADC1);//返回值
}
/********************************************
* 1.651428 200 *
* 1.437143 300 *
* 1.257143 400 *
* 1.137143 500 *
* 1 600 *
* 0.928704 700 *
* 0.871296 800 *
* 0.816667 900 *
* 0.785714 1000 *
* 0.574393 2000 *
* 0.466047 3000 *
* 0.415581 4000 *
* 0.370478 5000 *
* 0.337031 6000 *
* 0.305119 7000 *
* 0.288169 8000 *
* 0.272727 9000 *
* 0.254795 10000 *
* *
* ppm = 613.9f * pow(RS/RL, -2.074f) *
***************************************/
void MQ2_cumlate(float RS)
{
R0 = RS / pow(CAL_PPM / 613.9f, 1 / -2.074f);
}
float MQ2_GetPPM(void)
{
u16 adcx;
adcx=Get_Adc_Average(ADC_Channel_2,30);//ADC1,取30次的平均值
float Vrl = 3.3f * adcx / 4096.f;//3.3v的参考电压,4096份
Vrl = ( (float)( (int)( (Vrl+0.005)*100 ) ) )/100;
float RS = (3.3f - Vrl) / Vrl * RL;
if(times<6) // 获取系统执行时间,3s前进行校准,用到了定时器
{
R0 = RS / pow(CAL_PPM / 613.9f, 1 / -2.074f);//校准R0
}
float ppm = 613.9f * pow(RS/R0, -2.074f);
return ppm;
}
u16 Get_Adc_Average(u8 ch,u8 times)//两个入口参数,通道,取平均值的次数
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
Delay_nopnms(5);
}
return temp_val/times;
}
time.c
#include "time.h"
uint16_t times = 0;
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSture;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//定时器3,时钟
TIM_TimeBaseInitSture.TIM_Period = arr;//自动装载值
TIM_TimeBaseInitSture.TIM_Prescaler = psc;//预分频系数
TIM_TimeBaseInitSture.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitSture.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitSture);//定时器3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//定时器3,更新中断,使能
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM3,ENABLE);
}
void TIM3_IRQHandler(void)//中断函数,0.5秒中断一次
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)//判断状态
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断待处理位
times++;
}
}
main
int main(void)
{
//此处代码只执行一次
LED_Config();
KEY_Config();
BEEP_Config();
// OLED_Config();
USART_Config(115200);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Adc_Init();
TIM3_Int_Init(5000,7200);
OLED_ShowString(0,1,"AD:");
while(1)
{
printf("AD值:%d\r\n",Get_Adc(2));
printf("烟雾浓度为:%.2f ppm\r\n", MQ2_GetPPM());//计算烟雾浓度并通过串口打印
Delay_nopnms(100);
}
}
运行结果