PIR alarm: upravljanje stanjima, svjetlom i zvukom

Poveži PIR senzor, taster i aktivnu zujalicu u alarm sa početnim čekanjem, vremenom za izlazak i ručnim isključivanjem. Nauči kako stanja i neblokirajući tajmeri upravljaju cijelim projektom.

Zvuk, releji i interaktivni projektiSrednji nivo90 min

Ciljevi učenja

  • Definisati stanja alarma i događaje koji uzrokuju prelazak između njih.
  • Razlikovati početno smirivanje PIR senzora od vremena za izlazak.
  • Upravljati aktivnom zujalicom preko dodatnog tranzistorskog izlaza.
  • Zadržati alarm do ručnog isključivanja, nezavisno od kasnijeg PIR signala.
  • Istovremeno obrađivati taster, senzor i različite ritmove LED i zvuka.

Prije početka

Kursevi 09 i 13: PIR senzor, aktivna zujalica preko tranzistora, taster sa uklanjanjem odskakivanja i upravljanje vremenom pomoću millis().

Referentna postavka

Ploča u Arduino IDE-u
ESP32 Dev Module
Arduino-ESP32
3.3.12
Serial Monitor
115200 baud

Ovo je referentni profil, a ne identifikacija ploče sa fotografije. Za ESP32-C3/S2/S3 ili drugačije označenu ploču treba prilagoditi GPIO i provjeriti šemu prije spajanja.

Šta ćemo napraviti

Napravićemo edukativni alarm koji povezuje PIR senzor, taster, LED i aktivnu zujalicu. Poslije početnog smirivanja taster uključuje desetosekundno vrijeme za izlazak. Zatim senzor može aktivirati alarm: LED stalno svijetli, a zujalica daje kratke ponavljane signale. Jednom aktiviran alarm ostaje aktivan do pritiska tastera, čak i kada se izlaz senzora vrati na LOW.

Ovo je model za učenje upravljanja stanjima, a ne sertifikovani sigurnosni sistem. U njemu razlikujemo opažanje senzora, trenutno stanje programa i komandu korisnika.

Šta ćeš naučiti

  • Organizovati program u pet jasno definisanih stanja.
  • Istovremeno pratiti taster, senzor i više vremenskih intervala.
  • Napraviti alarm koji pamti događaj do ručnog isključivanja.
  • Prepoznati razliku između izlaznog kašnjenja i smirivanja senzora.
  • Upravljati aktivnom zujalicom preko tranzistora.

Predznanje

Završi kurs 09 o PIR senzoru i kurs 13 o aktivnoj zujalici. Potrebno je razumjeti INPUT_PULLUP, uklanjanje odskakivanja tastera i računanje proteklog vremena pomoću millis(). Prije objedinjavanja provjeri da senzor i tranzistorski izlaz rade u tim jednostavnijim primjerima.

Potrebna oprema

KomponentaKoličinaSpecifikacija i napomene
ESP32 razvojna ploča sa klasičnim ESP32-WROOM-32 modulom1GPIO nazivi moraju odgovarati referentnom profilu; fizički položaj izvoda provjeriti na ploči.
USB kabl za podatke i napajanje1Priključak prilagoditi ploči; komplet na slici navodi Micro-USB.
Eksperimentalna ploča1Komplet navodi 830 kontaktnih tačaka. Provjeriti eventualni prekid naponskih vodova.
Aktivni buzzer — referenca 5 V, do 20 mA1Fotografija navodi aktivni buzzer, ali ne potvrđuje njegov napon i struju. Za ovu šemu izaberi dokumentovani 5 V model sa najviše 20 mA radne struje.
Dodatni NPN tranzistor PN2222A1Obavezno dodatno — nije na slici kompletaDODATNO, nije naveden u kompletu. Identifikuj B/C/E prema tačnom proizvođaču; PN2222A i P2N2222A mogu imati različit raspored.

DODATNO: tranzistor nije naveden na fotografiji kompleta.

Dodatna zaštitna dioda 1N41481Obavezno dodatno — nije na slici kompletaDODATNO, nije navedena u kompletu. Prsten označava katodu K. U buzzer krugu katoda ide prema +5 V.

