当前位置: 首页 > news >正文

MQ2烟雾传感器模块(第九天)

在这里插入图片描述


👨‍💻个人主页:@开发者-削好皮的Pineapple!

👨‍💻 hello 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 削好皮的Pineapple! 原创

👨‍💻 收录于专栏:C语言到基于STM32 的智能矿探小车


请添加图片描述

请添加图片描述

文章目录

    • 🎶一、MQ2模块基本介绍与引脚连接
      • 快速判断步骤
    • 🎶二、MQ2模块数据获取与处理
      • uart.c
      • uart.h
      • main.c
        • 结束语🥇


前言

  • 本文主要介绍MQ2烟雾传感器模块的相关知识,包括其引脚连接方式、数据获取方法以及如何将检测到的烟雾浓度值显示到手机蓝牙串口APP上,为智能矿探小车的烟雾检测功能实现提供基础。

🎶一、MQ2模块基本介绍与引脚连接


  • MQ2模块主要用于测量烟雾浓度,相关详细说明可参考《Z-MQ-01烟雾传感器使用说明书.pdf》。
  • 引脚连接方式如下:
    • VCC引脚连接至5V电源
    • GND引脚连接至地
    • TXD引脚连接至单片机的RXD(可选择USART1、USART2或USART3的RXD)
    • RXD引脚连接至单片机的TXD(可选择USART1、USART2或USART3的TXD)

在这里插入图片描述
在这里插入图片描述

区分维度模拟输出型MQ2串口输出型MQ2
引脚数量及标识通常4脚,包含VCC、GND、AO(核心)、DO(可选)通常4~6脚,包含VCC、GND、TX(发送)、RX(接收),可能有RESET、SET等
核心引脚作用AO输出05V或03.3V模拟电压(随烟雾浓度变化);DO输出高/低电平(阈值报警)TX和RX为串口通信核心引脚,用于数据收发
是否带串口芯片无,仅含MQ2气敏元件、电阻、电容等基础元件有,含CH340(常见)、CP2102、PL2303等串口转换芯片
尺寸较小,通常为2cm×2cm左右的小型电路板相对较大(因含额外芯片)
指示灯一般无特殊指示灯可能有PWR(电源灯)、TX(发送灯)、RX(接收灯),通信时TX/RX灯会闪烁

快速判断步骤

  1. 看引脚:有TX和RX → 串口型;只有AO/DO → 模拟输出型。
  2. 找芯片:有CH340/CP2102等串口芯片 → 串口型;无则为模拟输出型。

像我们今天所用的下面就有标识串口类型。


🎶二、MQ2模块数据获取与处理


  • 单片机若要获取MQ2模块的数据,需要通过串口(USART1、USART2或USART3)向MQ2发送一帧特定数据:FF 01 86 00 00 00 00 00 79
  • MQ2模块收到上述数据后,会反馈一帧数据,例如:FF 86 00 85 00 00 00 00 F5
  • 其中,反馈数据的第二字节和第三字节表示检测到的浓度值。以上述示例为例:
    • 第二个字节为0x00
    • 第三个字节为0x85
    • 计算检测到的浓度值(十进制)的方法为:0x00 << 8 | 0x85
  • 后续需将获取到的烟雾浓度值(十进制)通过蓝牙模块发送到手机的蓝牙串口APP上进行显示。
  • 串口2连接蓝牙,串口3连接MQ2。手机蓝牙APP发送S或s,收到烟雾浓度。

uart.c

