外设模块学习(11)——火焰传感器、光敏电阻传感器(STM32)

目录

引言

一、火焰传感器介绍

[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获取强度模拟量,具有相似的硬件接口和应用方式。


以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!

鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!

相关推荐
DIY机器人工房16 分钟前
嵌入式面试题:纹波率怎么计算;Buck 电路电感值的标准计算式是什么?
stm32·嵌入式硬件·面试题·diy机器人工房
DIY机器人工房32 分钟前
嵌入式面试题:电容滤波,低频高频谁来滤?放置顺序怎么定?
stm32·单片机·嵌入式硬件·diy机器人工房
学习路上_write40 分钟前
嵌入式系统bringup指南:软硬件调试
c语言·单片机·嵌入式硬件
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [kernel]workqueue
linux·笔记·学习
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [kernel]usermode_helper
linux·笔记·学习
冬夜戏雪2 小时前
【学习日记】【刷题回溯、贪心、动规】
学习
一只爱做笔记的码农2 小时前
【BootstrapBlazor】移植BootstrapBlazor VS工程到Vscode工程,报error blazor106的问题
笔记·学习·c#
磨十三3 小时前
ARM Cortex-M 系列 MCU:内核、指令、异常与中断解析
arm开发·单片机·嵌入式硬件
xixixi777773 小时前
“C2隐藏”——命令与控制服务器的隐藏技术
网络·学习·安全·代理·隐藏·合法服务·c2隐藏
名字不相符3 小时前
攻防世界WEB难度一(个人记录)
学习·php·web·萌新