DODATNO: dioda nije navedena na fotografiji kompleta.

Otpornik 1 kΩ1Otpornik baze; u kursu 14 i paralelni otpornik piezo elementa. Količina ove vrijednosti u kompletu nije potvrđena.
Otpornik 10 kΩ1R2 je pull-down od baze Q1 prema GND; baza ostaje nisko dok GPIO ne upravlja.
PIR senzor pokreta HC-SR5011Napajanje modula 5 V sa USB voda ploče; izlaz OUT 3,3 V. Provjeriti raspored pinova, H/L kratkospojnik i trajanje impulsa.
Trenutni taster1Koristiti par priključaka koji se spaja pritiskom; ista strana četvoronožnog tastera može već biti spojena.
Crvena LED dioda1Anoda A i katoda K; provjeriti polaritet stvarne komponente.
Otpornik 220 Ω1Po jedan otpornik za svaku LED granu; 220 Ω iz kompleta.
Spojni kablovi15M-M ili F-M prema priključcima ploče.

Okvirna količina; zavisi od fizičkog rasporeda.

PN2222A tranzistor i zaštitna dioda 1N4148 dodatne su komponente koje nisu prikazane u fotografisanom kompletu. Referentna aktivna zujalica ima napajanje 5 V i nazivnu struju najviše 20 mA. Nepoznata zujalica ne potvrđuje te osobine samim izgledom; provjeri oznaku i dokumentaciju prije korišćenja ove šeme.

Referentni PIR je HC-SR501, napajan sa 5 V, sa izlazom kompatibilnim sa 3,3 V. Provjeri stvarne oznake modula i raspored priključaka. Koristimo klasični ESP32-WROOM-32 i samo njegovo USB napajanje.

Stanja i pravila prelaska

StanjeLED i zvukDogađaj za prelazak
WARMUPOba izlaza ugašena.Poslije 60 s prelazi u DISARMED.
DISARMEDOba izlaza ugašena.Novi pritisak započinje EXIT_DELAY.
EXIT_DELAYLED 250 ms uključena, 250 ms ugašena.Poslije 10 s prelazi u ARMED; pritisak otkazuje.
ARMEDLED 50 ms uključena, 1950 ms ugašena.PIR HIGH aktivira ALARM; pritisak isključuje.
ALARMLED stalno uključena; zvuk 200 ms, pauza 800 ms.Pritisak vraća DISARMED.

PIR tokom izlaznog kašnjenja ne aktivira zvuk. Međutim, ako je njegov izlaz već HIGH kada istekne deset sekundi, alarm se aktivira odmah. Program ne čeka novu uzlaznu ivicu. To je namjerna posljedica provjere trenutnog nivoa ulaza.

Šema i povezivanje

Šema povezivanja

PIR OUT sada ide na GPIO33, taster na GPIO27, a buzzer preko Q1 na GPIO26. PIR i aktivni buzzer koriste provjereno napajanje 5 V; PIR OUT je logika 3,3 V. D1 je zaštitna dioda, D2 je LED. Q1 i D1 nisu navedeni u kompletu.

