STM32读取MQ2烟雾浓度数据判断烟雾是否超标

news2024/12/29 10:43:42

【1】MQ2传感器是什么?

MQ2传感器是一种可探测多种气体的传感器,常用于监测烟雾、液化气、丙酮、乙醇、甲醛、天然气等有害气体。MQ2传感器基于半导体敏感元件,通过检测气体中有害物质的浓度变化来实现气体检测。
在这里插入图片描述

MQ2传感器具有以下特点:

  • 可靠性高:采用优质半导体敏感元件,响应速度快、灵敏度高。
  • 响应时间快:在检测到有害气体时能够立即发出警报。
  • 易于集成:小巧轻便,易于安装和集成到各种设备中。
  • 价格低廉:相对于其他气体检测传感器,MQ2传感器的价格较为低廉。

MQ2传感器广泛应用于家庭、工业、医疗、环保等领域,帮助人们实时监测气体浓度,保障生命健康和财产安全。

【2】MQ2传感器浓度如何转换?

MQ2传感器的电压输出值可以通过ADC进行采集。MQ2传感器检测到烟雾等有害气体时,其敏感材料的电阻值会发生变化,从而导致输出电压值的变化。因此,可以通过采集MQ2传感器的输出电压值来判断烟雾浓度。

MQ2传感器的输出电压与烟雾浓度之间的关系是线性的,需要进行一定的转换才能得出准确的烟雾浓度。

常见的转换方法如下:

(1)标定法

将MQ2传感器置于标准烟雾环境中,记录其输出电压值和对应的烟雾浓度,并建立二者之间的关系模型。然后再使用这个模型将采集到的MQ2传感器输出电压值转换为相应的烟雾浓度。该方法测量精度较高,但需要专业仪器作为标准烟雾环境。

(2)经验公式法

根据经验统计,MQ2传感器的电压输出值与实际烟雾浓度之间呈现出某种函数关系。通过实验数据拟合出该函数关系,就可以将MQ2传感器的电压输出值直接转换为烟雾浓度。该方法需要进行多次实验,并对数据进行处理和拟合,相对较为复杂。

(3)查表法

通过实验得到一系列MQ2传感器输出电压值与对应烟雾浓度的关系数据,形成一张转换表格。在实际使用过程中,将采集到的MQ2传感器输出电压值查表后即可得到相应的烟雾浓度。该方法简单易行,但需要大量实验数据作为基础。

【3】STM32采集MQ2烟雾浓度(标准库)

#include "stm32f10x.h"
#include <stdio.h>

int main(void)
{
    // 初始化ADC
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    // 配置ADC通道1的GPIO引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 启动ADC校准
    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));

    // 读取ADC值
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_28Cycles5);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    uint16_t adc_value = ADC_GetConversionValue(ADC1);

    // 计算烟雾浓度
    float voltage = (float)adc_value / 4096.0f * 3.3f;
    float density = (voltage - 0.4f) / 0.4f * 10000.0f;

    // 打印出烟雾浓度
    printf("MQ2 Smoke Density: %.2f ppm\n", density);
}




float adc_average() 
{
    const int num_discarded = 3;  // 剔除的最大/最小值数量
    float samples[20];   // 存储采样结果的数组
    
    // 采集数据
    for (int i = 0; i < num_samples; i++) {
        samples[i] = ADC_GET();
    }
    
    // 对采样结果进行排序(升序)
    for (int i = 0; i < num_samples - 1; i++) {
        for (int j = i + 1; j < num_samples; j++) {
            if (samples[i] > samples[j]) {
                float temp = samples[i];
                samples[i] = samples[j];
                samples[j] = temp;
            }
        }
    }
    
    // 计算剩下的平均值
    float sum = 0;
    for (int i = num_discarded; i < num_samples - num_discarded; i++) {
        sum += samples[i];
    }
    return sum / (num_samples - 2 * num_discarded);  // 返回计算结果
}

【4】STM32采集MQ2烟雾浓度(HAL库)

以下是一个基于STM32F103C8T6和MQ2传感器的示例代码,它可以采集MQ2的烟雾浓度并通过串口打印出来。请注意,此示例使用了HAL库和CubeMX配置工具。

#include "main.h"
#include "stdio.h"
#include "string.h"

ADC_HandleTypeDef hadc1;
UART_HandleTypeDef huart1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART1_UART_Init(void);

