🔥 سیستم اعلام حریق با آردوینو: سنسور گاز MQ-2، سنسور دما، آژیر و ریست (کد کامل)
در این پروژه یک سیستم اعلام حریق با آردوینو میسازیم که سه نشانهی آتش را زیر نظر دارد: دود و گاز با سنسور MQ-2، دمای بالا و افزایش ناگهانی دما با سنسور TMP36. دو سطح هشدار دارد (احتیاط و خطر)، آژیر دوصدا میزند، یک رله برای فن تخلیه یا آژیر بیرونی روشن میکند و مثل پنلهای واقعی، هشدارش «قفل» میشود تا کسی ریستش کند. همهچیز را اول در شبیهساز آردوینو میسازیم؛ بدون فندک و بدون دود.
دستگاه چطور تصمیم میگیرد؟
| وضعیت | شرط | خروجی |
|---|---|---|
| گرم شدن | ۲۰ ثانیهی اول بعد از روشن شدن | LED سبز چشمک میزند |
| عادی | همهچیز زیر آستانه | LED سبز روشن |
| احتیاط | گاز ≥ ۳۰۰ یا دما ≥ ۴۵ درجه | LED زرد و یک بوق کوتاه هر دو ثانیه |
| خطر | گاز ≥ ۴۵۰، یا دما ≥ ۵۷ درجه، یا ۸ درجه افزایش در حدود یک دقیقه، یا شعله | LED قرمز چشمکزن، آژیر دوصدا، رله روشن |
عدد ۵۷ درجه از دتکتورهای حرارتی ثابت میآید و «افزایش سریع» از دتکتورهای نرخ افزایش: آتش واقعی دما را خیلی تند بالا میبرد، در حالی که یک روز گرم تابستان آرام گرم میشود.
قطعهها
- آردوینو اونو
- سنسور گاز و دود MQ-2
- سنسور دمای TMP36
- بازر
- سه LED: سبز، زرد و قرمز، هر کدام با یک مقاومت ۲۲۰ اهم
- یک دکمهی فشاری برای سکوت و ریست
- یک ماژول رله برای فن تخلیه یا آژیر بیرونی (کمولتاژ)
- اختیاری روی نمونهی واقعی: ماژول سنسور شعلهی مادون قرمز (مثل KY-026). این سنسور در شبیهساز نیست و در کد با یک کلید روشن و خاموش میشود.
سیمکشی
| قطعه | پایه | به آردوینو |
|---|---|---|
| MQ-2 | + / OUT (آنالوگ) / − | 5V / A0 / GND |
| TMP36 | + / OUT / − | 5V / A1 / GND |
| دکمه | دو پایهی روبهرو | D2 و GND |
| سنسور شعله (اختیاری) | DO / VCC / GND | D3 / 5V / GND |
| رله | IN / VCC / GND | D4 / 5V / GND |
| LED سبز، زرد، قرمز | پایهی بلند از راه ۲۲۰ اهم | D5، D6، D7؛ پایهی کوتاه به GND |
| بازر | + / − | D8 / GND |
کد کامل
// Fire and gas alarm: MQ-2 smoke/gas sensor + TMP36 heat sensor
// (+ optional flame sensor), three LEDs, a two-tone siren and a relay.
const int GAS_PIN = A0; // MQ-2 analog output
const int TEMP_PIN = A1; // TMP36 output
const int BUTTON_PIN = 2; // silence / reset button to GND
const int FLAME_PIN = 3; // optional flame sensor DO (LOW = flame)
const int RELAY_PIN = 4; // exhaust fan or external siren (low voltage!)
const int GREEN_PIN = 5;
const int YELLOW_PIN = 6;
const int RED_PIN = 7;
const int BUZZER_PIN = 8;
const bool HAS_FLAME_SENSOR = false; // true if you wired a flame sensor
const int GAS_WARN = 300; // calibrate in clean air first!
const int GAS_ALARM = 450;
const float TEMP_WARN = 45.0; // C
const float TEMP_ALARM = 57.0; // C, a common fixed-heat detector level
const float RISE_ALARM = 8.0; // C rise within about one minute
const unsigned long WARMUP_MS = 20000; // MQ-2 heater warm-up
const unsigned long SILENCE_MS = 60000; // the button mutes the siren this long
enum State { WARMUP, NORMAL, WARNING, ALARM };
State state = WARMUP;
bool latched = false; // an alarm stays on until someone resets it
bool silenced = false;
unsigned long silencedAt = 0, lastMinute = 0, lastReport = 0;
int gas = 0;
float tempC = 25.0, tempMinuteAgo = 25.0;
void readSensors() {
gas = (gas * 3 + analogRead(GAS_PIN)) / 4; // smooth the noisy MQ-2
float volts = analogRead(TEMP_PIN) * 5.0 / 1023.0;
tempC = (volts - 0.5) * 100.0; // TMP36: 0.5 V at 0 C, 10 mV per C
}
State evaluate() {
bool flame = HAS_FLAME_SENSOR && digitalRead(FLAME_PIN) == LOW;
bool fastRise = tempC - tempMinuteAgo >= RISE_ALARM;
if (flame || gas >= GAS_ALARM || tempC >= TEMP_ALARM || fastRise) return ALARM;
if (gas >= GAS_WARN || tempC >= TEMP_WARN) return WARNING;
return NORMAL;
}
bool buttonPressed() {
static bool last = HIGH;
static unsigned long changedAt = 0;
bool reading = digitalRead(BUTTON_PIN);
if (reading != last && millis() - changedAt > 50) { // 50 ms debounce
changedAt = millis();
last = reading;
return reading == LOW;
}
return false;
}
void setTone(int freq) {
static int current = -1;
if (freq == current) return; // only touch the buzzer when the sound changes
current = freq;
if (freq > 0) tone(BUZZER_PIN, freq);
else noTone(BUZZER_PIN);
}
void updateOutputs(unsigned long now) {
bool fast = (now / 250) % 2; // flips every 250 ms
digitalWrite(GREEN_PIN, (state == NORMAL || (state == WARMUP && fast)) ? HIGH : LOW);
digitalWrite(YELLOW_PIN, state == WARNING ? HIGH : LOW);
digitalWrite(RED_PIN, (state == ALARM && fast) ? HIGH : LOW);
digitalWrite(RELAY_PIN, state == ALARM ? HIGH : LOW);
if (state == ALARM && !silenced) setTone(fast ? 1300 : 900); // two-tone siren
else if (state == WARNING && !silenced && now % 2000 < 150) setTone(2000); // short chirp
else setTone(0);
}
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(FLAME_PIN, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
gas = analogRead(GAS_PIN);
Serial.println("Fire alarm: warming up the gas sensor...");
}
void loop() {
unsigned long now = millis();
readSensors();
if (state == WARMUP) {
if (now >= WARMUP_MS) {
state = NORMAL;
tempMinuteAgo = tempC;
lastMinute = now;
Serial.println("Ready.");
}
} else {
if (now - lastMinute >= 60000) { // remember the temperature once a minute
tempMinuteAgo = tempC;
lastMinute = now;
}
State s = evaluate();
if (s == ALARM) latched = true;
if (latched) s = ALARM;
if (buttonPressed()) {
if (latched && evaluate() != ALARM) { // danger is gone: reset
latched = false;
silenced = false;
s = evaluate();
Serial.println("Reset.");
} else if (s != NORMAL) { // still dangerous: just mute
silenced = true;
silencedAt = now;
Serial.println("Siren silenced for 60 s.");
}
}
if (silenced && now - silencedAt > SILENCE_MS) silenced = false;
if (s == NORMAL) silenced = false;
if (s != state) {
state = s;
if (state == ALARM) Serial.println("!!! ALARM !!!");
else if (state == WARNING) Serial.println("Warning");
else Serial.println("Normal");
}
}
updateOutputs(now);
if (now - lastReport >= 500) { // name:value pairs for the Serial Plotter
lastReport = now;
Serial.print("gas:");
Serial.print(gas);
Serial.print(" temp:");
Serial.println(tempC);
}
delay(20);
}
توضیح بخشهای مهم
- ماشین حالت: دستگاه همیشه در یکی از چهار وضعیت
WARMUP،NORMAL،WARNINGیاALARMاست. تابعevaluate()فقط میگوید سنسورها الان چه میگویند وloopتصمیم میگیرد با آن چه کند. این جدا کردن، کد را برای گزارش و دیباگ خیلی خوانا میکند. - میانگینگیری:
gas = (gas * 3 + analogRead(GAS_PIN)) / 4هر عدد جدید را فقط یکچهارم حساب میکند. نوسانهای لحظهای MQ-2 صاف میشوند و هشدار الکی نمیآید. - فرمول TMP36: این سنسور در صفر درجه ۰٫۵ ولت میدهد و به ازای هر درجه ۱۰ میلیولت بالا میرود. پس ولتاژ را از عدد آنالوگ حساب میکنیم، ۰٫۵ را کم میکنیم و در ۱۰۰ ضرب میکنیم.
- افزایش سریع دما: هر یک دقیقه دمای فعلی در
tempMinuteAgoذخیره میشود. اگر دما از آن عدد ۸ درجه بالاتر برود، حتی اگر هنوز به ۵۷ نرسیده باشد، هشدار خطر میدهد. - قفل شدن: متغیر
latchedبعد از اولین خطر روشن میماند. دکمه اگر خطر هنوز هست فقط آژیر را ۶۰ ثانیه ساکت میکند، و اگر خطر رفته باشد، سیستم را ریست میکند. - آژیر بدون
delay:(now / 250) % 2هر ربع ثانیه بین صفر و یک عوض میشود و همین هم چشمک LED قرمز است و هم دو صدای آژیر.setToneفقط وقتی صدا عوض شده بازر را دست میزند.
قدمبهقدم در شبیهساز
- قطعهها را طبق جدول بچین و سیم بزن. اگر جایی اشتباه وصل شده باشد، دکمهی «چرا کار نمیکند؟» به فارسی میگوید کدام سیم.
- کد را اجرا کن. ۲۰ ثانیه LED سبز چشمک میزند و بعد «Ready.» در سریال مانیتور میآید.
- زبانهی نمودار را باز کن؛ دو خط
gasوtempرا زنده میبینی. - روی سنسور گاز کلیک کن و مقدارش را کمکم بالا ببر. اول LED زرد و بوق کوتاه، بعد آژیر و LED قرمز.
- گاز را پایین بیاور: آژیر هنوز میزند (قفل). دکمه را بزن تا ریست شود.
- دما را یکباره ۱۰ درجه بالا ببر تا هشدار «افزایش سریع» را ببینی.
آردوینو اونو در تینکرکد فارسی رایگان است و این پروژه کاملاً بدون اشتراک اجرا میشود. برای پروژهی آمادهی مشابه، دزدگیر کامل و درس سیستم امنیتی را ببین. برای آشنایی دقیقتر با خود سنسور، سنسور گاز MQ-2 با آردوینو را بخوان.
کالیبره کردن روی نمونهی واقعی
عدد MQ-2 به دما، رطوبت و حتی خود سنسور بستگی دارد. سنسور را چند دقیقه در هوای تمیز روشن بگذار، عدد gas را در نمودار ببین و آستانهی احتیاط را حدود ۱۵۰ واحد بالاتر از آن و آستانهی خطر را حدود ۳۰۰ واحد بالاتر بگذار. برای تست، فقط با نظارت بزرگتر و از فاصله، چند ثانیه بخار الکل یا اسپری مخصوص تست دتکتور کافی است؛ هرگز شعله یا گاز شهری. گرمکن MQ-2 حدود ۱۵۰ میلیآمپر میکشد و داغ میشود؛ آن را در جعبهی سوراخدار نصب کن و اگر پروژه با باتری کار میکند، عمر باتری را حساب کن.
اشکالهای رایج
- بلافاصله بعد از روشن شدن آژیر میزند: سنسور هنوز گرم نشده یا آستانهها برای سنسور تو پایین است.
WARMUP_MSرا روی نمونهی واقعی بیشتر کن. - دما ۵۰- درجه یا عدد عجیب نشان میدهد: پایههای TMP36 جابهجاست. سمت تخت سنسور رو به توست: چپ +، وسط OUT، راست −.
- دکمه کاری نمیکند: دکمه باید بین D2 و GND باشد و پایههای روبهروی آن را استفاده کنی.
- صدای بازر خشدار است: بازر اکتیو داری؛
toneبا بازر پسیو صدای تمیز میدهد. - رله روشن نمیشود: بعضی ماژولها با LOW روشن میشوند. در
updateOutputsجای HIGH و LOW رله را عوض کن.
قدمهای بعدی
یک ماژول رله میتواند بهجای فن یک آژیر ۱۲ ولتی را روشن کند. با یک LCD I2C عددها را روی دستگاه نشان بده، یا پروژه را به ESP32 ببر تا هشدار در گوشی هم بیاید؛ ایدهاش در ۳۰ ایده پروژه اینترنت اشیا هست.
اعلام حریق را رایگان در شبیهساز بساز 🔥سؤالهای رایج
میشود این پروژه را بهجای دتکتور دود واقعی در خانه نصب کرد؟
نه. این یک پروژهی آموزشی است. دتکتورهای استاندارد آزمونهای ایمنی سخت را گذراندهاند و باتری پشتیبان دارند. این دستگاه را برای یادگیری، نمایشگاه و هشدار کمکی بساز، نه جایگزین تجهیزات استاندارد.
چرا هشدار بعد از پاک شدن هوا خاموش نمیشود؟
چون «قفلشونده» است، مثل پنلهای اعلام حریق واقعی. اگر آتش یک لحظه شعله کشید و خاموش شد، کسی باید بفهمد و بررسی کند. فقط وقتی خطر رفع شده باشد، دکمه هشدار را ریست میکند.
سنسور MQ-2 چقدر طول میکشد تا آماده شود؟
گرمکن داخلیاش در دقیقههای اول عدد ناپایدار میدهد. برای استفادهی واقعی چند دقیقه صبر کن و برای دقت بیشتر سنسور نو را یک بار ۲۴ ساعت روشن بگذار. در کد ۲۰ ثانیه گذاشتهایم تا در شبیهساز منتظر نمانی.