news 2026/8/22 12:39:09

MQ-9可燃气体传感器在TI TMS320F28P550开发板上的ADC与GPIO驱动移植实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MQ-9可燃气体传感器在TI TMS320F28P550开发板上的ADC与GPIO驱动移植实战

MQ-9可燃气体传感器在TI TMS320F28P550开发板上的ADC与GPIO驱动移植实战

最近在做一个环境监测的小项目,需要检测一氧化碳和可燃气体,用到了MQ-9传感器。很多刚开始接触TI C2000系列DSP(比如TMS320F28P550)的朋友,可能会觉得配置ADC和GPIO有点复杂。其实,只要理清思路,一步步来,把传感器用起来并不难。

这篇教程,我就以立创的TI电赛开发板(TMS320F28P550核心)为例,手把手带你完成MQ-9传感器的驱动移植。咱们的目标很明确:用ADC读取模拟浓度值(AO引脚),用GPIO读取数字报警信号(DO引脚)。我会把原理、接线、配置、代码编写和调试的整个过程都讲清楚,即使你是第一次用这个开发板,也能跟着做出来。

1. 认识你的“伙伴”:MQ-9传感器模块

在动手接线写代码之前,咱们先花几分钟了解一下MQ-9传感器。这就像打仗前先熟悉自己的武器,非常重要。

MQ-9的核心是一层二氧化锡(SnO2)气敏材料。这东西在干净空气里导电性很差(电阻大),但一旦遇到一氧化碳(CO)或者甲烷、丙烷这类可燃气体,它的电导率就会上升(电阻变小)。传感器就是通过测量这个电阻变化来感知气体浓度的。

它有个挺巧妙的工作方式:高低温循环检测

  • 低温阶段(加热电压约1.5V):主要用来检测一氧化碳(CO)。在这个温度下,传感器对CO最敏感。
  • 高温阶段(加热电压约5.0V):主要用来检测可燃气体(如甲烷),同时还有一个重要作用,就是“清洗”掉低温时吸附在传感器上的其他杂散气体,为下一次测量做准备。

你买到的模块通常长这样,有4个引脚(2.54mm间距,很好接):

  • VCC:供电脚,接3.3V或5V都行。
  • GND:电源地。
  • DO:数字量输出。当气体浓度超过你设定的阈值(通过模块上的蓝色电位器调节)时,这个引脚会输出低电平(0);否则输出高电平(1)。简单理解就是一个“超标报警”开关信号。
  • AO:模拟量输出。这个引脚会输出一个电压值,电压大小随气体浓度变化而变化。浓度越高,输出电压一般也越高。我们需要用开发板的ADC(模数转换器)来读取这个电压,从而得到具体的浓度信息。

模块关键参数速览:

参数说明
工作电压3.3V ~ 5V
工作电流约150mA(加热时电流较大,注意电源带载能力)
输出信号AO(模拟电压输出),DO(数字开关输出)
读取方式AO需ADC读取,DO可直接用GPIO读取
接口4 Pin 排针

提示:模块资料(数据手册、原理图等)可以在提供的链接中下载,里面包含了更详细的灵敏度特性曲线等信息,对于需要精确标定的项目很有帮助。

2. 硬件连接:把传感器“插”到开发板上

接线是第一步,千万不能错。根据原文的指引,我们使用开发板的以下资源:

  1. 电源:模块VCC接开发板的5V0输出引脚,为传感器提供工作电压。
  2. 地线:模块GND接开发板的GND
  3. 数字输出(DO):接开发板的GPIO54。这个引脚我们将配置为数字输入,用来读取高低电平。
  4. 模拟输出(AO):接开发板的GPIO-A6。注意,这个“A6”指的是ADC的通道编号,它对应着某个具体的GPIO引脚(例如可能是GPIO16,具体看开发板引脚图)。在SysConfig工具里,我们直接选择ADC通道即可,工具会自动映射到正确的GPIO。

接线对照表:

传感器模块引脚开发板对应引脚/功能
VCC5V0 (5V电源输出)
GNDGND (电源地)
DOGPIO54
AOADC-A通道6 (对应GPIO-A6)