Šema povezivanja — električne veze navedene u tabeli ispod
Šema povezivanjaUvećajSVGPNG
Veze · Šema povezivanja
OdDoOpis veze
ESP32.GPIO26R1.1Otpornik R1 od 1 kΩ ograničava struju baze.
R1.2Q1.BBaza dodatnog PN2222A tranzistora.
Q1.BR2.1R2 od 10 kΩ drži bazu nisko dok GPIO ne upravlja.
R2.2ESP32.GNDDrugi kraj pull-down otpornika.
Q1.EESP32.GNDEmiter prema zajedničkoj masi; provjeriti stvarni B/C/E raspored.
ESP32.USB5VBZ1.PLUSProvjereni USB vod 5 V prema pozitivnom izvodu buzzera.
D1.KESP32.USB5VKatoda zaštitne 1N4148, označena prstenom, prema +5 V.
BZ1.MINUSQ1.CKolektor prekida struju aktivnog buzzera.
D1.ABZ1.MINUSAnoda diode prema negativnom izvodu buzzera i kolektoru.
ESP32.USB5VU1.VCCHC-SR501 se napaja sa provjerenog USB voda 5 V.
ESP32.GNDU1.GNDZajednička masa.
U1.OUTESP32.GPIO33Izlaz PIR-a od 3,3 V; u kursu 15 koristi se GPIO33.
ESP32.GPIO27SW1.CONTACT_ATaster na ulaz sa INPUT_PULLUP.
SW1.CONTACT_BESP32.GNDDrugi izvod odabranog para kontakata, koji se spaja pritiskom.
ESP32.GPIO25R3.1Digitalni izlaz prema serijskom otporniku 220 Ω.
R3.2D2.AOtpornik prema anodi LED.
D2.KESP32.GNDKatoda LED prema masi.
  1. Isključi USB. Provjeri B, C i E konkretnog tranzistora u njegovom tehničkom listu; raspored nožica ne pretpostavljaj prema fotografiji.
  2. Spoji zajednički GND za ESP32, emiter Q1, PIR i ostale povratne veze.
  3. Poveži GPIO26 preko R1 od 1 kΩ sa bazom Q1. R2 od 10 kΩ poveži između baze i GND.
  4. Kolektor Q1 spoji na minus zujalice BZ1, a njen plus na potvrđeni USB priključak od 5 V na ploči.
  5. Diodu 1N4148 spoji paralelno sa zujalicom: anoda na njen minus, katoda sa označenom trakom na plus od 5 V.
  6. Spoji PIR VCC na isti USB izvod od 5 V, GND na zajednički GND, a OUT na GPIO33. U kursu 09 korišćen je GPIO27; sada je on rezervisan za taster.
  7. Spoji GPIO27 preko tastera na GND. Kod četvoronožnog tastera odaberi kontakte koji se stvarno spajaju pritiskom.
  8. Spoji GPIO25 preko R3 od 220 Ω na anodu LED D2; katodu spoji na GND.

Provjeri da ploča i USB izvor mogu napajati sve povezane potrošače. Ne spajaj drugo nezavisno napajanje od 5 V paralelno sa USB-om. Zujalica se ne spaja direktno na GPIO, a PIR OUT mora ostati u dozvoljenom opsegu logike 3,3 V.

Kako radi izlazni stepen

Kada GPIO26 postane HIGH, preko R1 teče struja baze i Q1 omogućava strujni put kroz zujalicu prema GND. Kada je GPIO LOW, tranzistor se isključuje. R2 drži bazu blizu GND kada je izlaz ploče privremeno visokoomski. Zaštitna dioda u normalnom radu ne provodi; njena orijentacija mora odgovarati šemi.

Aktivna zujalica sama stvara ton. Naš program određuje samo trajanje uključivanja i pauze, pa promjena intervala od 200 ms mijenja ritam alarma, a ne zadatu frekvenciju tona.

Priprema Arduino okruženja

U Arduino IDE-u 2.x odaberi esp32 by Espressif Systems 3.3.12, ESP32 Dev Module i port ploče. Dodatne biblioteke nisu potrebne. Otvori pir_alarm/pir_alarm.ino, pregledaj GPIO33 za senzor, GPIO27 za taster, GPIO26 za zujalicu i GPIO25 za LED. Serial Monitor koristi 115200 baud.

Kompletan Arduino program

pir_alarm.ino Arduino / C++
Preuzmi .ino

#include <Arduino.h>

