MQ2烟雾传感器 完整代码!!

 

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

 运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值