float SmokeDensity;

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();

  while (1)
  {
    // 启动ADC转换
    HAL_ADC_Start(&hadc1);
    // 等待转换完成
    HAL_ADC_PollForConversion(&hadc1, 100);
    // 获取ADC转换结果
    uint16_t adc_value = HAL_ADC_GetValue(&hadc1);

    // 将ADC转换结果转换为烟雾浓度
    SmokeDensity = (float)adc_value / 4095 * 100;

    // 将数据打印到串口
    char msg[50];
    sprintf(msg, "Smoke density: %.2f%%\n", SmokeDensity);
    HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 1000);

    // 延迟一段时间再次采集
    HAL_Delay(5000);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_ADC1_Init(void) 
{
	ADC_ChannelConfTypeDef sConfig = {0};
	/** Common config 
  */
	hadc1.Instance = ADC1;
	hadc1.Init.ScanConvMode = DISABLE;
	hadc1.Init.ContinuousConvMode = ENABLE;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc1.Init.NbrOfConversion = 1;
	if (HAL_ADC_Init(&hadc1) != HAL_OK) 
	{
		Error_Handler();
	}
	/** Configure Regular Channel 
  */
	sConfig.Channel = ADC_CHANNEL_1;
	sConfig.Rank = ADC_REGULAR_RANK_1;
	sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) 
	{
		Error_Handler();
	}
}
static void MX_USART1_UART_Init(void) 
{
	huart1.Instance = USART1;
	huart1.Init.BaudRate = 115200;
	huart1.Init.WordLength = UART_WORDLENGTH_8B;
	huart1.Init.StopBits = UART_STOPBITS_1;
	huart1.Init
	  .Parity = UART_PARITY_NONE;
	huart1.Init.Mode = UART_MODE_TX_RX;
	huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	huart1.Init.OverSampling = UART_OVERSAMPLING_16;
	if (HAL_UART_Init(&huart1) != HAL_OK) 
	{
		Error_Handler();
	}
}
static void MX_GPIO_Init(void) 
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOA_CLK_ENABLE();
	/*Configure GPIO pin : PA1 */
	GPIO_InitStruct.Pin = GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Error_Handler(void) 
{
	while(1);
}
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line) 
{
}
#endif

在此示例代码中,PA1被配置成了模拟输入通道,并在ADC采样时使用。通过将采集到的ADC值转换为烟雾浓度并打印出来,可以实现对MQ2传感器的烟雾检测。

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

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

相关文章

Python的self作用,以及__init__,__new__

本章来探讨一下Python类的self作用&#xff0c;以及__init__,__new__。 为什么是探讨&#xff0c;不是学习&#xff0c;因为菜&#x1f40e;&#xff1b; 先看个例子&#xff1a; class Example:def animal(self):self.dog "大黄"def Dog(self):print(self.dog)if _…

【前端 - CSS】第 10 课 - CSS 引入方式

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、CSS 引入方式 2.1、内部样式表 2.2、外部样式表 2.3、行内样式 3、总结 1、缘起 要想在 HTML 代码中写入 CSS 代…

English Learning - L3 作业打卡 Lesson5 Day33 2023.6.6 周二

English Learning - L3 作业打卡 Lesson5 Day33 2023.6.6 周二 引言&#x1f349;句1: And theres a student reading an English textbook.成分划分弱读连读语调 &#x1f349;句2: What do their choices say about them?成分划分连读爆破语调 &#x1f349;句3: Do you jud…

nodejs+vue+Express论坛网站34t91

本论坛网站有管理员&#xff0c;用户&#xff0c;普通管理员。管理员功能有个人中心&#xff0c;用户管理&#xff0c;普通管理员管理&#xff0c;论坛类别管理&#xff0c;交流论坛管理&#xff0c;系统管理等。用户功能有个人中心&#xff0c;交流论坛管理&#xff0c;我的收…

华为OD机试真题 JavaScript 实现【水仙花数】【2022Q4 100分】

一、题目描述 所谓水仙花数&#xff0c;是指一个n位的正整数&#xff0c;其各位数字的n次方和等于该数本身。 例如153是水仙花数&#xff0c;153是一个3位数&#xff0c;并且153 1^3 5^3 3^3。 二、输入描述 第一行输入一个整数n&#xff0c;表示一个n位的正整数。n在3到…

单容水箱建模(自衡单容水箱+无自衡单容水箱)

自衡单容水箱Simulink建模和PLC源代码请参看下面文章链接: 单容双容水箱建模(simulink仿真+PLC代码)_RXXW_Dor的博客-CSDN博客PLC通过伯努利方程近似计算水箱流量详细内容请参看下面的文章博客PLC通过伯努利方程近似计算水箱流量(FC)_怎么用伯努利方程求某水位流量_RXXW_Dor的…

基础汇编语言编程

目录 什么是汇编语言&#xff1f; 工程搭建 新建工程 环境设置 测试是否成功 正式学习汇编语言 数据处理指令 填充&#xff0c;加&#xff0c;减&#xff0c;乘 思考&#xff1a;我们可以看到R0寄存器可以存放8位十六进制数&#xff0c;那么0x12345678能不能用mov存入&am…