constexpr uint8_t BUZZER_PIN = 26;
constexpr uint8_t PIR_PIN = 33;
constexpr uint8_t LED_PIN = 25;
constexpr uint8_t BUTTON_PIN = 27;
constexpr uint32_t DEBOUNCE_MS = 30;
constexpr uint32_t WARMUP_MS = 60000;
constexpr uint32_t EXIT_DELAY_MS = 10000;
// Each event is accepted once after 30 ms of stable input.
// If held during reset, a stable release is required before the first press.
struct DebouncedButton {
  bool rawHigh = true;
  bool stableHigh = true;
  bool armed = true;
  bool pressed = false;
  bool released = false;
  uint32_t rawChangedAt = 0;
  uint32_t pressStartedAt = 0;
  void begin(uint32_t now) {
    rawHigh = stableHigh = digitalRead(BUTTON_PIN) == HIGH;
    armed = rawHigh;
    rawChangedAt = now;
    pressed = released = false;
  }
  void update(uint32_t now) {
    pressed = released = false;
    const bool readingHigh = digitalRead(BUTTON_PIN) == HIGH;
    if (readingHigh != rawHigh) {
      rawHigh = readingHigh;
      rawChangedAt = now;
    }
    if (rawHigh != stableHigh && static_cast<uint32_t>(now - rawChangedAt) >= DEBOUNCE_MS) {
      stableHigh = rawHigh;
      if (stableHigh) {
        armed = true;
        released = true;
      } else if (armed) {
        pressed = true;
        pressStartedAt = rawChangedAt;
      }
    }
    // A short LOW pulse inhibited at the warmup boundary may never become
    // stable LOW. Still recognize a complete stable-HIGH release afterward.
    if (!armed && rawHigh && stableHigh && static_cast<uint32_t>(now - rawChangedAt) >= DEBOUNCE_MS) {
      armed = true;
    }
  }
};
DebouncedButton button;

enum AlarmState { WARMUP, DISARMED, EXIT_DELAY, ARMED, ALARM };
AlarmState state = WARMUP;
uint32_t stateSince = 0;
void enterState(AlarmState next, uint32_t now);

void enterState(AlarmState next, uint32_t now) {
  state = next;
  stateSince = now;
  Serial.print("State=");
  switch (state) {
    case WARMUP: Serial.println("WARMUP"); break;
    case DISARMED: Serial.println("DISARMED"); break;
    case EXIT_DELAY: Serial.println("EXIT_DELAY"); break;
    case ARMED: Serial.println("ARMED"); break;
    case ALARM: Serial.println("ALARM"); break;
  }
}

void updateOutputs(uint32_t now) {
  const uint32_t elapsed = static_cast<uint32_t>(now - stateSince);
  bool ledOn = false;
  bool buzzerOn = false;
  if (state == EXIT_DELAY) ledOn = (elapsed % 500UL) < 250UL;
  else if (state == ARMED) ledOn = (elapsed % 2000UL) < 50UL;
  else if (state == ALARM) {
    ledOn = true;
    buzzerOn = (elapsed % 1000UL) < 200UL;
  }
  digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
  digitalWrite(BUZZER_PIN, buzzerOn ? HIGH : LOW);
}

void setup() {
  Serial.begin(115200);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);
  digitalWrite(LED_PIN, LOW);
  pinMode(PIR_PIN, INPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  button.begin(millis());
  enterState(WARMUP, millis());
}

void loop() {
  const uint32_t now = millis();
  button.update(now);
  if (state == WARMUP) {
    if (static_cast<uint32_t>(now - stateSince) >= WARMUP_MS) {
      // Discard an unfinished press that began before warmup ended.
      // A button still LOW (raw or stable) must be released before arming.
      button.armed = button.rawHigh && button.stableHigh;
      enterState(DISARMED, now);
    }
  } else if (button.pressed) {
    if (state == DISARMED) enterState(EXIT_DELAY, now);
    else enterState(DISARMED, now);
  } else {
    if (state == EXIT_DELAY && static_cast<uint32_t>(now - stateSince) >= EXIT_DELAY_MS) enterState(ARMED, now);
    if (state == ARMED && digitalRead(PIR_PIN) == HIGH) enterState(ALARM, now);
  }
  updateOutputs(now);
}

Prvo koristi originalna vremena: 60 s početnog čekanja, 10 s za izlazak i ciklus zvuka 200/800 ms.

Kako čitati program

