基于立创开发板的红外火焰传感器模块驱动移植与火源探测实战

最近在做一个智能灭火小车的项目,需要给小车装上“眼睛”来寻找火源。我选用了市面上常见的4线制红外火焰传感器模块,并把它成功移植到了立创开发板(主控为R7FA6E2BB3CNE)上。整个过程踩过一些坑,也总结了不少经验,今天就把从模块原理、硬件连接到代码编写、调试验证的完整过程分享给大家,手把手教你实现火源探测功能。

无论你是正在参加机器人比赛的学生,还是想为智能家居项目添加火灾预警功能的爱好者,这篇教程都能帮你快速上手。咱们不扯那些虚的理论,直接进入实战。

1. 认识你的“火眼金睛”:红外火焰传感器模块

在开始接线写代码之前,咱们得先搞清楚手里这个传感器是干什么的、怎么工作的。这能帮你后面调试时心里有底。

这个红外火焰传感器模块,本质上是一个“红外光强度检测器”。它的核心是一个对特定红外光敏感的光电二极管。火焰在燃烧时,会发出大量的红外线,波长主要集中在700纳米到1000纳米这个范围,其中对880纳米左右的红外光最敏感。

模块是怎么工作的呢?你可以把它想象成一个“光敏电阻”,但它只对红外光有反应。当有火源(或其他高温热源)出现在它面前时,红外光照射到内部的光电二极管上,二极管的内阻就会发生变化,从而引起输出端电压的变化。红外光越强,输出电压的模拟值(AO)就越低。

模块提供了两种输出方式,非常方便:

  • AO(模拟输出):直接输出一个连续的电压值(0-3.3V或0-5V,取决于供电)。连接到单片机的ADC(模数转换器)引脚,可以读取到一个具体的数值(比如0-4095)。这个数值直接反映了红外光的强弱,可以用来判断火源的远近或大小。
  • DO(数字输出):模块上自带了一个LM393电压比较器芯片和一个小电位器。你可以通过旋转电位器,设定一个“警报阈值”。当AO端的电压低于这个阈值(即红外光强于设定值)时,DO端就会从高电平变成低电平,同时模块上的一个LED指示灯会亮起。这个开关信号非常适合直接触发报警或控制动作。

简单总结一下它的关键参数,这些信息在你设计项目时很重要:

参数项规格说明
工作电压3.3V - 5V(兼容性强,立创开发板的5V和3.3V引脚都能用)
探测距离约1米(实际受火焰大小和环境光影响)
输出信号AO(模拟量),DO(数字量0/1)
接口类型4 Pin 2.54mm间距排针(VCC, GND, DO, AO)
探测角度约60度(一个比较广的扇形区域)

模块的资料和购买链接,原文里都提供了,你可以按需取用。有了这些基本认识,咱们就可以动手把它接到开发板上了。

2. 硬件连接:给传感器找个“家”

接线是第一步,千万不能错。立创开发板的引脚很多,我们得选两个合适的:一个用于读取模拟量(ADC引脚),一个用于读取数字量(普通GPIO输入引脚)。

根据原文的移植过程,连接关系如下:

传感器模块引脚连接至立创开发板引脚说明
VCC5V0电源正极,接5V输出引脚
GNDGND电源地,接任意GND引脚
DOP407数字输出,接GPIO P4.7(用作输入)
AOP000模拟输出,接ADC通道0对应的引脚(通常是P000)

注意:这里AO接的是P000,意味着我们在软件配置里需要将ADC的通道0与这个物理引脚绑定。不同芯片的ADC通道与引脚对应关系可能不同,一定要查数据手册确认。

接线完成后,建议你先不要着急写代码,可以用打火机(注意安全!)或者热水杯在传感器前方晃动一下,观察模块上的DO指示灯是否亮起。如果指示灯能随火源亮灭,说明硬件连接和模块本身基本没问题,电位器灵敏度可能也需要调一下。接下来就是软件部分的配置了。

3. 软件配置:在IDE中“画”出硬件电路