接好线后,给开发板上电,你应该能看到MQ-9模块上的加热丝微微发红(小心烫),这说明它开始工作了。

3. 软件配置:用SysConfig图形化工具“画”出硬件

TI的C2000系列现在推荐使用SysConfig图形化配置工具来初始化外设,这比直接怼寄存器代码方便直观多了。咱们就在CCS(Code Composer Studio)里完成这个配置。

步骤详解:

  1. 打开配置文件:在你的CCS工程里,找到并双击c2000.syscfg这个文件。SysConfig界面就会在CCS内打开。

  2. 添加ADC配置

    • 在界面中找到“ADC”或“Analog-to-Digital Converter”相关的部分,点击ADD按钮。
    • 我们需要配置一个ADC转换通道。在参数中,找到SOC0(可以理解为第0个采样转换序列)的配置。
    • Channel(通道)选择为A6。这就是对应我们接线的GPIO-A6模拟输入。
    • 其他参数如采样窗口时间(AcqPs)可以先保持默认,后续根据信号特性可以微调。
  3. 添加GPIO配置

    • 找到“GPIO”或“PinMux”(引脚复用)相关的部分,点击ADD按钮。
    • 我们需要配置两个GPIO:
      • GPIO54:将其功能设置为GPIO Input(GPIO输入模式)。这就是用来读取DO数字信号的。
      • 找到ADC-A6对应的那个GPIO引脚(例如GPIO16):将其功能设置为ADC-A6或者Analog(模拟功能)。这一步很关键,它把物理引脚切换到了ADC输入模式,而不是普通的数字IO。
  4. 保存并生成代码

    • Ctrl + S保存SysConfig配置。
    • Ctrl + B编译一次工程。这里可能会弹出一些警告,但通常不影响,可以按原文提示先不管它。
    • 编译成功后,SysConfig会自动根据你的图形化配置,生成对应的C代码。这些代码主要位于board.hboard.c文件中,里面定义了你刚才配置的所有引脚和ADC通道的宏、初始化函数等。
  5. 包含头文件:原文的工程模板已经做得很好,它把board.h等必要的文件都汇总在了tjx_init.h这个头文件里。所以,在我们自己写的驱动文件中,只需要包含#include "tjx_init.h"就可以了,非常省心。

4. 驱动代码编写:让传感器“说话”

配置好了硬件接口,接下来就是写代码让它们动起来。我们在工程里新建一个module_driver文件夹,专门放各种传感器驱动。在里面创建bsp_mq9.cbsp_mq9.h两个文件。

注意:新建文件夹、文件以及添加头文件路径到编译器的方法,如果不会,可以参考原文中提到的DHT11章节教程,步骤是完全一样的。

4.1 头文件定义 (bsp_mq9.h)

头文件主要做两件事:声明外部可用的函数,以及定义一些宏来简化操作。

#ifndef _BSP_MQ9_H_ #define _BSP_MQ9_H_ #include "tjx_init.h" // 包含开发板所有初始化定义 // 宏定义:读取DO引脚的电平状态。GPIO_DO应在board.h中由SysConfig定义为GPIO54的引脚常量 #define MQ_DO GPIO_readPin( GPIO_DO ) // 定义ADC采样次数,通过多次采样取平均可以滤除偶然干扰 #define SAMPLES 5 // 函数声明 uint16_t Get_Adc_MQ9_Value(void); // 获取ADC原始值(平均值) uint8_t Get_MQ9_Percentage_value(void); // 获取浓度百分比(0-100%) char Get_MQ9_DO(void); // 获取DO引脚数字状态 #endif

4.2 核心源文件实现 (bsp_mq9.c)

这里是驱动逻辑的核心,我们逐个函数来分析。

首先,是一个内部使用的ADC读取辅助函数ADC_GET这个函数负责触发一次ADC转换并读取结果。它被设计为静态函数,意味着它只在当前.c文件内有效,是对外隐藏的实现细节。