java SSM 摄影作品网站myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 摄影作品网站系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

会用Python做副业的人,有多豪横!

前两天一个朋友找到我吐槽&#xff0c;说工资一发交完房租水电&#xff0c;啥也不剩&#xff0c;搞不懂朋友圈里那些天天吃喝玩乐的同龄人钱都是哪来的&#xff1f; 确实如此&#xff0c;刚毕业的大学生工资起薪都很低&#xff0c;在高消费、高租金的城市&#xff0c;别说存钱…

浏览器跨域请求

跨域是浏览器的一种同源策略&#xff0c;所以该概念只存在于通过浏览器访问服务里。 如果缺少了同源策略&#xff0c;则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的&#xff0c;浏览器只是针对同源策略的一种实现 请求的url地址,必须与浏览器上的…

Vue3 ElementPlus Dialog封装 (二:使用provide inject)

引言 上一章Vue3 ElementPlus Dialog封装 &#xff08;一&#xff1a;使用props emit&#xff09; propemit实现的方法用于父子组件比较方便, 跨多层次组件比较麻烦 vue3 中 还提供了provide和inject方法供组件间通信(参考官网图片), 本篇使用该方法实现上章效果 实现原理 参考…

K8S之Ingress 对外暴露应用(十四)

• Ingress为弥补NodePort不足而生 • Pod与Ingress的关系 • Ingress Controller • Ingress 规则配置 一&#xff0c;Ingress为弥补NodePort不足而生 NodePort存在的不足&#xff1a; • 一个端口只能一个服务使用&#xff0c;端口需提前规划 • 只支持4层负载均衡二&#x…

九耶丨阁瑞钛伦特-大型计算机硬件组成(二)

TSO&#xff1a; TSO是Time Sharing Option的缩写&#xff0c;用户可以通过TSO命令和系统进行交互式工作。TSO命令直接使用并不方便&#xff0c;所以IBM又在TSO下开发了程序产品ISPF/PDF&#xff08;Interactive System Productivity/Program Development Facility)其中ISPF支…

VAPS XT4.2 与 VS2013 安装

VAPS XT4.2 与 VS2013 安装 安装顺序 安装 VS2013安装 License tool安装 VAPS XT4.2VS2013 的安装 安装 VS2013,安装内容全选,安装路径选择D盘;VS2013 激活,网上找密钥,比如:【BWG7X-J98B3-W34RT-33B3R-JVYW9】;电脑重启;Win+R,sysdm.cpl,打开环境变量,查看VS相关的…

Linux SSH命令实战教程,提升你的服务器管理基本功!

前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文是专栏【linux基本功-基础命令实战】的第62篇文章。 专栏地址&#xff1a;[linux基本功-基础命令专栏] &#xff0c; 此专栏是沐风晓月对Linux常用命令的汇总&#xff0c;希望能够加深自己的印象&am…

java生成、识别条形码和二维码

一、概述 使用 zxing 开源库 Zxing主要是Google出品的&#xff0c;用于识别一维码和二维码的第三方库主要类:BitMatrix 位图矩阵MultiFormatWriter 位图编写器MatrixToImageWriter 写入图片 可以生成、识别条形码和二维码 内置三种尺寸&#xff1a;enum Size {SMALL, MIDDLE, …

【习题】习题 2 - 编写程序求当前机器的字节序

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、字节序影响 3、示例代码 4、总结 1、缘起 在计算机中&#xff0c;字节序&#xff08;Byte Order&#xff09;指定了…

一文带你彻底掌握Java 中的Stream流(详细)

本文目录 学习目标中间操作Filter(过滤)Map(转换)Sorted(排序)Distinct(去重)Limit(限制)Skip(跳过)Peek(展示) 终止操作forEach(循环)Collect(收集)Count(计数)Reduce(聚合)AnyMatch(任意匹配)AllMatch(全部匹配)NoneMatch(无匹配) 使用Stream流的优缺点&#xff1a;优点&…

投票活动小程序开发搭建

由于小程序是基于微信开发者工具编写的&#xff0c;因此我先介绍一下需要使用的工具和技术&#xff1a; - 微信开发者工具&#xff1a;用于开发、调试和发布小程序。 - 小程序云开发&#xff1a;用于存储数据和进行后端逻辑处理。 - uni-app框架&#xff1a;uni-app 是一个使…

组件更新的底层逻辑

第一种更新&#xff1a;组件更新的逻辑&#xff0c;当修改了相关状态&#xff0c;组件会更新 1.触发shouldComponentUpdate 周期函数:是否允许更新 shouldComponentUpdate(nextProps, nextState) { // nextState: 存储要修改的最新状态 // this. state:存储的还是修改前的状态…