立创开发板配套的开发环境通常提供了图形化配置工具(如FSP Configurator),这能大大简化引脚和外设的初始化工作。咱们需要配置两项:一个是ADC通道,另一个是DO引脚。

配置步骤:

  1. 打开图形化配置界面:在你的工程中找到硬件配置相关的工具并打开。
  2. 配置ADC(模拟输入):
    • 在引脚分配图中,找到P000这个引脚。
    • 将其功能(Function)设置为 ADC0 的通道0(AN000)。这样就把物理引脚P000分配给了ADC模块的第0通道。
    • 在ADC模块的配置属性里,使能通道0,并根据需要设置采样精度(12位)、采样速度等参数。对于火焰传感器,用默认配置一般即可。
  3. 配置GPIO(数字输入):
    • 找到P407这个引脚。
    • 将其功能设置为 GPIO,方向(Direction)设置为 Input(输入)。因为我们只需要读取DO引脚的高低电平状态。
  4. 保存并生成代码:完成上述配置后,记得按 Ctrl + S 保存配置。然后点击生成代码的按钮(通常是 Generate Project Content)。这一步非常关键,工具会根据你的图形化配置,自动生成初始化ADC和GPIO的底层代码,我们后续的驱动代码将基于这些生成的代码来编写。

图形化配置的好处是避免了手动查找寄存器、写初始化代码的繁琐过程,而且不容易出错。配置完成后,咱们就可以专心编写上层应用驱动了。

4. 驱动代码编写:封装传感器操作逻辑

为了方便管理和使用,我们为火焰传感器单独创建两个文件:bsp_flame.c(源文件)和 bsp_flame.h(头文件)。把传感器的所有操作都封装成函数,这样在主程序里调用起来就非常清晰了。

4.1 头文件 (bsp_flame.h) 解析

头文件主要做了三件事:定义引脚、声明函数、提供一些便利的宏。

#ifndef BSP_CODE_BSP_FLAME_H_
#define BSP_CODE_BSP_FLAME_H_

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

// 一些常用的延时宏定义,方便使用
#ifndef delay_ms
#define delay_ms(x)   R_BSP_SoftwareDelay(x, BSP_DELAY_UNITS_MILLISECONDS)
#endif
// ... 其他延时宏定义

// 简洁的类型定义
#ifndef u8
#define u8  uint8_t
#endif
// ... u16, u32 定义

// 硬件关联定义(根据你的图形化配置来定!)
#define BSP_ADC_CHANNEL     ADC_CHANNEL_0  // 使用ADC通道0
#define BSP_DO_GPIO_PIN     BSP_IO_PORT_04_PIN_07 // DO引脚对应P4.7

// 读取DO引脚电平的快捷函数
static inline bsp_io_level_t GET_DO(void) {
    bsp_io_level_t p_pin_value;
    fsp_err_t err = R_IOPORT_PinRead(&g_ioport_ctrl, BSP_DO_GPIO_PIN, &p_pin_value);
    if(err != FSP_SUCCESS)
    {
        printf("GPIO Input Read Failed!!\r\n");
    }
    return p_pin_value;
}

#define SAMPLES     5 // ADC采样次数,取平均以抗干扰

// 函数声明
void Flame_Module_Init(void);
int Get_Adc_Flame_Value(void);
unsigned int Get_Flame_Percentage_value(void);
char Get_Flame_Do_value(void);

#endif /* BSP_CODE_BSP_FLAME_H_ */

关键点说明:

  • BSP_ADC_CHANNEL 和 BSP_DO_GPIO_PIN 必须与你图形化配置的通道和引脚一致。
  • GET_DO() 函数使用了 static inline 修饰,这是一个读取GPIO电平的高效方式,编译器可能会将其内联展开,减少函数调用开销。
  • SAMPLES 定义为5,意味着我们读取ADC值时将连续采样5次然后取平均值,这能有效滤除一些偶然的干扰信号。

4.2 源文件 (bsp_flame.c) 解析

