基于立创开发板的红外火焰传感器模块驱动移植与火源探测实战
基于立创开发板的红外火焰传感器模块驱动移植与火源探测实战
最近在做一个智能灭火小车的项目,需要给小车装上“眼睛”来寻找火源。我选用了市面上常见的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输入引脚)。
根据原文的移植过程,连接关系如下:
| 传感器模块引脚 | 连接至立创开发板引脚 | 说明 |
|---|---|---|
| VCC | 5V0 | 电源正极,接5V输出引脚 |
| GND | GND | 电源地,接任意GND引脚 |
| DO | P407 | 数字输出,接GPIO P4.7(用作输入) |
| AO | P000 | 模拟输出,接ADC通道0对应的引脚(通常是P000) |
注意:这里AO接的是P000,意味着我们在软件配置里需要将ADC的通道0与这个物理引脚绑定。不同芯片的ADC通道与引脚对应关系可能不同,一定要查数据手册确认。
接线完成后,建议你先不要着急写代码,可以用打火机(注意安全!)或者热水杯在传感器前方晃动一下,观察模块上的DO指示灯是否亮起。如果指示灯能随火源亮灭,说明硬件连接和模块本身基本没问题,电位器灵敏度可能也需要调一下。接下来就是软件部分的配置了。
3. 软件配置:在IDE中“画”出硬件电路
立创开发板配套的开发环境通常提供了图形化配置工具(如FSP Configurator),这能大大简化引脚和外设的初始化工作。咱们需要配置两项:一个是ADC通道,另一个是DO引脚。
配置步骤:
- 打开图形化配置界面:在你的工程中找到硬件配置相关的工具并打开。
- 配置ADC(模拟输入):
- 在引脚分配图中,找到
P000这个引脚。 - 将其功能(Function)设置为
ADC0的通道0(AN000)。这样就把物理引脚P000分配给了ADC模块的第0通道。 - 在ADC模块的配置属性里,使能通道0,并根据需要设置采样精度(12位)、采样速度等参数。对于火焰传感器,用默认配置一般即可。
- 在引脚分配图中,找到
- 配置GPIO(数字输入):
- 找到
P407这个引脚。 - 将其功能设置为
GPIO,方向(Direction)设置为Input(输入)。因为我们只需要读取DO引脚的高低电平状态。
- 找到
- 保存并生成代码:完成上述配置后,记得按
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转换一结束,就会自动调用这个函数,我们就能安全地读取数据了。
然后,是获取传感器值的三个主要接口函数:
Get_Adc_Flame_Value:获取原始ADC值。它调用ADC_GET()采样SAMPLES次并求平均值,使读数更稳定。Get_Flame_Percentage_value:将原始ADC值转换为百分比。公式是百分比 = (ADC值 / 4095) * 100。注意:由于火焰越强ADC值越小,所以这个百分比实际上是“无火焰强度百分比”,值越小代表火焰越强。你可以用100 - 百分比来得到更直观的“火焰强度百分比”。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读取一次
}
}
编译、烧录、上电测试:
- 将整个工程编译,确保没有错误。
- 通过调试器将程序烧录到立创开发板。
- 打开串口调试助手(如Putty、SecureCRT),波特率设置为开发板串口初始化时使用的波特率(通常是115200)。
- 观察串口输出的数据。
- 在没有火源时,原始ADC值应该较高(接近4095),百分比值也高,DO状态为1。
- 用打火机(请小心远离其他物品)在传感器前方约50cm处点燃,你会看到ADC值迅速下降,百分比值也下降,DO状态很可能变为0(同时模块上的指示灯亮起)。
- 尝试调节模块上的蓝色电位器,可以改变DO输出的灵敏度。顺时针旋转,灵敏度提高(更容易触发);逆时针旋转,灵敏度降低。
常见问题与调试技巧:
- ADC读数一直为0或4095:检查AO引脚(P000)是否接触良好,图形化配置中ADC通道0是否已正确绑定到该引脚并启用。
- DO状态不变,指示灯不亮:检查DO引脚(P407)配置是否为输入模式。用万用表测量DO引脚对地电压,当有火焰时电压应从高电平(~3.3V/5V)跳变为低电平(~0V)。同时检查电位器是否拧到了合适位置。
- 数值跳动剧烈:这是正常现象,环境中的红外噪声(如阳光、白炽灯)都会干扰。我们的代码已经做了5次平均滤波。如果要求更高,可以增加
SAMPLES次数,或在软件中采用更复杂的滤波算法(如中值滤波)。 - 如何判断火源距离:ADC值或百分比值可以作为一个粗略的距离/强度参考。你需要通过实验,记录下不同距离下稳定的ADC读数,然后在代码中设置几个阈值区间来判断“远、中、近”。DO信号更适合做简单的“有/无”火灾判断。
至此,一个完整的红外火焰传感器驱动移植和测试流程就完成了。你可以把读取数据的部分封装成任务,把DO信号作为中断触发源,再结合电机驱动,就能做出一个自动寻火、灭火的机器人了。希望这篇教程能帮你扫清障碍,顺利玩转火焰传感器。
更多推荐
所有评论(0)