目录
[1.1 概述](#1.1 概述)
[1.2 特性](#1.2 特性)
[1.3 检测原理](#1.3 检测原理)
[1.4 应用场景](#1.4 应用场景)
[2.1 概述](#2.1 概述)
[2.2 特性](#2.2 特性)
[2.3 检测原理](#2.3 检测原理)
[2.4 应用场景](#2.4 应用场景)
[4.1 火焰传感器参考代码](#4.1 火焰传感器参考代码)
[4.1.1 flame.h](#4.1.1 flame.h)
[4.1.2 flame.c](#4.1.2 flame.c)
[4.1.3 adc.h](#4.1.3 adc.h)
[4.1.4 adc.c](#4.1.4 adc.c)
[4.1.4 main.c](#4.1.4 main.c)
[4.2 光敏电阻传感器参考代码](#4.2 光敏电阻传感器参考代码)
[4.2.1 light.h](#4.2.1 light.h)
[4.2.2 light.c](#4.2.2 light.c)
[4.2.3 adc,h](#4.2.3 adc,h)
[4.2.4 adc.c](#4.2.4 adc.c)
[4.2.5 main.c](#4.2.5 main.c)
引言
本次,我们继续学习两种传感器,分别是火焰传感器、光敏电阻传感器 ,之所以放一块讲,主要原因是这俩传感器都非常类似,控制起来也是非常简单,他们都是使用一个**均采用LM393比较器加上电位器控制输出开关量(是否达到一定阈值)和模拟量(具体强度)**实现对火焰和光强的检测。这俩传感器外观如下图所示。

对于本次传感器学习,需要大家具有一定的C语言基础,同时STM32需要熟悉GPIO外设以及ADC外设的应用逻辑。
一、火焰传感器介绍
1.1 概述
火焰传感器主要用于探测火焰及 760nm~1100nm 波长光源 ,搭载LM393 比较器,工作电压 3.3V-5V;支持 DO 数字(0/1)、AO 模拟输出,可调灵敏度,体型小(3.2cm×1.4cm)且带安装孔,易对接单片机。
1.2 特性
(1)对火焰光谱敏感,打火机探测距 80cm(火焰越大距越远),探测角约 60°;
(2)电位器可调灵敏度,LM393 输出信号干净,驱动能力超 15mA;
(3)供电电压3.3V-5V 宽压适配,双输出模式,小巧易安装。
1.3 检测原理
通过黑色光敏元件捕捉火焰的红外光谱(760nm~1100nm),蓝色电位器可调节灵敏度。模块输出 DO 数字信号(0/1)和 AO 模拟信号,工作电压 3.3V-5V,能直接对接单片机。主要用于火焰报警、火源探测,探测角度约 60 度,打火机火焰探测距离达 80cm,火焰越大探测距离越远,还设有固定孔方便安装。
1.4 应用场景
(1)家庭 / 工厂火灾预警;
(2)工业明火安全监控;
(3)火焰追踪机器人、互动玩具感应;
(4)实验室 / 户外设备火焰状态判断。
二、光敏电阻传感器介绍
2.1 概述
该光敏电阻传感器基于光敏电阻的光电特性,用于检测环境光线强度,搭载信号调理电路,工作电压 3.3V-5V;支持 DO 数字(0/1)、AO 模拟输出,可调灵敏度,体型小巧且带安装孔,易对接单片机。
2.2 特性
(1)对光线强度敏感,可检测可见光范围内的光线变化,探测范围随光敏电阻特性而定;
其它特性与火焰传感器介绍的基本一致。
2.3 检测原理
通过红色光敏电阻感知光线强度,光线越强,光敏电阻阻值越小;蓝色电位器调节灵敏度,将光敏电阻的阻值变化转化为电压信号,经处理后输出 DO 数字信号(0/1,用于判断光线是否超过阈值)和 AO 模拟信号(用于反映光线强度的连续变化),工作电压 3.3V-5V,可直接对接单片机,用于光线检测、自动光控等场景,设有固定孔方便安装。
2.4 应用场景
(1)智能照明系统,根据光线强度自动开关灯;
(2)智能玩具,通过光线变化触发互动效果;
(3)环境监测设备,检测光照强度变化;
(4)自动控制设备,如光线感应的自动窗帘、遮阳棚等。
三、类似特性
通过前面对俩模块的介绍,大家应该能够明显感觉到:无论是外观还是检测原理上都非常相似,只是检测内容不同导致模块有稍微的差异。因此接下来,我们再说一下这俩基本类似的特性。
(1)**作控制开关:**由于这俩传感器的数字量 DO 输出端输出的是开关量(数字量),因此都可直接驱动继电器模块,由此能组成光控或火警开关。
(2)**模拟量获取强度值:**这俩传感器都含有AO口,即Analog Output模拟输出引脚。模拟量 AO 可与单片机的AD外设或外置AD模块相连,通过 AD 转换,能获得环境光强/火焰强度的数值。
(3)**开关量输出电平:**这俩传感器都通过DO口输出一个高低电平来判断检测内容强度是否达到一定程度。当环境火焰强度/光线亮度达不到设定阈值时,DO 端输出高电平;当外界环境火焰强度/光线亮度超过设定阈值时,DO 端输出低电平。
(4)阈值调节: 检测亮度/火焰强度的阈值均可通过蓝色电位器进行调节,顺时针调电位器,检测亮度/火焰强度的阈值增加;逆时针调电位器,检测亮度/火焰阈值减少。
四、参考代码
根据前面描述,我们可以发现驱动这俩传感器的逻辑就很简单了,实际与前面介绍的几个传感器都非常类似,即使用单片机接收传感器通过DO输出的电平(低电平--达到光强/火焰强度阈值、高电平--未达到阈值),只不过还多了个AO口的输出,所以还需要涉及到ADC转换的逻辑。
因此,接下来我们就直接给出参考代码,该代码是基于STM32F103系列单片机、寄存器方式编写的代码。
4.1 火焰传感器参考代码
4.1.1 flame.h
cpp
#ifndef __FLAME_H
#define __FLAME_H
#include "stm32f10x.h"
/**
* 引脚接线
*
* VCC ---> 3.3/5V
* GND ---> GND
* DO ---> PA0
* AO ---> PA1
*
*/
void Flame_Init(void);
uint8_t Flame_Detect(void);
#endif
/*** (C) COPYRIGHT 2025 END OF FILE ***/
4.1.2 flame.c
cpp
/*
* @Descripttion: 火焰传感器驱动文件(.c)
* @Author: JaRyon
* @version:
* @Date: 2025-10-28 12:19:43
*/
#include "flame.h"
/**
* @brief 火焰传感器初始化
* @param void 无
* @return void
* @example Flame_Init();
* @attention
*/
void Flame_Init(void)
{
// 1. 开启时钟 PA
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 2. DO-PA0 浮空输入 mode-00 cnf-01
GPIOA->CRL &= ~GPIO_CRL_MODE0;
GPIOA->CRL |= GPIO_CRL_CNF0_0;
GPIOA->CRL &= ~GPIO_CRL_CNF0_1;
}
/**
* @brief 检测火焰,获取状态
* @param void 无
* @return uint8_t
* @example uint8_t flameState = Flame_Detect();
* @attention
*/
uint8_t Flame_Detect(void)
{
uint8_t flameState = 0;
if (GPIOA->IDR & GPIO_IDR_IDR0)
{
flameState = 1;
}
return flameState;
}
4.1.3 adc.h
cpp
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
void ADC1_Init(void);
void ADC1_StartConvert(void);
double ADC1_GetVol(void);
#endif
4.1.4 adc.c
cpp
/*
* @Descripttion: ADC单通道采集驱动
* @Author: JaRyon
* @version:
* @Date: 2025-10-28 21:16:11
*/
#include "adc.h"
// 初始化
void ADC1_Init(void)
{
// 1. 开启时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 分频:6分频 12MHz
RCC->CFGR |= RCC_CFGR_ADCPRE_1;
RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;
// 2. GPIO工作模式:模拟输入 MODE-00 CNF-00
GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
// 3. ADC配置
ADC1->CR1 &= ~ADC_CR1_SCAN;
ADC1->CR2 |= ADC_CR2_CONT;
ADC1->CR2 &= ~ADC_CR2_ALIGN;
ADC1->SMPR1 |= ADC_SMPR2_SMP1_0;
ADC1->SMPR1 &= ~(ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1);
ADC1->SQR1 &= ~ADC_SQR1_L;
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= (1 << 0);
ADC1->CR2 |= ADC_CR2_EXTTRIG;
ADC1->CR2 |= ADC_CR2_EXTSEL;
}
// 开启转换
void ADC1_StartConvert(void)
{
// 1. 上电唤醒
ADC1->CR2 |= ADC_CR2_ADON;
// 2. AD校准
ADC1->CR2 |= ADC_CR2_CAL;
// 轮询判断校准是否完毕,完成则清除
while (ADC1->CR2 & ADC_CR2_CAL)
{}
// 3. 启动转换
ADC1->CR2 |= ADC_CR2_SWSTART;
// 4. 判断是否转换完成 EOC置位
while (ADC1->SR & ADC_SR_EOC == 0)
{}
}
// 输出转换后的模拟电压
double ADC1_GetVol(void)
{
return ADC1->DR * 3.3 / (4096 - 1);
}
4.1.4 main.c
主程序测试逻辑比较简单,就是每10ms查询一次传感器检测情况:外界环境火焰强度达到设定阈值时点亮某个LED,同时在OLED 屏幕上显示"Fire!!",否则熄灭某个LED且OLED显示"Normal",然后同时显示获取的火焰强度。(其中,显示的火焰强度由0-100的数值展示)
cpp
/*
* @Descripttion: 火焰传感器测试
* @Author: JaRyon
* @version:
* @Date: 2025-10-28 12:19:43
*/
#include "stm32f10x.h"
#include "Systick.h"
#include "oled.h"
#include "flame.h"
#include "LED.h"
#include "adc.h"
int main(void)
{
uint32_t waitTimes = 0;
char *str = "Normal";
double FlameIntensity = 0, flameRes = 0.0;
uint8_t count = 0;
// 初始化
Systick_Init();
LED_Init();
OLED_Init();
OLED_ClearAll();
ADC1_Init();
Flame_Init();
ADC1_StartConvert();
waitTimes = Systick_GetTick();
while(1)
{
if (Systick_GetTick() - waitTimes >= 10000)
{
if (Flame_Detect() == 0)
{
str = "Fire!!";
LED_On(LED1);
}
else
{
str = "Normal";
LED_Off(LED1);
}
// 提高精度 算10次均值
FlameIntensity += (3.3 - ADC1_GetVol()) * 100 / 3.3;
count++;
if (count >= 10)
{
flameRes = FlameIntensity / count;
count = 0;
FlameIntensity = 0;
}
waitTimes = Systick_GetTick();
}
OLED_ShowString(39, 27, str, 8);
OLED_ShowString(25, 45, "FI:", 8);
OLED_ShowFloat(53, 45, flameRes, 3, 1, 8);
OLED_Update();
}
}
4.2 光敏电阻传感器参考代码
4.2.1 light.h
cpp
#ifndef __LIGHT_H
#define __LIGHT_H
#include "stm32f10x.h"
/**
* 引脚接线
*
* VCC ---> 3.3/5V
* GND ---> GND
* DO ---> PA0
* AO ---> PA1
*
*/
void Light_Init(void);
uint8_t Light_Detect(void);
#endif
/*** (C) COPYRIGHT 2025 END OF FILE ***/
4.2.2 light.c
cpp
/*
* @Descripttion: 光敏传感器驱动文件(.c)
* @Author: JaRyon
* @version:
* @Date: 2025-10-29 11:59:07
*/
#include "light.h"
/**
* @brief 光敏传感器初始化
* @param void 无
* @return void
* @example Light_Init();
* @attention
*/
void Light_Init(void)
{
// 1. 开启时钟 PA
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 2. DO-PA0 浮空输入 mode-00 cnf-01
GPIOA->CRL &= ~GPIO_CRL_MODE0;
GPIOA->CRL |= GPIO_CRL_CNF0_0;
GPIOA->CRL &= ~GPIO_CRL_CNF0_1;
}
/**
* @brief 检测光照,获取状态
* @param void 无
* @return uint8_t
* @example uint8_t lightState = Light_Detect();
* @attention
*/
uint8_t Light_Detect(void)
{
uint8_t lightState = 0;
if (GPIOA->IDR & GPIO_IDR_IDR0)
{
lightState = 1;
}
return lightState;
}
4.2.3 adc,h
4.2.4 adc.c
这里的ADC驱动可直接移植前面给出的ADC代码,因为使用的引脚相同,所以没有问题,因此这里不再赘述。
4.2.5 main.c
主程序测试逻辑与火焰传感器逻辑基本相同,就是每10ms查询一次传感器检测情况:外界环境光照强度达到设定阈值时点亮某个LED,同时在OLED 屏幕上显示"HLight",否则熄灭某个LED且OLED显示"Normal",然后同时显示获取的光照强度。(其中,显示的光照强度由0-100的数值展示)
cpp
/*
* @Descripttion: 光敏电阻传感器测试
* @Author: JaRyon
* @version:
* @Date: 2025-10-29 11:59:07
*/
#include "stm32f10x.h"
#include "Systick.h"
#include "oled.h"
#include "light.h"
#include "LED.h"
#include "adc.h"
int main(void)
{
uint32_t waitTimes = 0;
char *str = "Normal";
double LightIntensity = 0, LightRes = 0.0;
uint8_t count = 0;
// 初始化
Systick_Init();
LED_Init();
OLED_Init();
OLED_ClearAll();
Light_Init();
ADC1_Init();
ADC1_StartConvert();
waitTimes = Systick_GetTick();
while(1)
{
if (Systick_GetTick() - waitTimes >= 5000)
{
if (Light_Detect() == 0)
{
str = "HLight";
LED_On(LED1);
}
else
{
str = "Normal";
LED_Off(LED1);
}
// 提高光强精度 算10次均值
LightIntensity += (3.3 - ADC1_GetVol()) * 100 / 3.3;
count++;
if (count >= 10)
{
LightRes = LightIntensity / count;
count = 0;
LightIntensity = 0;
}
waitTimes = Systick_GetTick();
}
OLED_ShowString(39, 27, str, 8);
OLED_ShowString(25, 45, "LI:", 8);
OLED_ShowFloat(53, 45, LightRes, 3, 1, 8);
OLED_Update();
}
}
需要说明的是:主程序中会涉及到OLED 屏幕显示、LED驱动以及延时等代码逻辑,由于本次主要介绍传感器相关内容,因此这些内容就不再赘述,大家可缺少相关器件可使用串口输出,没有什么影响。当然若需要相关代码可私聊。
五、总结
本次我们介绍了火焰传感器和光敏电阻传感器的原理与应用。两种传感器结构相似,均采用LM393比较器,提供数字(DO)和模拟(AO)双输出,可通过电位器调节灵敏度。
同时提供了基于STM32的驱动代码实现方案,包括初始化配置、状态检测和ADC数据采集。两种传感器均可通过GPIO读取开关量状态,并通过ADC获取强度模拟量,具有相似的硬件接口和应用方式。
以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!
鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!