MQ-2烟雾传感器模块功能实现(STM32)

news2025/1/17 6:01:39

认识MQ-2模块与其工作原理

        MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。当处于200~300摄氏度时,二氧化锡吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当与烟雾接触时,如果晶粒间界处的势垒收到烟雾的调至而变化,就会引起表面导电率的变化。利用这一点就可以获得这种烟雾存在的信息,烟雾的浓度越大,导电率越大,输出电阻越低,则输出的模拟信号就越大,与MQ-7类似。

        与MQ-7一样,MQ-2一共有4个引脚,分别是GND、DOUT、AOUT和VCC。VCC是电源引脚,用于给模块供电,可以理解为正极,一般接3.3V或者5V。GND连接模块的地线,可以理解为是负极,通常是0V。DOUT是数字输出引脚,用于输出数字信号。AOUT是模拟输出引脚,用于输出模拟信号。我们一般使用AOUT引脚也就是读取模块输出的模拟信号。

        32单片机可以通过模数转换器(ADC)读取传感器输出的模拟电压信号,而我们需要做的则是根据传感器特性曲线函数将电压值转换为烟雾浓度值。

MQ-2传感器特性曲线

        如图,假如说要测量CH4的ppm, 则可以取对应的坐标点,然后作成函数。

CH4_ppm20050080010001100
Rs/Ro32.21.91.81.4

模块与32单片机的连接

        这里我使用的单片机型号为STM32F407ze,上面也说过,要获得MQ-2测量的数据就要使用模数转换器(ADC),所以需要选择具有ADC功能的引脚,哪一个引脚拥有ADC功能可以通过查阅单片机的资料可知。

        通过查阅资料,我选择具有ADC功能的PA4引脚,PA4与CAMERA的第5引脚相连,所以只需要将MQ-7的AOUT引脚通过杜邦线接到CAMERA的第5引脚即可。剩下的就是接电源线了,随便找两个满足要求的引脚即可。

 具有ADC功能的引脚

 硬件连接

代码功能实现

        本次使用MQ-2传感器监测CH4的浓度。32单片机通过ADC(模数转换器)读取MQ-2传感器输出的模拟电压信号。首先可以先获取ADC在一定时间内的平均值,其次,可以利用公式将ADC的平均值转化为MQ-2的输出电压值,接着根据这个电压信号和传感器特性曲线(即上图中的带黄色三角形的折线)计算出CH4的浓度。例如,定义Smog_Get_Vol()函数用于读取MQ-2传感器的电压值。它使用了STM32的ADC模块来获取模拟信号,并将其转换为数字值。接着,函数将模拟电压值转换为数字值,并将其除以4096.0,以获得0到3.3V范围内的电压值。最后,函数返回电压值,该值与CH4的浓度成正比。然后再定义Smog_GetPPM()函数用于计算MQ-2传感器检测到的CH4浓度。在这个函数里先通过调用Smog_Get_Vol()函数来获取MQ-2传感器的电压值。然后,计算MQ-2传感器的电阻值(RS),该值基于传感器的电压值和电路中的电阻值。在这里,电路中的电阻值(RL)和空气中的CH4浓度下MQ-2传感器的电阻值(R0)是预先确定的常量。最后,该函数计算CH4的浓度(ppm),并返回该值。

模块部分

        本次将ADC部分代码与MQ-2融合到一起写:

        MQ2.c

#include "mq2.h"

#define CAL_PPM  10  // 校准环境中PPM值
#define RL	     10  // RL阻值
#define R0	     26  // R0阻值


void MQ2_Init(void)
{
	GPIO_InitTypeDef      GPIO_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_InitTypeDef       ADC_InitStructure;
	
	/* 引脚和ADC的时钟使能 */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	/* 配置引脚为模拟功能模式 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;		//模拟功能模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/* ADC的常规配置 */
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;		//独立模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;		//84MHz/2 = 42MHz
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	//禁止MDA
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;	//ADC通道采用间隔
	ADC_CommonInit(&ADC_CommonInitStructure);

	/* ADC1 初始化 ****************************************************************/
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;		//分辨率
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;				//禁止扫描			
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;			//连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//不需要外部触发
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;		//数据右对齐
	ADC_InitStructure.ADC_NbrOfConversion = 1;					//一次转换
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//ADC1的采样通道4放入规则通道1中
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_3Cycles);

	/* 使能 ADC1 */
	ADC_Cmd(ADC1, ENABLE);
}