Promjenljiva state pamti trenutno stanje, a stateSince vrijeme njegovog početka. enterState() ažurira obje vrijednosti i ispisuje novi naziv u Serial Monitoru. Razlika vremena određuje prelazak. updateOutputs() iz te razlike izvodi ritam LED i zvuka, bez dugog delay() koji bi zaustavio čitanje tastera.

Taster mora zadržati novi nivo najmanje 30 ms. Događaj pritiska nastaje samo jednom po prihvaćenom pritisku. Tokom WARMUP debouncer se i dalje ažurira, ali događaji ne uključuju alarm: držanje tastera kroz završetak čekanja ne smije samo aktivirati sistem. Potrebni su otpuštanje i novi pritisak.

Prelaskom u ALARM program pamti aktiviranje kroz svoje stanje. Kasniji LOW sa PIR-a ne briše alarm. Pritisak ima prednost pri ručnom isključivanju. Računanje pomoću razlika tipa uint32_t podržava prelivanje brojača za ove kratke intervale.

Pokretanje

Klikni Verify, zatim Upload. Resetuj ploču i sačekaj 60 s bez pomjeranja modula. Taj interval je izbor vježbe; svaki modul mora biti dovoljno stabilan za probu. Podesi PIR prema njegovoj dokumentaciji, po mogućnosti na kratko zadržavanje, kako bi lakše pratio izlaz.

Pritisni i otpusti taster. Tokom brzog treptanja udalji se iz vidnog polja. Poslije prelaska na rijetko treptanje prođi ispred senzora. Sačekaj da senzor prestane prijavljivati pokret: alarm treba da ostane aktivan. Isključi ga novim pritiskom.

Eksperiment i opažanja

ProbaOčekivani rezultat
Drži taster tokom početnog čekanja i njegovog završetka.Sistem ostaje isključen do otpuštanja i novog pritiska.
Pritisni tokom izlaznog kašnjenja.Kašnjenje se otkazuje, LED se gasi.
PIR ostane HIGH na kraju kašnjenja.Alarm se aktivira odmah po uključivanju nadzora.
PIR vrati LOW poslije aktiviranja.Zvuk i stalna LED ostaju aktivni.
Drži taster poslije isključivanja.Sistem se ne uključuje ponovo samo zbog držanja.

Očekivanja u tabeli provjeri i zapiši na svojoj opremi; tabela ne predstavlja izvršeno fizičko testiranje.

Najčešći problemi

SimptomProvjera
Nema reakcije na pokret.Provjeri stanje i OUT na GPIO33, umjesto stare veze na GPIO27.
Alarm počinje čim istekne deset sekundi.PIR još daje HIGH; provjeri njegovo zadržavanje i položaj.
LED radi, zvuka nema.Provjeri aktivni tip, polaritet BZ1, B/C/E tranzistora i napajanje.
Alarm se ne gasi udaljavanjem.To je zadato pamćenje alarma; pritisni taster.
Reset pri zvuku.Isključi napajanje i provjeri struju potrošača, spojeve i USB izvor.

Samostalni zadatak i rješenje

Postavi EXIT_DELAY_MS na 5000. U zvučnom uslovu updateOutputs() promijeni < 200UL u < 100UL, a % 1000UL zadrži: dobijaš 100 ms zvuka i 900 ms pauze. Zadrži početno čekanje. Ako prihvaćeni pritisak nastupi u 72. sekundi od pokretanja, kada počinje nadzor? Koliko zvučnih početaka očekuješ tokom pet punih sekundi alarma?

Nadzor počinje približno u 77. sekundi, u prvom prolazu petlje poslije isteka intervala. Ciklus zvuka i dalje traje jednu sekundu, pa početke ima na 0, 1, 2, 3 i 4 s alarma. Udio uključenosti opada sa 20% na 10%. Ako je PIR tada već HIGH, alarm se aktivira bez dodatnog čekanja.

Zašto PIR LOW ne prekida zvuk? Zato što zvuk određuje zapamćeno stanje ALARM, a ne direktno izlaz senzora. Zašto ne koristimo desetosekundni delay()? Tokom njega ne bismo redovno obrađivali taster za otkazivanje.

Preuzimanja

Primarni izvori