基于TI MSPM0 MCU的MQ-3酒精传感器驱动移植与数据采集实战最近在准备电赛项目用到了MQ-3酒精传感器发现网上关于TI MSPM0系列MCU的驱动资料不多。正好手头有块立创的开发板我就把整个驱动移植和数据采集的过程整理了一下分享给同样在用MSPM0做传感器开发的朋友们。这篇文章会手把手带你从理解传感器原理开始到用SysConfig工具配置引脚最后写出完整的采集代码最终实现酒精浓度百分比的读取和显示。1. 认识我们的主角MQ-3酒精传感器在动手写代码之前咱们得先搞清楚要驱动的对象是什么。MQ-3是一款非常常用的酒精气体传感器模块在很多酒驾检测、环境监测的小项目里都能看到它。它是怎么工作的呢MQ-3传感器的核心是一层二氧化锡(SnO₂)气敏材料。在干净的空气里这层材料的导电能力电导率比较差。但是一旦它周围存在酒精蒸气神奇的事情就发生了酒精分子会和材料表面发生反应导致材料的电导率随着酒精浓度的增加而变大。模块内部已经集成了简单的电路能把这个电导率的变化转换成我们可以测量的电压信号。模块引脚与输出信号市面上常见的MQ-3模块通常有4个引脚2.54mm间距排针非常方便插在面包板或扩展板上引脚名称类型功能说明VCC电源工作电压范围是3.3V ~ 5V咱们的开发板通常提供3.3V。GND电源接地。DO数字输出数字量输出。模块上有个比较器通常是LM393它会将传感器信号和一个可调阈值比较超过阈值就输出低电平0否则输出高电平1。你可以通过模块上的电位器调节这个灵敏度。AO模拟输出模拟量输出。这是传感器最原始的电压信号酒精浓度越高这个引脚输出的电压也越高。我们需要用MCU的ADC模数转换器来读取它。简单来说DO引脚给我们一个“有”或“无”的开关信号适合做简单的报警而AO引脚则给我们一个连续的浓度信息适合做更精确的测量。我们这个教程两个都会用上。注意MQ-3对酒精很敏感但它也会受到汽油、烟雾等气体的干扰所以它测的是“酒精类气体”的浓度在要求非常精确的场合需要注意这点。2. 硬件连接与引脚规划拿到传感器和开发板第一步就是连线。连线很简单关键是规划好MCU的哪个引脚来接传感器的信号线。1. 电源连接传感器VCC-开发板3.3V传感器GND-开发板GND2. 信号线连接传感器DO-开发板任意GPIO配置为输入模式传感器AO-开发板具有ADC功能的引脚这里有个关键点AO引脚必须连接到MCU支持ADC输入功能的引脚上。根据原始资料我们选择使用开发板上的PA27引脚因为它具有ADC的附属功能。DO引脚就比较随意了我随便选了一个空闲的GPIO比如PA26你完全可以根据自己板子的情况来选。连接好之后硬件部分就准备好了。接下来就是重头戏在软件工程里配置这些引脚和外设。3. 使用SysConfig图形化工具配置工程TI为MSPM0系列提供了非常好用的SysConfig图形化配置工具它能自动生成底层引脚和驱动初始化代码省去了我们手动查手册、写寄存器的麻烦。咱们一步步来。3.1 打开并添加ADC配置在你的CCS或IAR工程里找到并双击empty.syscfg文件或者类似名称的.syscfg文件这会打开SysConfig配置界面。在界面左侧的“Software”或“Peripherals”栏里找到ADC12模块MSPM0的12位ADC点击ADD按钮添加一个ADC实例比如ADC12_0。在ADC的详细配置中我们需要设置转换通道。找到我们连接AO引脚的PA27将它配置为ADC的输入通道。通常操作是选择一个“ADC Channel”然后在下拉菜单或引脚图上将其映射到PA27。接着配置ADC的基本参数比如采样时钟、分辨率12位、参考电压通常选内部参考等。对于MQ-3这种变化不快的信号用默认的单次转换模式就足够了。3.2 添加GPIO配置用于DO引脚同样在SysConfig界面找到GPIO模块并添加。找到我们连接DO引脚的PA26以你实际连接的为准将其配置为输入模式。因为DO引脚是模块输出给MCU的信号我们只需要读取它的电平状态。3.3 保存并生成代码所有配置完成后点击保存按钮。这时可能会弹出一个警告框提示你要覆盖一些已有的驱动文件。重要提示当出现覆盖文件的确认对话框时一定要选择Yes to All确保配置工具生成的新代码能替换旧文件。保存后点击编译整个工程。这里可能会遇到一些编译警告甚至错误先不用管它因为工具生成的代码可能和原有工程结构有些小冲突我们后续通过包含正确的头文件来解决。完成这一步后SysConfig工具会自动在工程里生成一个ti_msp_dl_config.h文件里面就定义了我们刚才配置的ADC和GPIO的所有信息比如ADC12_0_INSTADC实例、MQ_DO_PINDO引脚宏等。这个文件通常会被主配置文件board.h所包含所以我们后续编程时只需要#include board.h就行了非常方便。4. 编写MQ-3传感器驱动代码配置工具帮我们搭好了舞台现在该我们上台唱戏——编写具体的驱动函数了。我们需要创建两个文件bsp_mq3.c和bsp_mq3.h。4.1 头文件定义 (bsp_mq3.h)头文件主要用于声明函数和定义一些宏让代码更清晰。#ifndef _BSP_MQ3_H_ #define _BSP_MQ3_H_ #include board.h // 包含SysConfig生成的配置 // 读取DO引脚电平的宏定义 // 原理读取GPIO端口引脚状态并进行逻辑判断返回1或0 #define MQ_DO ( ( DL_GPIO_readPins( MQ_PORT, MQ_DO_PIN ) MQ_DO_PIN ) ? 1 : 0 ) // ADC采样次数多次采样取平均可以滤除偶然干扰 #define SAMPLES 30 // 函数声明 void ADC_MQ3_Init(void); // ADC初始化 unsigned int Get_Adc_MQ3_Value(void); // 获取原始ADC值 unsigned int Get_MQ3_Percentage_value(void); // 获取酒精浓度百分比 char Get_MQ3_DO_value(void); // 获取DO数字状态 #endif4.2 源文件实现 (bsp_mq3.c)这里是所有功能的实现我会逐段解释。#include bsp_mq3.h #include stdio.h // 全局变量ADC转换完成标志位 volatile bool gCheckADC; /****************************************************************** * 函数名称ADC_MQ3_Init * 函数说明初始化ADC功能主要是使能ADC中断 * 函数形参无 * 函数返回无 ******************************************************************/ void ADC_MQ3_Init(void) { // 使能ADC的中断这样ADC转换完成后才能触发我们的中断服务函数 NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); }这个初始化函数非常简单因为ADC模块本身的时钟、引脚复用等配置已经在SysConfig里设置好并由board_init()函数统一初始化了。我们这里只需要打开ADC的中断开关。/****************************************************************** * 函数名称ADC_GET * 函数功能启动一次ADC转换并等待读取结果 * 传入参数无 * 函数返回单次ADC转换的原始结果0-4095 ******************************************************************/ uint32_t ADC_GET(void) { unsigned int gAdcResult 0; int timeout 20; // 超时计数器防止ADC卡死 // 软件触发ADC开始一次转换 DL_ADC12_startConversion(ADC12_0_INST); // 等待转换完成标志位gCheckADC被置位在中断函数中设置 while (false gCheckADC) { delay_us(1); timeout--; if(timeout 0) // 超时处理 { printf(ADC转换超时错误!! LINE:%d\r\n,__LINE__); return 1; // 返回一个错误值 } } // 从ADC结果存储器中读取通道0的数据 gAdcResult DL_ADC12_getMemResult(ADC12_0_INST, ADC12_0_ADCMEM_ADC_CH0); // 清除标志位为下一次转换做准备 gCheckADC false; return gAdcResult; }这个函数是ADC读取的核心。它启动转换然后等待。这里用了一个gCheckADC标志位这个标志位会在ADC转换完成的中断服务函数里被设置为true。用循环等待标志位的方式比死等ADC状态寄存器更清晰。我还加了个超时判断这是个好习惯避免程序因为硬件问题卡死在这里。/****************************************************************** * 函数名称Get_Adc_MQ3_Value * 函数说明连续采样SAMPLES次然后取平均值得到稳定的ADC值 * 函数形参无 * 函数返回平均后的ADC值 ******************************************************************/ unsigned int Get_Adc_MQ3_Value(void) { uint32_t Data 0; for(int i 0; i SAMPLES; i) { Data ADC_GET(); // 累加每次采样结果 delay_ms(5); // 稍作延时避免采样过于密集 } Data Data / SAMPLES; // 求平均值 return Data; }传感器信号可能会有微小波动一次采样结果可能不准。这里我们采样30次SAMPLES定义为30然后求平均值这样得到的数值就稳定多了。/****************************************************************** * 函数名称Get_MQ3_Percentage_value * 函数说明将ADC值转换为百分比浓度值 * 函数形参无 * 函数返回酒精浓度百分比 (0-100%) ******************************************************************/ unsigned int Get_MQ3_Percentage_value(void) { int adc_max 4095; // MSPM0的12位ADC最大值是2^12 -1 4095 int adc_new 0; int Percentage_value 0; adc_new Get_Adc_MQ3_Value(); // 获取平均ADC值 // 核心换算公式 (当前ADC值 / 最大ADC值) * 100% Percentage_value ((float)adc_new / (float)adc_max) * 100.f; return Percentage_value; }这是将原始数据“翻译”成我们看得懂的信息的关键函数。ADC读到的是0-4095的数字我们把它转换成0-100%的百分比。注意这个百分比是电压的百分比并不是精确的酒精浓度ppm值。要得到精确浓度需要根据传感器数据手册进行标定和公式换算。但对于很多定性或相对比较的应用这个百分比已经非常直观有用了。/****************************************************************** * 函数名称Get_MQ3_DO_value * 函数说明读取DO引脚的数字状态 * 函数形参无 * 函数返回0未检测到高于阈值的酒精1检测到酒精 ******************************************************************/ char Get_MQ3_DO_value(void) { // 直接使用头文件中定义的宏 MQ_DO 来读取引脚电平 if( MQ_DO 0 ) // 模块上比较器输出低电平表示检测到 { return 1; // 我们返回1表示“检测到” } else { return 0; // 返回0表示“未检测到” } }数字输出DO的读取就简单多了直接读GPIO电平就行。这里逻辑反了一下因为模块通常是检测到酒精时DO输出低电平所以我们判断为0时返回1表示有酒精。// ADC中断服务函数 void ADC12_0_INST_IRQHandler(void) { // 查询是哪个ADC中断源触发了 switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) { // 检查是否是“存储器0结果已加载”中断即转换完成 case DL_ADC12_IIDX_MEM0_RESULT_LOADED: gCheckADC true; // 置位转换完成标志位 break; default: break; } }这个中断函数是ADC转换完成的“通知中心”。当ADC转换结束后硬件会自动跳转到这里。我们检查中断类型如果是我们关心的“转换完成”中断就把那个等待循环里用的gCheckADC标志位设为true这样ADC_GET函数就知道可以读取结果了。5. 在主函数中调用与测试驱动写好了最后就是在主程序里调用它们并打印出结果。#include board.h #include stdio.h #include bsp_mq3.h int main(void) { // 开发板初始化时钟、SysConfig配置的GPIO/ADC等都在这里初始化 board_init(); // 初始化MQ-3驱动主要是使能ADC中断 ADC_MQ3_Init(); printf(MQ-3酒精传感器Demo开始...\r\n); while(1) { // 读取并打印酒精浓度百分比 printf(酒精含量 %d%%\r\n, Get_MQ3_Percentage_value() ); // 读取并打印数字输出状态 char do_state Get_MQ3_DO_value(); if(do_state 1) { printf(数字输出(DO): 检测到酒精\r\n); } else { printf(数字输出(DO): 未检测到酒精。\r\n); } printf(\n); // 空行分隔 delay_ms(1000); // 每秒读取一次 } }将代码编译下载到开发板打开串口调试助手波特率要和board_init里配置的一致你就能看到每秒输出一次的酒精浓度百分比和数字报警状态了。对着传感器吹口气含微量酒精看看数值会不会变化吧几个调试小贴士如果百分比一直为0或很小检查AO引脚是否接触良好或者用手靠近传感器体温会导致微小变化看数值是否有波动以判断ADC读取是否正常。如果DO状态不对可以调节传感器模块上的蓝色电位器顺时针调灵敏度增高更容易输出低电平报警逆时针则降低。数值跳变尝试增加bsp_mq3.h中的SAMPLES采样次数比如从30改到50可以让平均值更稳定。希望这篇教程能帮你顺利搞定MQ-3和MSPM0的搭配。整个过程的核心就是理解传感器输出、用对工具配置引脚、然后按照“初始化-触发-等待-读取”的逻辑去写ADC驱动。把这个流程掌握了其他类似的模拟量传感器也就触类旁通了。
基于TI MSPM0 MCU的MQ-3酒精传感器驱动移植与数据采集实战
基于TI MSPM0 MCU的MQ-3酒精传感器驱动移植与数据采集实战最近在准备电赛项目用到了MQ-3酒精传感器发现网上关于TI MSPM0系列MCU的驱动资料不多。正好手头有块立创的开发板我就把整个驱动移植和数据采集的过程整理了一下分享给同样在用MSPM0做传感器开发的朋友们。这篇文章会手把手带你从理解传感器原理开始到用SysConfig工具配置引脚最后写出完整的采集代码最终实现酒精浓度百分比的读取和显示。1. 认识我们的主角MQ-3酒精传感器在动手写代码之前咱们得先搞清楚要驱动的对象是什么。MQ-3是一款非常常用的酒精气体传感器模块在很多酒驾检测、环境监测的小项目里都能看到它。它是怎么工作的呢MQ-3传感器的核心是一层二氧化锡(SnO₂)气敏材料。在干净的空气里这层材料的导电能力电导率比较差。但是一旦它周围存在酒精蒸气神奇的事情就发生了酒精分子会和材料表面发生反应导致材料的电导率随着酒精浓度的增加而变大。模块内部已经集成了简单的电路能把这个电导率的变化转换成我们可以测量的电压信号。模块引脚与输出信号市面上常见的MQ-3模块通常有4个引脚2.54mm间距排针非常方便插在面包板或扩展板上引脚名称类型功能说明VCC电源工作电压范围是3.3V ~ 5V咱们的开发板通常提供3.3V。GND电源接地。DO数字输出数字量输出。模块上有个比较器通常是LM393它会将传感器信号和一个可调阈值比较超过阈值就输出低电平0否则输出高电平1。你可以通过模块上的电位器调节这个灵敏度。AO模拟输出模拟量输出。这是传感器最原始的电压信号酒精浓度越高这个引脚输出的电压也越高。我们需要用MCU的ADC模数转换器来读取它。简单来说DO引脚给我们一个“有”或“无”的开关信号适合做简单的报警而AO引脚则给我们一个连续的浓度信息适合做更精确的测量。我们这个教程两个都会用上。注意MQ-3对酒精很敏感但它也会受到汽油、烟雾等气体的干扰所以它测的是“酒精类气体”的浓度在要求非常精确的场合需要注意这点。2. 硬件连接与引脚规划拿到传感器和开发板第一步就是连线。连线很简单关键是规划好MCU的哪个引脚来接传感器的信号线。1. 电源连接传感器VCC-开发板3.3V传感器GND-开发板GND2. 信号线连接传感器DO-开发板任意GPIO配置为输入模式传感器AO-开发板具有ADC功能的引脚这里有个关键点AO引脚必须连接到MCU支持ADC输入功能的引脚上。根据原始资料我们选择使用开发板上的PA27引脚因为它具有ADC的附属功能。DO引脚就比较随意了我随便选了一个空闲的GPIO比如PA26你完全可以根据自己板子的情况来选。连接好之后硬件部分就准备好了。接下来就是重头戏在软件工程里配置这些引脚和外设。3. 使用SysConfig图形化工具配置工程TI为MSPM0系列提供了非常好用的SysConfig图形化配置工具它能自动生成底层引脚和驱动初始化代码省去了我们手动查手册、写寄存器的麻烦。咱们一步步来。3.1 打开并添加ADC配置在你的CCS或IAR工程里找到并双击empty.syscfg文件或者类似名称的.syscfg文件这会打开SysConfig配置界面。在界面左侧的“Software”或“Peripherals”栏里找到ADC12模块MSPM0的12位ADC点击ADD按钮添加一个ADC实例比如ADC12_0。在ADC的详细配置中我们需要设置转换通道。找到我们连接AO引脚的PA27将它配置为ADC的输入通道。通常操作是选择一个“ADC Channel”然后在下拉菜单或引脚图上将其映射到PA27。接着配置ADC的基本参数比如采样时钟、分辨率12位、参考电压通常选内部参考等。对于MQ-3这种变化不快的信号用默认的单次转换模式就足够了。3.2 添加GPIO配置用于DO引脚同样在SysConfig界面找到GPIO模块并添加。找到我们连接DO引脚的PA26以你实际连接的为准将其配置为输入模式。因为DO引脚是模块输出给MCU的信号我们只需要读取它的电平状态。3.3 保存并生成代码所有配置完成后点击保存按钮。这时可能会弹出一个警告框提示你要覆盖一些已有的驱动文件。重要提示当出现覆盖文件的确认对话框时一定要选择Yes to All确保配置工具生成的新代码能替换旧文件。保存后点击编译整个工程。这里可能会遇到一些编译警告甚至错误先不用管它因为工具生成的代码可能和原有工程结构有些小冲突我们后续通过包含正确的头文件来解决。完成这一步后SysConfig工具会自动在工程里生成一个ti_msp_dl_config.h文件里面就定义了我们刚才配置的ADC和GPIO的所有信息比如ADC12_0_INSTADC实例、MQ_DO_PINDO引脚宏等。这个文件通常会被主配置文件board.h所包含所以我们后续编程时只需要#include board.h就行了非常方便。4. 编写MQ-3传感器驱动代码配置工具帮我们搭好了舞台现在该我们上台唱戏——编写具体的驱动函数了。我们需要创建两个文件bsp_mq3.c和bsp_mq3.h。4.1 头文件定义 (bsp_mq3.h)头文件主要用于声明函数和定义一些宏让代码更清晰。#ifndef _BSP_MQ3_H_ #define _BSP_MQ3_H_ #include board.h // 包含SysConfig生成的配置 // 读取DO引脚电平的宏定义 // 原理读取GPIO端口引脚状态并进行逻辑判断返回1或0 #define MQ_DO ( ( DL_GPIO_readPins( MQ_PORT, MQ_DO_PIN ) MQ_DO_PIN ) ? 1 : 0 ) // ADC采样次数多次采样取平均可以滤除偶然干扰 #define SAMPLES 30 // 函数声明 void ADC_MQ3_Init(void); // ADC初始化 unsigned int Get_Adc_MQ3_Value(void); // 获取原始ADC值 unsigned int Get_MQ3_Percentage_value(void); // 获取酒精浓度百分比 char Get_MQ3_DO_value(void); // 获取DO数字状态 #endif4.2 源文件实现 (bsp_mq3.c)这里是所有功能的实现我会逐段解释。#include bsp_mq3.h #include stdio.h // 全局变量ADC转换完成标志位 volatile bool gCheckADC; /****************************************************************** * 函数名称ADC_MQ3_Init * 函数说明初始化ADC功能主要是使能ADC中断 * 函数形参无 * 函数返回无 ******************************************************************/ void ADC_MQ3_Init(void) { // 使能ADC的中断这样ADC转换完成后才能触发我们的中断服务函数 NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); }这个初始化函数非常简单因为ADC模块本身的时钟、引脚复用等配置已经在SysConfig里设置好并由board_init()函数统一初始化了。我们这里只需要打开ADC的中断开关。/****************************************************************** * 函数名称ADC_GET * 函数功能启动一次ADC转换并等待读取结果 * 传入参数无 * 函数返回单次ADC转换的原始结果0-4095 ******************************************************************/ uint32_t ADC_GET(void) { unsigned int gAdcResult 0; int timeout 20; // 超时计数器防止ADC卡死 // 软件触发ADC开始一次转换 DL_ADC12_startConversion(ADC12_0_INST); // 等待转换完成标志位gCheckADC被置位在中断函数中设置 while (false gCheckADC) { delay_us(1); timeout--; if(timeout 0) // 超时处理 { printf(ADC转换超时错误!! LINE:%d\r\n,__LINE__); return 1; // 返回一个错误值 } } // 从ADC结果存储器中读取通道0的数据 gAdcResult DL_ADC12_getMemResult(ADC12_0_INST, ADC12_0_ADCMEM_ADC_CH0); // 清除标志位为下一次转换做准备 gCheckADC false; return gAdcResult; }这个函数是ADC读取的核心。它启动转换然后等待。这里用了一个gCheckADC标志位这个标志位会在ADC转换完成的中断服务函数里被设置为true。用循环等待标志位的方式比死等ADC状态寄存器更清晰。我还加了个超时判断这是个好习惯避免程序因为硬件问题卡死在这里。/****************************************************************** * 函数名称Get_Adc_MQ3_Value * 函数说明连续采样SAMPLES次然后取平均值得到稳定的ADC值 * 函数形参无 * 函数返回平均后的ADC值 ******************************************************************/ unsigned int Get_Adc_MQ3_Value(void) { uint32_t Data 0; for(int i 0; i SAMPLES; i) { Data ADC_GET(); // 累加每次采样结果 delay_ms(5); // 稍作延时避免采样过于密集 } Data Data / SAMPLES; // 求平均值 return Data; }传感器信号可能会有微小波动一次采样结果可能不准。这里我们采样30次SAMPLES定义为30然后求平均值这样得到的数值就稳定多了。/****************************************************************** * 函数名称Get_MQ3_Percentage_value * 函数说明将ADC值转换为百分比浓度值 * 函数形参无 * 函数返回酒精浓度百分比 (0-100%) ******************************************************************/ unsigned int Get_MQ3_Percentage_value(void) { int adc_max 4095; // MSPM0的12位ADC最大值是2^12 -1 4095 int adc_new 0; int Percentage_value 0; adc_new Get_Adc_MQ3_Value(); // 获取平均ADC值 // 核心换算公式 (当前ADC值 / 最大ADC值) * 100% Percentage_value ((float)adc_new / (float)adc_max) * 100.f; return Percentage_value; }这是将原始数据“翻译”成我们看得懂的信息的关键函数。ADC读到的是0-4095的数字我们把它转换成0-100%的百分比。注意这个百分比是电压的百分比并不是精确的酒精浓度ppm值。要得到精确浓度需要根据传感器数据手册进行标定和公式换算。但对于很多定性或相对比较的应用这个百分比已经非常直观有用了。/****************************************************************** * 函数名称Get_MQ3_DO_value * 函数说明读取DO引脚的数字状态 * 函数形参无 * 函数返回0未检测到高于阈值的酒精1检测到酒精 ******************************************************************/ char Get_MQ3_DO_value(void) { // 直接使用头文件中定义的宏 MQ_DO 来读取引脚电平 if( MQ_DO 0 ) // 模块上比较器输出低电平表示检测到 { return 1; // 我们返回1表示“检测到” } else { return 0; // 返回0表示“未检测到” } }数字输出DO的读取就简单多了直接读GPIO电平就行。这里逻辑反了一下因为模块通常是检测到酒精时DO输出低电平所以我们判断为0时返回1表示有酒精。// ADC中断服务函数 void ADC12_0_INST_IRQHandler(void) { // 查询是哪个ADC中断源触发了 switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) { // 检查是否是“存储器0结果已加载”中断即转换完成 case DL_ADC12_IIDX_MEM0_RESULT_LOADED: gCheckADC true; // 置位转换完成标志位 break; default: break; } }这个中断函数是ADC转换完成的“通知中心”。当ADC转换结束后硬件会自动跳转到这里。我们检查中断类型如果是我们关心的“转换完成”中断就把那个等待循环里用的gCheckADC标志位设为true这样ADC_GET函数就知道可以读取结果了。5. 在主函数中调用与测试驱动写好了最后就是在主程序里调用它们并打印出结果。#include board.h #include stdio.h #include bsp_mq3.h int main(void) { // 开发板初始化时钟、SysConfig配置的GPIO/ADC等都在这里初始化 board_init(); // 初始化MQ-3驱动主要是使能ADC中断 ADC_MQ3_Init(); printf(MQ-3酒精传感器Demo开始...\r\n); while(1) { // 读取并打印酒精浓度百分比 printf(酒精含量 %d%%\r\n, Get_MQ3_Percentage_value() ); // 读取并打印数字输出状态 char do_state Get_MQ3_DO_value(); if(do_state 1) { printf(数字输出(DO): 检测到酒精\r\n); } else { printf(数字输出(DO): 未检测到酒精。\r\n); } printf(\n); // 空行分隔 delay_ms(1000); // 每秒读取一次 } }将代码编译下载到开发板打开串口调试助手波特率要和board_init里配置的一致你就能看到每秒输出一次的酒精浓度百分比和数字报警状态了。对着传感器吹口气含微量酒精看看数值会不会变化吧几个调试小贴士如果百分比一直为0或很小检查AO引脚是否接触良好或者用手靠近传感器体温会导致微小变化看数值是否有波动以判断ADC读取是否正常。如果DO状态不对可以调节传感器模块上的蓝色电位器顺时针调灵敏度增高更容易输出低电平报警逆时针则降低。数值跳变尝试增加bsp_mq3.h中的SAMPLES采样次数比如从30改到50可以让平均值更稳定。希望这篇教程能帮你顺利搞定MQ-3和MSPM0的搭配。整个过程的核心就是理解传感器输出、用对工具配置引脚、然后按照“初始化-触发-等待-读取”的逻辑去写ADC驱动。把这个流程掌握了其他类似的模拟量传感器也就触类旁通了。