CW32F030C8T6开发板火焰传感器模块驱动移植与火源检测实战

CW32F030C8T6开发板火焰传感器模块驱动移植与火源检测实战 CW32F030C8T6开发板火焰传感器模块驱动移植与火源检测实战最近在做一个智能灭火小车的项目需要用到火焰传感器来寻找火源。手头正好有一块武汉芯源的CW32F030C8T6开发板以及一个常见的四线制红外火焰传感器模块。网上关于这个模块在STM32上的资料不少但在CW32这颗国产MCU上的具体实现却不多。今天我就把整个驱动移植和调试的过程记录下来从硬件连接到代码编写手把手带你实现火源检测。无论你是正在做相关比赛的学生还是项目中需要用到火焰探测的工程师这篇教程都能帮你快速上手。1. 认识我们的“眼睛”红外火焰传感器模块在开始写代码之前咱们得先搞清楚要用的传感器是什么、能干什么。这个红外火焰传感器你可以把它想象成机器人的“眼睛”专门用来寻找火源。它的工作原理其实挺直观的任何发热的物体比如火焰都会向外辐射红外线。这个传感器内部的核心是一个对特定红外光敏感的光电二极管。当有火焰时红外光变强光电二极管的特性就会发生变化从而引起输出信号的变化。我用的这个模块有几个关键特点你得了解一下探测范围它对波长在700纳米到1000纳米之间的红外光敏感尤其对880纳米左右的红外光最灵敏。这正好覆盖了典型火焰发出的红外光谱范围。探测角度与距离它的探测角度大约是60度有效探测距离标称在1米左右。实际距离会受到火焰大小和环境光的影响。双输出模式这是最方便的地方模块提供了两种输出AO模拟输出直接输出一个电压值其大小与检测到的红外光强度成反比。光越强电压值转换后的ADC数值越小。我们可以用MCU的ADC模数转换器来读取这个连续变化的量从而判断火焰的远近或强弱。DO数字输出模块上自带一个LM393电压比较器。你可以通过板载的可调电阻设定一个阈值。当红外光强度超过这个阈值时DO引脚就直接输出一个低电平0否则输出高电平1。这相当于一个“有火/无火”的开关信号用起来非常简单。模块工作电压是3.3V-5V和我们的CW32开发板完美兼容。它引出了4个引脚VCC, GND, AO, DO用2.54mm排针连接非常方便。注意模块上通常还有一个指示灯D0当DO输出有效检测到火焰时会点亮调试的时候看这个灯非常直观。2. 硬件连接把“眼睛”装上开发板硬件连接很简单但接错了可不行。咱们以CW32F030C8T6开发板为例下面是接线方法火焰传感器模块引脚连接到CW32开发板作用说明VCC3.3V或5V引脚电源正极。模块兼容3.3V和5V建议与开发板逻辑电压一致接3.3V。GNDGND引脚电源地。必须共地。AOPA5(或其他ADC通道引脚)模拟信号输出。我们将用ADC来读取这个引脚上的电压。DOPA6(或其他任意GPIO引脚)数字信号输出。我们将用普通数字输入GPIO来读取高低电平。为什么选PA5和PA6这是根据原始资料和CW32F030的用户手册决定的。PA5引脚复用了ADC的通道5AIN5功能正好用来做模拟输入。PA6就作为一个普通的数字输入引脚。在你的实际项目中如果这些引脚被占用了也可以换用其他具有ADC功能的引脚和普通GPIO记得在代码里改过来就行。接好线后给开发板和传感器通电。你可以试着用打火机小心烫手或点燃的纸巾在传感器前方晃动看看模块上的D0指示灯是否会亮起这是初步检验硬件是否正常的好方法。3. 软件驱动移植编写CW32的专属驱动程序硬件准备就绪接下来就是重头戏——软件部分。我们要为CW32F030编写火焰传感器的驱动代码。代码主要分为两部分bsp_flame.c源文件和bsp_flame.h头文件。3.1 头文件 (bsp_flame.h) 的配置头文件里主要进行宏定义把硬件连接关系“告诉”程序这样以后改引脚会非常方便。#ifndef _BSP_FLAME_H_ #define _BSP_FLAME_H_ #include board.h // 包含CW32的板级支持包头文件 /* 时钟使能宏定义 */ #define RCC_FLAME_GPIO_ENABLE() __RCC_GPIOA_CLK_ENABLE() // 使能GPIOA的时钟 #define RCC_FLAME_ADC_ENABLE() __RCC_ADC_CLK_ENABLE() // 使能ADC的时钟 /* ADC通道选择PA5对应ADC通道5 */ #define CHANNEL_ADC ADC_ExInputCH5 /* 将PA5引脚配置为模拟功能 */ #define ANALOG_GPIO_ENABLE() PA05_ANALOG_ENABLE() /* 端口与引脚定义 */ #define PORT_GPIO_FLAME CW_GPIOA // 传感器使用的GPIO端口 #define GPIO_FLAME_AO GPIO_PIN_5 // AO引脚接PA5 #define GPIO_FLAME_DO GPIO_PIN_6 // DO引脚接PA6 /* 采样次数ADC采样时多次采样取平均值可以滤除偶然干扰 */ #define SAMPLES 30 /* 函数声明 */ void ADC_FLAME_Init(void); // ADC初始化函数 unsigned int Get_FLAME_Percentage_value(void); // 获取火焰强度百分比 unsigned char Get_FLAME_Do_value(void); // 获取数字开关状态 #endif3.2 源文件 (bsp_flame.c) 的核心函数源文件里包含了三个关键函数。第一个函数ADC_FLAME_Init—— 初始化ADC这个函数负责配置PA5为模拟输入模式并初始化ADC模块。CW32的ADC配置稍微有点步骤但跟着我做一遍就明白了。void ADC_FLAME_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体 // 1. 打开相关时钟 RCC_FLAME_GPIO_ENABLE(); // 使能GPIOA时钟 RCC_FLAME_ADC_ENABLE(); // 使能ADC时钟 // 2. 初始化DO引脚PA6为数字输入模式用于读取高低电平 GPIO_InitStruct.Pins GPIO_FLAME_DO; GPIO_InitStruct.Mode GPIO_MODE_INPUT; // 输入模式 GPIO_Init(PORT_GPIO_FLAME, GPIO_InitStruct); // 3. 将AO引脚PA5设置为模拟功能这是ADC采样的前提 ANALOG_GPIO_ENABLE(); /* 4. 配置ADC模块 */ ADC_InitTypeDef ADC_InitStructure; // ADC主结构体 ADC_WdtTypeDef ADC_WdtStructure; // ADC看门狗结构体本例未使用但需初始化 ADC_SingleChTypeDef ADC_SingleChStructure; // 单通道配置结构体 // 配置ADC基础参数 ADC_InitStructure.ADC_OpMode ADC_SingleChOneMode; // 单通道单次转换模式采一次就停 ADC_InitStructure.ADC_ClkDiv ADC_Clk_Div4; // ADC时钟分频。假设系统时钟64MHz则ADC时钟为16MHz ADC_InitStructure.ADC_SampleTime ADC_SampTime5Clk; // 采样时间5个ADC时钟周期 ADC_InitStructure.ADC_VrefSel ADC_Vref_VDDA; // 参考电压选择VDDA通常接3.3V ADC_InitStructure.ADC_InBufEn ADC_BufDisable; // 关闭输入缓冲器一般情况关闭即可 ADC_InitStructure.ADC_TsEn ADC_TsDisable; // 关闭内部温度传感器通道 ADC_InitStructure.ADC_DMAEn ADC_DmaDisable; // 不使能DMA我们手动读取 ADC_InitStructure.ADC_Align ADC_AlignRight; // 转换结果右对齐方便阅读 ADC_InitStructure.ADC_AccEn ADC_AccDisable; // 不使能累加功能 // 初始化ADC看门狗本例中未使用其功能但需调用初始化函数 ADC_WdtInit(ADC_WdtStructure); // 配置单通道转换的具体通道 ADC_SingleChStructure.ADC_DiscardEn ADC_DiscardNull; // 溢出数据不丢弃单次模式无影响 ADC_SingleChStructure.ADC_Chmux CHANNEL_ADC; // 选择通道AIN5即PA5 ADC_SingleChStructure.ADC_InitStruct ADC_InitStructure; // 传入基础配置 ADC_SingleChStructure.ADC_WdtStruct ADC_WdtStructure; // 传入看门狗配置 // 将以上配置写入ADC寄存器 ADC_SingleChOneModeCfg(ADC_SingleChStructure); // 5. 使能ADC并启动一次转换 ADC_Enable(); ADC_SoftwareStartConvCmd(ENABLE); }第二个函数ADC_GET—— 读取一次ADC原始值这是一个底层辅助函数负责启动一次ADC转换并读取结果。CW32的ADC在单次模式下每次读取都需要软件触发。uint32_t ADC_GET(void) { ADC_SoftwareStartConvCmd(ENABLE); // 启动一次转换 uint32_t adcValue ADC_GetConversionValue(); // 读取转换结果 return adcValue; // 返回12位ADC值0~4095 }第三个函数Get_FLAME_Percentage_value—— 获取火焰强度百分比这是给我们上层应用调用的核心函数。它通过多次采样取平均值来稳定数据并将原始的ADC值0~4095转换成一个更直观的“火焰强度百分比”0%~100%。unsigned int Get_FLAME_Percentage_value(void) { uint32_t i 0; uint32_t adc_max 4095; // CW32F030的ADC是12位最大值是4095 uint32_t adc_new 0; uint32_t Percentage_value 0; // 循环采样SAMPLES次在.h文件中定义为30次 for(i 0; i SAMPLES; i) { adc_new ADC_GET(); // 累加ADC值 delay_us(10); // 可以加一个很小的延时确保每次采样独立 } adc_new adc_new / SAMPLES; // 计算平均值 // 核心转换公式将ADC值转换为百分比 // 注意传感器特性是红外光越强ADC值越小。所以要用1减去比值。 Percentage_value ( 1.0f - ( (float)adc_new / (float)adc_max ) ) * 100.0f; return Percentage_value; }关键点解释为什么是1.0f - (adc_new / adc_max) 因为火焰传感器的AO输出特性是红外光越强输出电压越低ADC读到的数值越小。当没有火焰时ADC值接近最大值4095百分比应为0%当传感器正对强火焰时ADC值很小百分比应接近100%。这个公式正好实现了这个反向映射。第四个函数Get_FLAME_Do_value—— 读取数字开关状态这个函数就简单多了直接读取DO引脚PA6上的电平状态。unsigned char Get_FLAME_Do_value(void) { // 读取引脚电平返回0低电平表示有火焰或1高电平表示无火焰 return GPIO_ReadPin(PORT_GPIO_FLAME, GPIO_FLAME_DO); }4. 实战应用在主程序中读取并打印结果驱动写好了怎么用呢咱们在main函数里调用它们。通常的做法是初始化后在一个循环里不断读取传感器数据。#include board.h #include stdio.h // 为了使用printf #include bsp_uart.h // 串口初始化头文件用于打印 #include bsp_flame.h // 我们刚写的火焰传感器驱动头文件 int32_t main(void) { board_init(); // 开发板基础初始化系统时钟、GPIO等 uart1_init(115200); // 初始化串口1波特率115200用于打印信息到电脑 ADC_FLAME_Init(); // 初始化火焰传感器ADC printf(CW32 Flame Sensor Test Start!\r\n); while(1) { // 读取并打印火焰强度百分比 unsigned int flame_percent Get_FLAME_Percentage_value(); printf(Flame Percentage %d%%\r\n, flame_percent); // 读取并打印数字开关状态 unsigned char flame_switch Get_FLAME_Do_value(); if(flame_switch 0) { printf(DO Status: FLAME DETECTED! (LOW)\r\n); } else { printf(DO Status: No flame. (HIGH)\r\n); } printf(--------------------\r\n); delay_ms(500); // 延时500毫秒避免打印太快 } }如何验证将代码编译下载到CW32F030C8T6开发板。用串口线连接开发板和电脑打开串口助手如XCOM Putty等设置波特率为115200。观察串口打印的信息。正常情况下没有火焰时百分比接近0%DO状态为HIGH。用打火机请小心或点燃的纸巾在传感器前方约20-50厘米处晃动。你应该能看到打印的百分比数值显著上升例如升到50%、80%同时DO状态变为LOW并且模块上的D0指示灯也会亮起。5. 调试心得与常见问题百分比数值跳动大这是正常的因为红外光容易受到环境干扰如日光灯、人体热辐射。除了代码中已经做的多次采样取平均你还可以在软件里做滑动平均滤波或卡尔曼滤波让数值更平稳。DO输出不灵敏或太灵敏模块上有一个蓝色的可调电阻电位器。用它来调整LM393比较器的阈值。顺时针旋转通常是提高灵敏度更容易触发逆时针是降低灵敏度。根据你的应用场景火焰远近、环境干扰调整到一个合适的点。ADC读数始终很高或很低检查AO引脚PA5是否接触良好。检查bsp_flame.h中的CHANNEL_ADC宏定义是否与你的实际连接引脚ADC通道匹配。用万用表测量AO引脚对地的电压当传感器被火焰照射时电压应下降。想改变探测距离或灵敏度除了调整板载电位器你还可以在代码里做文章。例如将Get_FLAME_Percentage_value()函数返回的百分比与一个你自己设定的阈值比如30%比较来实现软件上的灵敏度调节。好了以上就是将通用火焰传感器模块成功移植到CW32F030平台上的全过程。代码我已经在实际项目里跑通了你可以直接拿去用。希望这篇教程能帮你快速搞定火焰检测功能让你的智能小车或机器人顺利找到火源。