火焰传感器(3针) ADC采样与火焰检测代码例程
一、Arduino - 基础ADC读取 + 阈值判断
#define FLAME_AO_PIN A0
#define BUZZER_PIN 5
#define LED_PIN 6
#define FLAME_THRESHOLD 500 // 高于此值认为检测到火焰
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
Serial.println("3针火焰传感器检测系统");
Serial.println("正在建立环境基线...");
long baseline = 0;
for (int i = 0; i < 50; i++) {
baseline += analogRead(FLAME_AO_PIN);
delay(20);
}
baseline /= 50;
Serial.print("环境基线: "); Serial.println(baseline);
}
void loop() {
int raw = analogRead(FLAME_AO_PIN);
float voltage = (raw / 1024.0) * 5.0;
Serial.print("ADC: "); Serial.print(raw);
Serial.print(" | 电压: "); Serial.print(voltage, 3);
Serial.println("V");
if (raw > FLAME_THRESHOLD) {
Serial.println("🔥 火焰检测! 警报!");
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
delay(100);
}
二、Arduino - 自适应阈值(动态基线扣除)
#define FLAME_PIN A0
#define ALPHA 0.05 // EMA平滑系数
float baseline = 0; // 动态基线
void setup() {
Serial.begin(115200);
baseline = analogRead(FLAME_PIN); // 初始基线
}
void loop() {
int raw = analogRead(FLAME_PIN);
baseline = (ALPHA * raw) + ((1 - ALPHA) * baseline);
float delta = raw - baseline;
Serial.print("Raw: "); Serial.print(raw);
Serial.print(" | Baseline: "); Serial.print(baseline, 1);
Serial.print(" | Delta: "); Serial.print(delta, 1);
if (delta > 200) { // 差值超过阈值
Serial.println(" 🔥 FIRE!");
} else if (delta > 50) {
Serial.println(" ⚠ 附近有热源");
} else {
Serial.println(" ✓ 正常");
}
delay(50);
}
三、Arduino - 火焰闪烁频率分析(FFT去干扰)
#include <ArduinoFFT.h>
#define FLAME_PIN A0
#define SAMPLES 64 // 采样点数(2的幂)
#define SAMPLING_FREQ 200 // 采样频率(Hz)
ArduinoFFT<float> FFT;
float vReal[SAMPLES];
float vImag[SAMPLES];
void setup() {
Serial.begin(115200);
Serial.println("火焰频率分析模式");
}
void loop() {
unsigned long start = micros();
for (int i = 0; i < SAMPLES; i++) {
vReal[i] = analogRead(FLAME_PIN);
vImag[i] = 0;
while (micros() - start < (i + 1) * (1000000 / SAMPLING_FREQ));
}
FFT.windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.complexToMagnitude(vReal, vImag, SAMPLES);
float flameEnergy = 0;
float totalEnergy = 0;
int binStart = (4 * SAMPLES) / SAMPLING_FREQ; // 4Hz对应的bin
int binEnd = (20 * SAMPLES) / SAMPLING_FREQ; // 20Hz对应的bin
for (int i = 1; i < SAMPLES / 2; i++) {
if (i >= binStart && i <= binEnd) {
flameEnergy += vReal[i];
}
totalEnergy += vReal[i];
}
float flameRatio = flameEnergy / totalEnergy;
Serial.print("火焰闪烁能量占比: ");
Serial.print(flameRatio * 100, 1);
Serial.print("%");
if (flameRatio > 0.4) { // 火焰频段能量占比>40%
Serial.println(" 🔥 真实火焰!");
} else {
Serial.println(" (静态红外源/环境光)");
}
delay(200);
}
四、ESP-IDF - 火焰传感器ADC任务
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_log.h"
static const char *TAG = "FLAME";
#define FLAME_ADC_CHANNEL ADC_CHANNEL_7 // GPIO35
#define FLAME_THRESHOLD 2000 // 12位ADC下的阈值
static adc_oneshot_unit_handle_t adc_handle;
void flame_sensor_init(void) {
adc_oneshot_unit_init_cfg_t init_cfg = {
.unit_id = ADC_UNIT_1,
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
adc_oneshot_new_unit(&init_cfg, &adc_handle);
adc_oneshot_chan_cfg_t chan_cfg = {
.atten = ADC_ATTEN_DB_11,
.bitwidth = ADC_BITWIDTH_12,
};
adc_oneshot_config_channel(adc_handle, FLAME_ADC_CHANNEL, &chan_cfg);
ESP_LOGI(TAG, "Flame sensor initialized");
}
void flame_task(void *pvParameters) {
flame_sensor_init();
int64_t baseline_sum = 0;
for (int i = 0; i < 100; i++) {
int raw;
adc_oneshot_read(adc_handle, FLAME_ADC_CHANNEL, &raw);
baseline_sum += raw;
vTaskDelay(pdMS_TO_TICKS(10));
}
int baseline = baseline_sum / 100;
ESP_LOGI(TAG, "Baseline: %d", baseline);
while (1) {
int raw;
adc_oneshot_read(adc_handle, FLAME_ADC_CHANNEL, &raw);
int delta = raw - baseline;
if (delta > FLAME_THRESHOLD) {
ESP_LOGW(TAG, "🔥 FIRE DETECTED! Raw=%d Delta=%d", raw, delta);
} else {
ESP_LOGI(TAG, "OK | Raw=%d Delta=%d", raw, delta);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
五、3针 vs 4针代码对比
| 特性 |
3针(纯模拟) |
4针(模拟+数字) |
| 信号读取 |
analogRead(A0) |
analogRead(A0) + digitalRead(D2) |
| 阈值设置 |
代码中定义常数 |
旋转板上电位器 |
| 灵敏度调节 |
修改代码重新烧录 |
螺丝刀拧电位器 |
| 快速原型 |
需要编程 |
不需要代码即可触发 |
| 抗干扰能力 |
软件滤波灵活 |
硬件固定阈值 |
| MCU资源 |
需1个ADC引脚 |
需1个ADC + 1个GPIO |