这里是功能实现的核心。我们一步步来看每个函数。

首先,是模块初始化函数 Flame_Module_Init: 这个函数负责打开并配置ADC模块。注意,GPIO的输入初始化通常在图形化配置生成代码时已经完成了,所以这里不需要再配置P4.7。

void Flame_Module_Init(void)
{
    fsp_err_t err = FSP_SUCCESS;
    // 打开ADC设备(g_adc0_ctrl和g_adc0_cfg是图形化工具生成的)
    err = R_ADC_Open(&g_adc0_ctrl, &g_adc0_cfg);
    if (FSP_SUCCESS != err) {
        printf("ADC Open Failed! \n");
        return;
    }
    // 配置ADC扫描(g_adc0_channel_cfg也是工具生成的)
    err = R_ADC_ScanCfg(&g_adc0_ctrl, &g_adc0_channel_cfg);
    if (FSP_SUCCESS != err) {
        printf("ADC Scan Config Failed! \n");
        R_ADC_Close(&g_adc0_ctrl); // 如果配置失败,记得关闭已打开的ADC
        return;
    }
}

接着,是ADC读取的核心辅助函数 ADC_GET: 它启动一次ADC转换,并等待转换完成,最后读取结果。这里用到了一个回调函数标志 adc_flag。

static int ADC_GET(void)
{
    int gAdcResult = 0;
    int timeOut = 1000; // 超时计数器,防止卡死
    fsp_err_t err = FSP_SUCCESS;

    err = R_ADC_ScanStart(&g_adc0_ctrl); // 启动一次ADC扫描
    if (FSP_SUCCESS != err) {
        printf("ADC扫描启动失败! \n");
        return 9999; // 返回一个明显的错误值
    }

    // 等待ADC转换完成标志(adc_flag在回调函数中被置位)
    while(!adc_flag && timeOut--)
    {
        delay_us(1);
    }
    adc_flag = false; // 清除标志

    if(!timeOut) // 超时处理
    {
        printf("ADC_GET Failed!!!\r\n");
        return 0;
    }

    // 读取指定通道的ADC转换结果
    err = R_ADC_Read(&g_adc0_ctrl, BSP_ADC_CHANNEL, (uint16_t *)&gAdcResult);
    if (FSP_SUCCESS != err) {
        printf("ADC Read Failed!\n");
        return 9999;
    }
    return gAdcResult; // 返回12位ADC值(0-4095)
}

// ADC转换完成的中断回调函数(需在配置中启用)
void adc_callback(adc_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args); // 未使用参数,防止警告
    adc_flag = true; // 设置完成标志
}

提示:adc_callback 这个回调函数需要在图形化配置ADC模块时,在“Callback”选项里设置好。这样ADC转换一结束,就会自动调用这个函数,我们就能安全地读取数据了。

然后,是获取传感器值的三个主要接口函数:

  1. Get_Adc_Flame_Value:获取原始ADC值。它调用 ADC_GET() 采样 SAMPLES 次并求平均值,使读数更稳定。
  2. Get_Flame_Percentage_value:将原始ADC值转换为百分比。公式是 百分比 = (ADC值 / 4095) * 100。注意:由于火焰越强ADC值越小,所以这个百分比实际上是“无火焰强度百分比”,值越小代表火焰越强。你可以用 100 - 百分比 来得到更直观的“火焰强度百分比”。
  3. Get_Flame_Do_value:直接读取DO引脚的数字状态(0或1)。返回1通常表示未检测到火焰(高电平),返回0表示检测到火焰(低电平,LED亮)。这个阈值可以通过模块上的蓝色电位器调节。
int Get_Adc_Flame_Value(void)
{
    uint32_t Data = 0;
    int i;
    for(i = 0; i < SAMPLES; i++) // 采样5次
    {
        Data += ADC_GET();
        delay_ms(5); // 每次采样间隔5ms
    }
    Data = Data / SAMPLES; // 求平均值
    return Data;
}