static uint16_t ADC_GET(void) { uint16_t gAdcResult = 0; uint16_t timeOut = 200; // 设置一个超时计数器,防止死等 // 1. 软件触发ADC开始转换。Module_ADC_BASE和Module_ADC_FORCE_SOC0由SysConfig生成 ADC_forceMultipleSOC(Module_ADC_BASE, Module_ADC_FORCE_SOC0); // 2. 等待ADC转换完成 while(ADC_isBusy(Module_ADC_BASE) && timeOut--) { delay_us(5); // 短暂延时,等待转换 } // 3. 检查是否超时(转换失败) if(!timeOut) { lc_printf("ADC_GET Failed!!!\r\n"); return 0; } // 4. 读取转换结果。ADC是12位的,所以结果范围是0-4095 gAdcResult = ADC_readResult(Module_ADC_RESULT_BASE, Module_ADC_SOC0); return gAdcResult; }

然后,是获取MQ-9 ADC值的函数Get_Adc_MQ9_Value直接读一次ADC可能受噪声影响,所以我们采样多次求平均值。

uint16_t Get_Adc_MQ9_Value(void) { uint16_t Data = 0; int i; for(i = 0; i < SAMPLES; i++) { Data += ADC_GET(); // 累加SAMPLES次采样值 delay_ms(5); // 每次采样间隔5ms,让传感器和ADC稳定一下 } Data = Data / SAMPLES; // 计算平均值 return Data; }

接着,是将ADC值转换为百分比的函数Get_MQ9_Percentage_value这个函数非常有用,它把原始的0-4095的ADC数值,映射到了0-100%的范围,更直观。

uint8_t Get_MQ9_Percentage_value(void) { int adc_max = 4095; // 12位ADC的最大值 int adc_new = 0; float Percentage_value = 0; adc_new = Get_Adc_MQ9_Value(); // 获取平均ADC值 // 计算百分比:(当前值 / 最大值) * 100 Percentage_value = ((float)adc_new / (float)adc_max) * 100.f; return (uint8_t)Percentage_value; // 转换为整数百分比返回 }

最后,是读取数字输出DO的函数Get_MQ9_DO这个最简单,直接返回我们在头文件里用宏定义好的引脚状态。MQ_DO宏展开就是GPIO_readPin(GPIO_DO)

char Get_MQ9_DO(void) { return MQ_DO; // 返回0(气体超标)或1(正常) }

5. 功能验证:在主程序中测试

驱动写好了,最后一步就是把它用起来。我们修改主函数(例如empty_driverlib_main.c)来进行测试。

#include "driverlib.h" #include "device.h" #include "board.h" #include "c2000ware_libraries.h" #include "tjx_init.h" #include "bsp_mq9.h" // 包含我们刚写的驱动头文件 void main(void) { // CCS自动生成的系统初始化代码 [Start] Device_init(); Device_initGPIO(); Interrupt_initModule(); Interrupt_initVectorTable(); Board_init(); // 这里会调用SysConfig生成的板级初始化函数,配置好ADC和GPIO C2000Ware_libraries_init(); EINT; ERTM; // CCS自动生成的系统初始化代码 [End] // 初始化串口,用于打印信息(lc_printf函数依赖此初始化,通常在tjx_init.h中已包含) lc_printf("\r\n=== MQ-9 Sensor Test Start ===\r\n"); while(1) { // 1. 打印ADC原始值 (0-4095) lc_printf("MQ9 ADC Raw Value = %d\r\n", Get_Adc_MQ9_Value()); // 2. 打印浓度百分比 (0%-100%) lc_printf("MQ9 Concentration = [%d%%]\r\n", Get_MQ9_Percentage_value()); // 3. 打印数字输出状态 (0:报警, 1:正常) lc_printf("MQ9 DO State = %d (0:Gas Detected)\r\n", Get_MQ9_DO()); lc_printf("----------------------------\r\n"); // 用一个简单的LED闪烁指示程序在运行 GPIO_writePin(RGB_B, 0); // 蓝灯亮 GPIO_writePin(RGB_G, 1); // 绿灯灭 delay_ms(500); GPIO_writePin(RGB_B, 1); // 蓝灯灭 GPIO_writePin(RGB_G, 0); // 绿灯亮 delay_ms(500); GPIO_writePin(RGB_B, 1); // 蓝灯灭 GPIO_writePin(RGB_G, 1); // 绿灯灭 delay_ms(500); } }

将代码编译、下载到开发板,然后打开串口调试助手(波特率等参数根据你的板子串口配置设置)。你就能看到终端里不断打印出三行信息:

  1. ADC原始数值。
  2. 浓度百分比。
  3. DO引脚状态(0或1)。

测试方法:

  • 对着MQ-9传感器吹一口气(含二氧化碳)或者用打火机(注意安全,别点火!)释放少量丁烷气体靠近,观察ADC值和百分比是否会上升。
  • 旋转模块上的蓝色电位器,可以改变DO输出的灵敏度阈值。当浓度超过阈值时,DO状态应从1变为0。

如果一切正常,恭喜你!你已经成功在TMS320F28P550开发板上驱动了MQ-9气体传感器。这个框架也可以作为模板,轻松移植到其他模拟传感器上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 16:39:11

软件测试新姿势:我是如何用AI工具发现3个隐藏登录漏洞的

软件测试新姿势&#xff1a;我是如何用AI工具发现3个隐藏登录漏洞的 上周&#xff0c;团队内部做了一次安全复盘&#xff0c;一个刚上线两周的会员系统被外部白帽子提交了一个中危漏洞&#xff0c;问题出在登录环节的短信验证码逻辑上。这事儿让我有点坐不住&#xff0c;因为这…

作者头像 李华
网站建设 2026/7/14 16:39:13

3.11情况

一.C竞赛&#xff1a;1.2021最大公约数&#xff08;采用辗转相除法&#xff09;int gcd(int a, int b, int c) {return gcd(gcd(a, b), c); }求三个的最大公约数返回最小公倍数&#xff1a;int lcm(int a,int b){return a/gcd(a,b)*b;}#include<iostream> using namespa…

作者头像 李华
网站建设 2026/7/14 16:39:25

Gemma大模型(2B/7B)高效微调实战:从LoRA到QLoRA技术解析

1. 为什么你需要了解Gemma和高效微调&#xff1f; 如果你对AI大模型感兴趣&#xff0c;但又觉得动辄几百上千亿参数的模型离自己太远&#xff0c;觉得训练和微调都是大公司的专属游戏&#xff0c;那今天这篇文章就是为你准备的。我花了很长时间折腾各种大模型&#xff0c;从早期…

作者头像 李华
网站建设 2026/7/14 16:39:14

C语言项目实战:为MogFace-large编写轻量级图像预处理模块

C语言项目实战&#xff1a;为MogFace-large编写轻量级图像预处理模块 最近在折腾一个嵌入式设备上的人脸识别项目&#xff0c;选型时看中了MogFace-large这个模型&#xff0c;效果和速度平衡得不错。但真到部署时&#xff0c;发现一个挺实际的问题&#xff1a;模型推理前的图像…

作者头像 李华
网站建设 2026/7/14 16:39:24

QtPy(PySide6),在线程中使用QEventLoop实现低成本待机

需求&#xff1a;在主线程中启动一个功能函数在指定线程中运行&#xff0c;功能函数运行完成后指定线程并不立即结束&#xff0c;等待运行下一个功能函数。1、使用moveToThread创建QObject类&#xff0c;将功能函数包装为QObject类的槽函数&#xff0c;然后使用使用moveToThrea…

作者头像 李华
网站建设 2026/7/14 16:39:25

西门子6SL3120-1TE21-0AD0单电机模块

品牌&#xff1a;西门子 Siemens系列&#xff1a;SINAMICS S120 单电机模块规格&#xff1a;书本型、单轴、内部风冷一、产品核心特性6SL3120-1TE21-0AD0 是西门子 SINAMICS S120 高性能驱动系统旗下的书本型 D 型单电机模块&#xff0c;专为共直流母线架构的高精度工业驱动场景…

作者头像 李华