#include "stm32f4xx.h"
#include "uart.h"
#include <stdio.h>// 全局变量定义
u8 recv; // USART2接收数据(命令指示)
u8 rdata; // USART3接收数据(MQ2传感器数据)
u8 mq2_response[9]; // 存储MQ2模块响应数据帧
u16 smoke_concentration; // 存储烟雾浓度值(百分比)
volatile uint8_t mq2_response_index = 0; // 记录MQ2响应帧索引
static uint8_t is_sending = 0; // 发送状态标志,防止数据冲突
uint8_t request_smoke_data = 0; // 请求烟雾数据标志// 向MQ2模块发送请求数据帧(固定帧)
void send_mq2_request(void) {int i;u8 request_data[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};for (i = 0; i < 9; i++) {while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);USART_SendData(USART3, request_data[i]);}
}// 解析MQ2数据接收逻辑,包括帧格式和校验位验证
void parse_mq2_response(void) {u8 checksum = 0;u16 raw_value;int i;// 1. 验证帧头格式,MQ2响应帧头为FF 86if (mq2_response[0] != 0xFF || mq2_response[1] != 0x86) {smoke_concentration = 0; // 帧格式错误,返回0return;}// 2. 计算校验和,确保数据有效性for (i = 0; i < 8; i++) {checksum += mq2_response[i];}checksum = 0xFF - (checksum % 0xFF);if (checksum != mq2_response[8]) {smoke_concentration = 0; // 校验失败,返回0return;}// 3. 提取有效数据,浓度值在第2和3字节raw_value = (mq2_response[2] << 8) | mq2_response[3]; // 合并字节// 4. 根据公式进行实际浓度转换if (raw_value > 5000) {smoke_concentration = 100;} else {smoke_concentration = (raw_value * 100) / 5000;}
}// 修改字符串发送逻辑,确保数据完整发送
void send_smoke_concentration_to_bluetooth(void) {char buffer[20];int i;uint32_t timeout;if (is_sending) return; // 避免冲突,直接退出is_sending = 1;// 格式化字符串,确保格式正确snprintf(buffer, sizeof(buffer), "Smoke: %d%%\n", smoke_concentration);// 暂时关闭串口接收中断,防止冲突USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);// 发送字符串,添加超时机制for (i = 0; buffer[i] != '\0'; i++) {timeout = 0;// 等待发送缓冲区为空,超时值设置为500000while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) {if (timeout++ > 500000) { // 简单的超时处理is_sending = 0;// 恢复中断并退出USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);return;}}USART_SendData(USART2, buffer[i]);}// 发送完成,恢复中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);is_sending = 0;
}// 串口初始化函数(固定帧)
void uart_init(int bond) {// 原始代码不变,确保USART2和USART3配置正确GPIO_InitTypeDef  GPIO_InitStruct;USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef  NVIC_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB1Periph_USART3, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;// USART2 (PA2=TX, PA3=RX)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;GPIO_Init(GPIOA, &GPIO_InitStruct);// USART3 (PB10=TX, PB11=RX)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);USART_InitStruct.USART_BaudRate = bond;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_InitStruct.USART_Parity = USART_Parity_No;USART_InitStruct.USART_StopBits = USART_StopBits_1;USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART2, &USART_InitStruct);USART_Init(USART3, &USART_InitStruct);USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;NVIC_Init(&NVIC_InitStruct);USART_Cmd(USART2, ENABLE);USART_Cmd(USART3, ENABLE);
}// 中断处理函数(固定帧)
void USART2_IRQHandler(void) {if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) {recv = USART_ReceiveData(USART2);USART_ClearITPendingBit(USART2, USART_IT_RXNE);// 检测特定指令触发烟雾浓度请求if (recv == 'S' || recv == 's') { // 当接收到 'S' 或 's' 时请求数据request_smoke_data = 1;}}
}void USART3_IRQHandler(void) {if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) {rdata = USART_ReceiveData(USART3);mq2_response[mq2_response_index++] = rdata;// 接收到9字节后开始处理if (mq2_response_index == 9) {mq2_response_index = 0;parse_mq2_response();send_smoke_concentration_to_bluetooth(); // 发送浓度数据request_smoke_data = 0; // 重置请求标志}USART_ClearITPendingBit(USART3, USART_IT_RXNE);}
}

uart.h

#ifndef __UART_H__
#define __UART_H__
#include "stm32f4xx.h"void uart_init(int bond);
void USART2_IRQHandler(void);
void USART3_IRQHandler(void);
void send_mq2_request(void);
void send_smoke_concentration_to_bluetooth(void);extern u8 recv;  // USART2接收数据(命令)
extern u8 rdata; // USART3接收数据(MQ2传感器数据)
extern uint8_t request_smoke_data; // 请求烟雾数据标志
#endif

main.c

#include "stm32f4xx.h"
#include "exit.h"
#include "car.h"
#include "delay.h"
#include "remote.h"
#include "uart.h"
#include "led.h"extern uint8_t request_smoke_data;int main(void) {SystemInit();car_init();remote_Init();delay_init();led_init();uart_init(9600); // 初始化串口,用于连接MQ2和蓝牙while(1) {// 当请求标志被设置时发送MQ2请求if (request_smoke_data) {send_mq2_request();// 等待一段时间以确保数据接收完成delay_ms(500);}}
}
结束语🥇

🔥 订阅专栏持续学习:C语言到基于STM32的智能矿探小车
💬 欢迎点赞、收藏、留言讨论,一起攻克嵌入式开发!

http://www.lryc.cn/news/588973.html

相关文章:

  • C++学习笔记五
  • 《时间简史》:窥探宇宙的奥秘
  • IOS 18下openURL 失效问题
  • 032_API参考文档
  • 前端面试专栏-工程化:25.项目亮点与技术难点梳理
  • 区块链的三种共识机制——PoW、PoS和DPoS原理
  • 数据库第二次作业
  • 【Python练习】044. 编写一个函数,实现快速排序算法
  • 本地电脑安装Dify|内网穿透到公网
  • 开源AI应用开发平台Dify系列(一)
  • YOLO融合CFFormer中的FeatureCorrection_s2c模块
  • 多租户SaaS系统中设计安全便捷的跨租户流程共享
  • 遥感数据与作物生长模型同化及在作物长势监测与估产中的应用
  • 弗兰肯斯坦式的人工智能与GTM策略的崩溃
  • 运维效率提升利器:grep、sed、awk详解与实战练习指南
  • (LeetCode 面试经典 150 题) 383. 赎金信 (哈希表)
  • AR眼镜:重塑医学教育,开启智能教学新时代
  • 配置使用SSH与VScode进行连接
  • dockerfile 最佳实践
  • 如何解决服务器频繁重启的问题?
  • 流媒体直播分发服务器
  • 基于深度学习的LSTM、GRU对大数据交通流量分析与预测的研究
  • Python初学者笔记第十二期 -- (集合与字典编程练习题)
  • 信息学奥赛一本通 1552:【例 1】点的距离
  • 短剧小程序的「技术革命」:从「粗放生长」到「精准运营」
  • MySQL中的“引擎“是什么意思
  • 【算法-BFS 解决最短路问题】探索BFS在图论中的应用:最短路径问题的高效解法
  • UnitTest测试框架的基本使用方法(详细介绍)
  • Ubuntu24 辅助系统-屏幕键盘的back按键在网页文本框删除不正常的问题解决方法
  • 博客项目 laravel vue mysql 第六章 文章功能