unsigned int Get_Flame_Percentage_value(void)
{
    int adc_max = 4095; // 12位ADC最大值
    int adc_new = 0;
    int Percentage_value = 0;
    adc_new = Get_Adc_Flame_Value(); // 获取平均ADC值
    Percentage_value = ((float)adc_new / (float)adc_max) * 100.f; // 计算百分比
    return Percentage_value;
}

char Get_Flame_Do_value(void)
{
    return GET_DO(); // 调用头文件里定义的快捷函数
}

5. 功能验证:让代码跑起来看结果

驱动写好了,最后一步就是在主程序中调用它们,看看传感器到底能不能工作。

在你的主程序文件(例如 app.c 的 Run 函数)中,加入以下测试代码:

#include "bsp_flame.h" // 包含我们的火焰传感器驱动头文件

void Run(void)
{
    // ... 其他初始化代码,比如串口初始化
    UART0_Debug_Init();
    printf("系统启动...\r\n");

    // 1. 初始化火焰传感器模块(主要是ADC)
    Flame_Module_Init();
    printf("火焰传感器初始化成功!\r\n");

    while(1)
    {
        // 2. 循环读取并打印三种数据
        printf("\n"); // 换行,让输出更清晰
        printf("火焰传感器原始ADC值 = %d\r\n", Get_Adc_Flame_Value());
        printf("火焰强度百分比 = %d%%\r\n", Get_Flame_Percentage_value());
        printf("数字输出DO状态 = %d\r\n", Get_Flame_Do_value());

        // 3. 根据DO状态做一些简单反应,比如点亮LED
        if(Get_Flame_Do_value() == 0) // 检测到火焰
        {
            // 点亮报警LED,或者启动风扇、水泵等
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_LOW);
        }
        else
        {
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_HIGH);
        }

        delay_ms(500); // 每500ms读取一次
    }
}

编译、烧录、上电测试:

  1. 将整个工程编译,确保没有错误。
  2. 通过调试器将程序烧录到立创开发板。
  3. 打开串口调试助手(如Putty、SecureCRT),波特率设置为开发板串口初始化时使用的波特率(通常是115200)。
  4. 观察串口输出的数据。
    • 在没有火源时,原始ADC值应该较高(接近4095),百分比值也高,DO状态为1。
    • 用打火机(请小心远离其他物品)在传感器前方约50cm处点燃,你会看到ADC值迅速下降,百分比值也下降,DO状态很可能变为0(同时模块上的指示灯亮起)。
  5. 尝试调节模块上的蓝色电位器,可以改变DO输出的灵敏度。顺时针旋转,灵敏度提高(更容易触发);逆时针旋转,灵敏度降低。

常见问题与调试技巧:

  • ADC读数一直为0或4095:检查AO引脚(P000)是否接触良好,图形化配置中ADC通道0是否已正确绑定到该引脚并启用。
  • DO状态不变,指示灯不亮:检查DO引脚(P407)配置是否为输入模式。用万用表测量DO引脚对地电压,当有火焰时电压应从高电平(~3.3V/5V)跳变为低电平(~0V)。同时检查电位器是否拧到了合适位置。
  • 数值跳动剧烈:这是正常现象,环境中的红外噪声(如阳光、白炽灯)都会干扰。我们的代码已经做了5次平均滤波。如果要求更高,可以增加 SAMPLES 次数,或在软件中采用更复杂的滤波算法(如中值滤波)。
  • 如何判断火源距离:ADC值或百分比值可以作为一个粗略的距离/强度参考。你需要通过实验,记录下不同距离下稳定的ADC读数,然后在代码中设置几个阈值区间来判断“远、中、近”。DO信号更适合做简单的“有/无”火灾判断。

至此,一个完整的红外火焰传感器驱动移植和测试流程就完成了。你可以把读取数据的部分封装成任务,把DO信号作为中断触发源,再结合电机驱动,就能做出一个自动寻火、灭火的机器人了。希望这篇教程能帮你扫清障碍,顺利玩转火焰传感器。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