Skip to content

第 13 章:看懂火焰检测代码

本章任务

看懂"火焰传感器检测报警"的 Arduino C++ 代码——和第二册第 13 章是同一个任务。这也是本册最后一个实验,前面学过的所有"单词"都会在这里汇合。

接线回顾

火焰模块Pico说明
VCC3V33.3V 供电(不要接 5V)
GNDGND共地
A 口(模拟)GP26ADC0,读连续电压——火焰越近,读数越小
D 口(数字)GP14火焰强到一定程度输出高电平

报警 LED 用板载 LED(GP25),无需额外接线。

Mind+ 生成的典型代码

cpp
const int FLAME_ANALOG = 26;    // A 口(模拟)接 GP26
const int FLAME_DIGITAL = 14;   // D 口(数字)接 GP14
const int LED_PIN = 25;         // 报警灯用板载 LED

const int THRESHOLD = 3;        // 报警阈值:读数低于它算有火(analogRead 范围 0~1023)

void setup() {
  Serial.begin(115200);
  pinMode(FLAME_DIGITAL, INPUT);    // D 口是"输入"
  pinMode(LED_PIN, OUTPUT);         // 报警灯是"输出"

  // 上电先标定:看看正常环境和有火焰时读数各是多少
  Serial.println("=== 阈值标定 ===");
  Serial.println("正常环境读数:");
  for (int i = 0; i < 5; i++) {
    Serial.println(analogRead(FLAME_ANALOG));   // 连打 5 次基准值
    delay(500);
  }
  Serial.println("现在把火焰靠近传感器...");
  delay(3000);                                  // 留 3 秒点火时间
  for (int i = 0; i < 5; i++) {
    Serial.println(analogRead(FLAME_ANALOG));   // 再连打 5 次火焰值
    delay(500);
  }
  Serial.println("=== 开始检测 ===");
}

void loop() {
  int analogVal = analogRead(FLAME_ANALOG);     // 读模拟值(0~1023)
  int digitalVal = digitalRead(FLAME_DIGITAL);  // 读数字值(0 或 1)

  Serial.print("A口=");
  Serial.print(analogVal);
  Serial.print("  D口=");
  Serial.print(digitalVal);

  if (analogVal < THRESHOLD || digitalVal == 1) {
    // 模拟值够小(火焰够近)"或"数字口触发——任何一个都算有火焰
    digitalWrite(LED_PIN, HIGH);                // 点亮报警灯
    Serial.println("  ⚠️ 检测到火焰!");
  } else {
    digitalWrite(LED_PIN, LOW);                 // 熄灭报警灯
    Serial.println("  正常");
  }

  delay(300);                                   // 每 0.3 秒检测一次
}

代码讲解

这段代码几乎是全册知识点的"毕业汇演",逐个认一认:

  • analogRead(26):读 GP26 的模拟电压,返回 0~1023。注意:第二册 Python 的 read_u16() 返回 0~65535,两个量程不同,阈值不能照抄
  • setup() 里的标定流程:先测无火焰的基准值(比如 5 左右),再测有火焰的值(比如跌到 1 以下),阈值取中间——方法和第二册一模一样
  • loop() 里的判断 analogVal < THRESHOLD || digitalVal == 1:第 4 章的逻辑运算符 ||(或)实战——模拟值够小(火焰够近)数字触发,都报警,双保险
  • 剩下的 pinMode / digitalWrite / Serial.print / delay,全是前面章节的老朋友

运行效果

  • 无火焰:A 口读数较高(约 5),D 口为 0,板载 LED 灭,串口打印"正常"
  • 火焰靠近:A 口读数骤降(小到 1 左右),D 口变 1,板载 LED 点亮,串口打印"⚠️ 检测到火焰!"

常见坑

  • 方向记反:以为"火越大读数越大"——其实相反,火越近读数越小。判断写成 > 会导致有火不报警、没火乱报警
  • 无火时读数不是顶格的 1023:室内有灯光、阳光等人眼看不见的红外线,没火焰也有一定读数,这是正常的,不是模块坏了
  • D 口一直是 1:模块灵敏度太高,逆时针调模块上的电位器
  • 读数波动大:避开白炽灯等强红外光源(火焰传感器对红外线敏感,不止火焰会让它误报)
  • 阈值对不上:第二册阈值是 100(0~65535 量程),本册是 3(0~1023 量程)——量程不同,别直接照抄

安全提醒

  • 火焰测试必须有成人陪同,远离易燃物
  • 每次点火 1~2 秒即可,不要把火焰贴着探头

想一想

  1. 第二册阈值 100(量程 0~65535)和本册阈值 3(量程 0~1023),验算一下:它们对应的是不是差不多同一个电压?

    💡 查看答案

    算一算比例:

    • Python:100 ÷ 65535 ≈ 0.0015,× 3.3V ≈ 0.005V
    • C++:3 ÷ 1023 ≈ 0.0029,× 3.3V ≈ 0.010V

    很接近(都在 0.01V 量级),基本对应同一个电压——阈值这个东西本来就是标定出来的经验值,差一点没关系。

  2. 如果想分三级报警(读数 < 2 危险、2~4 注意、> 4 安全),判断部分该怎么改?(提示:第 4 章的 else if

    💡 查看答案
    cpp
    if (analogVal < 2) {
      Serial.println("危险!");
    } else if (analogVal <= 4) {
      Serial.println("注意");
    } else {
      Serial.println("安全");
    }

    注意顺序:范围最小的(最严格的)条件放前面,从小到大排。

  3. 如果把板载 LED 换成蜂鸣器报警,代码里要改哪几行?(提示:回顾第 8 章)

    💡 查看答案

    只需把"灯"换成"蜂鸣器",改三处:

    1. 引脚定义:const int LED_PIN = 25; 改成蜂鸣器实际接的引脚,比如 const int BEEP_PIN = 15;
    2. setup() 里的 pinMode(LED_PIN, OUTPUT) 对应改名(仍然是输出)
    3. loop() 里两处 digitalWrite 改成控制蜂鸣器——高电平蜂鸣器响,低电平安静

    写法和第 8 章控灯一模一样,只是控制的器件换了。

不积跬步,无以至千里;万里之行,始于当下。