uint32_t MQ2_ADC_Read(void)
{
	/* 启动软件触发检测 */ 
	ADC_SoftwareStartConv(ADC1);
	
	//等待转换结束
	while( ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	
	return ADC_GetConversionValue(ADC1);
}

//计算平均值
u16 ADC1_Average_Data(u8 ADC_Channel)
{
	u16 temp_val=0;
	u8 t;
	for(t=0;t<SMOG_READ_TIMES;t++)	//#define SMOG_READ_TIMES	10	定义烟雾传感器读取次数,读这么多次,然后取平均值

	{
		temp_val+=MQ2_ADC_Read();	//读取ADC值
		delay_ms(5);
	}
	temp_val/=SMOG_READ_TIMES;//得到平均值
    return (u16)temp_val;//返回算出的ADC平均值
}

//读取MQ7传感器的电压值
float Smog_Get_Vol(void)
{
	u16 adc_value = 0;//这是从MQ-7传感器模块电压输出的ADC转换中获得的原始数字值,该值的范围为0到4095,将模拟电压表示为数字值
	float voltage = 0;//MQ-7传感器模块的电压输出,与一氧化碳的浓度成正比
	
	adc_value = ADC1_Average_Data(ADC_Channel_4);//#define SMOG_ADC_CHX	ADC_Channel_4	定义烟雾传感器所在的ADC通道编号
	delay_ms(5);
	
    voltage  = (3.3/4096.0)*(adc_value);
	
	return voltage;
}
/*********************
// 传感器校准函数,根据当前环境PPM值与测得的RS电压值,反推出R0值。
// 在空气中运行过后测出R0为26
float MQ7_PPM_Calibration()
{
	float RS = 0;
	float R0 = 0;
	RS = (3.3f - Smog_Get_Vol()) / Smog_Get_Vol() * RL;//RL	10  // RL阻值
	R0 = RS / pow(CAL_PPM / 98.322, 1 / -1.458f);//CAL_PPM  10  // 校准环境中PPM值
	return R0;
}
**********************/

// 计算Smog_ppm
float Smog_GetPPM()
{
	float RS = (3.3f - Smog_Get_Vol()) / Smog_Get_Vol() * RL;
	float ppm = 98.322f * pow(RS/R0, -1.458f);
	return  ppm;
}

        mq2.h

#ifndef _MQ2_H
#define _MQ2_H

//C文件中需要的其他的头文件
#include <stm32f4xx.h>
#include "sys.h"
#include "delay.h"
#include "math.h"

#define SMOG_READ_TIMES	10				//定义烟雾传感器读取次数,读这么多次,然后取平均值

//C文件中定义的函数的声明
void MQ2_Init(void);
float Smog_Get_Vol(void);	//读取MQ7传感器的电压值
//float MQ7_PPM_Calibration(void);
float Smog_GetPPM(void);

#endif

主函数部分

        main.c

#include <stm32f4xx.h>
#include "sys.h"
#include <stdio.h>
#include "delay.h"
#include "uart.h"
#include "mq7.h"

//重定向fputc函数
int fputc(int ch, FILE *F)
{
	//通过串口1发送数据到PC
	USART_SendData(USART1, ch);
	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送数据完毕
	
	return ch;
}

u8 Smog_yu = 30;//CO的阈值	

int main(void)
{
	float Smog_ppm = 0;
	
	//确定系统定时器的工作频率  内核的工作频率/8 = 168MHz/8 = 21MHz
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	
	UART1_Config();//配置串口
	
	MQ2_Init();
	
	
	while(1)
	{
		Smog_ppm = Smog_GetPPM();
		
		printf("烟雾浓度:%.3f  烟雾阈值:%d\n",Smog_ppm, Smog_yu);
		
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387273.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言复习】C语言中的数组与指针

数组与指针复习写在前面数组和指针指针基础概念进阶知识指针的分类指针和数组笔试题写在前面 数组和指针小节&#xff0c;主要分为以下关键点&#xff1a; 常见指针分类&#xff0c;如指针数组、数组指针、函数指针等。什么是数组/ 指针有关数组和指针的题目数组传参 我们也…

写字楼/园区/购物中心空置率太高?快用快鲸智慧楼宇系统

客户租不租你的写字楼&#xff0c;事关区位、交通、环境、价格、面积、装修等诸多因素&#xff0c;但很多招商部对这些影响客户决策的数据并不重视&#xff0c;在客户初次上门看房时仅简单记录姓名、联系方式、需求面积&#xff0c;对其他核心数据熟视无睹&#xff0c;也为日后…

第十三届蓝桥杯

这里写目录标题一、刷题统计&#xff08;ceil函数返回的是等值于某最小整数的浮点值&#xff0c;不强制转换回int就wa&#xff0c;没错就连和int整数相加都wa二、修剪灌木&#xff08;主要应看清楚会调转方向三、统计子矩阵&#xff08;前缀和滑动窗口⭐&#xff09;四、[积木画…

【算法】笔记:LeetCode 206. 反转链表

文章目录前言思考问题&#xff1a;把分开的节点连在一起结合原题&#xff1a;使用[迭代]解决卡点引入新指针边界条件代码反转的逻辑代码&#xff08;完整答案&#xff09;结合原题&#xff1a;使用[递归]解决卡点完整代码问题的子问题当前层要干什么递归出口前言 这道题可以拆…

冰箱压缩机 方案

压缩机是制冷系统的心脏&#xff0c;它从吸气管吸入低温低压的制冷剂气体&#xff0c;通过电机运转带动活塞对其进行压缩后&#xff0c;向排气管排出高温高压的制冷剂气体&#xff0c;为制冷循环提供动力&#xff0c;从而实现压缩→冷凝→膨胀→蒸发 ( 吸热 ) 的制冷循环。压缩…

C#开发的OpenRA的游戏主界面怎么样创建

通过前面加载界面布局数据,可以把整个界面逻辑的数据加载到内存, 但是这些数据怎么显示出来,又是没有定义的。比如前面定义了多个界面的布局, 又是怎么样知道需要显示哪一个界面? 现在就来解决这个问题,其实整个游戏都是可以通过yaml文件进行配置的, 所以我们需要从yaml…

水果FLStudio21.0.0中文版全能数字音乐工作站DAW

FL Studio 21.0.0官方中文版重磅发布纯正简体中文支持&#xff0c;更快捷的音频剪辑及素材管理器&#xff0c;多样主题随心换&#xff01;Mac版新增对苹果M2/1家族芯片原生支持。编曲、剪辑、录音、混音&#xff0c;20余年的技术积淀和实力研发&#xff0c;FL Studio 已经从电音…

【基础算法】单链表的OJ练习(3) # 移除链表元素 # 相交链表 #

文章目录前言移除链表元素相交链表写在最后前言 本章的OJ练习也是相对简单的&#xff0c;只要能够理解解题的思路&#xff0c;并且依照这个思路能够快速的写出代码&#xff0c;我相信&#xff0c;你的链表水平已经足够了。 对于OJ练习&#xff08;2&#xff09; : ->传送门…

不平凡的一天——

作者&#xff1a;指针不指南吗 专栏&#xff1a;个人日常记录 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录1.自我介绍2.上学期3.不凡的一天4.新学期写个博客&#xff0c;简单记录一下&#xff0c;新学期加油&#xff01;&#xff01;&#xff…

day7 同步互斥

作业 1.将一个文件中的数据打印到终端上类似cat一个文件&#xff0c;要求如下 &#xff08;1&#xff09;a线程读取文件中的数据 &#xff08;2&#xff09;B线程将A线程读取到的数据打印到终端上 &#xff08;3&#xff09;文件打印完毕后&#xff0c;结束进程 方法1&#…

CMMI流程规范—服务与维护

服务与维护&#xff08;Service and Maintenance, SM&#xff09;是指产品销售之后的客户服务和产品维护。客户服务和产品维护的宗旨就是提高客户对产品以及对开发方的满意度。服务与维护过程域是SPP模型的重要组成部分。本规范阐述了服务与维护过程域的两个主要规程&#xff1…

蓝库云|五大关键引领制造业数字化智慧升级

蓝库云根据《2023制造产业趋势展望》报告&#xff0c;并归纳出「强化企业韧性与敏捷、提升留才诱因、建构多元供应链、兼顾安全的智慧工厂、循环催化永续经营」是牵动制造产业发展的五大关键。将永续目标整合至企业中长期策略中&#xff1b;数字化方面则搭配五大发展关键&#…

【Redis应用】基于Redis实现共享session登录(一)

&#x1f697;Redis应用学习第一站~ &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 &#x1f44d;希望您能有所收获 &#x1f449;相关推荐&#xff1a;使用短信服务发送手机验证码进行安全校验 一.引入 ​ 在开发项目过程中&#xff0c;我们常常能碰到需要登录注…

Linux操作系统学习(文件IO)

文章目录基础IO系统相关接口文件描述符一切皆文件文件描述符的分配规则重定向fork后的文件描述符基础IO 系统相关接口 在C语言中对文件的操作有fopen打开、fclose关闭、fread读、fwrite写等函数&#xff1b;其实这些都是在系统调用接口上进行的封装。 这里介绍4个系统调用接…

【异常】因多租户字段缺少导致Error updating database. Column ‘tenant_id‘ cannot be null

一、报错内容 org.springframework.dao.DataIntegrityViolationException: ### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column tenant_id cannot be null ### The error may exist in com/xxx/cloud/mall/admin/mapper/Goods…

303. 区域和检索 - 数组不可变

303. 区域和检索 - 数组不可变 给定一个整数数组 nums&#xff0c;处理以下类型的多个查询: 计算索引 left 和 right &#xff08;包含 left 和 right&#xff09;之间的 nums 元素的 和 &#xff0c;其中 left < right 实现 NumArray 类&#xff1a; NumArray(int[] num…

英语六级的三大经典句型

目录 1.强调句型&#xff08;提前想好要写在哪个地方&#xff09; 2.虚拟语气 3.第三个句型 3.倒装&#xff08;写一到两个倒装&#xff09; &#xff08;1&#xff09;否定词放在句首就是倒装 &#xff08;2&#xff09;so...that句型结构的句子将so引导的部分置于句首时…

一、一篇文章打好高数基础-函数

1.连续函数的性质考点分析函数的连续性主要考察函数的奇偶性、有界性、单调性、周期性。例题判断函数的奇偶性的有界区间为&#xff08;&#xff09; A.(-1,0) B(0,1) C(1,2) D(2,3)2.闭区间上连续函数的性质考点分析闭区间上连续函数的性质主要考察函数的最大最小值定理、零点…

JavaScript 函数参数

JavaScript 函数对参数的值(arguments)没有进行任何的检查。JavaScript 函数参数与大多数其他语言的函数参数的区别在于&#xff1a;它不会关注有多少个参数被传递&#xff0c;不关注传递的参数的数据类型。函数显式参数与隐藏参数(arguments)在先前的教程中&#xff0c;我们已…

删除启动台(LaunchPad)残留的图标

忘记什么版本的时候以前在 “应用程序” 删除应用后&#xff0c;启动台自动更新删掉 不知道什么时候开始&#xff0c;直接在 “应用程序” 里删掉后&#xff0c;启动台居然不能删除了…… 10.13和10.14后&#xff0c;无论是按住 Option&#xff0c;还是按住 Control Option …