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
| Komponenta | Količina | Specifikacija i napomene |
|---|---|---|
| ESP32 razvojna ploča sa klasičnim ESP32-WROOM-32 modulom | 1 | GPIO nazivi moraju odgovarati referentnom profilu; fizički položaj izvoda provjeriti na ploči. |
| USB kabl za podatke i napajanje | 1 | Priključak prilagoditi ploči; komplet na slici navodi Micro-USB. |
| Eksperimentalna ploča | 1 | Komplet navodi 830 kontaktnih tačaka. Provjeriti eventualni prekid naponskih vodova. |
| Aktivni buzzer — referenca 5 V, do 20 mA | 1 | Fotografija 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 PN2222A | 1Obavezno dodatno — nije na slici kompleta | DODATNO, 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 1N4148 | 1Obavezno dodatno — nije na slici kompleta | DODATNO, 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Ω | 1 | Otpornik baze; u kursu 14 i paralelni otpornik piezo elementa. Količina ove vrijednosti u kompletu nije potvrđena. |
| Otpornik 10 kΩ | 1 | R2 je pull-down od baze Q1 prema GND; baza ostaje nisko dok GPIO ne upravlja. |
| PIR senzor pokreta HC-SR501 | 1 | Napajanje modula 5 V sa USB voda ploče; izlaz OUT 3,3 V. Provjeriti raspored pinova, H/L kratkospojnik i trajanje impulsa. |
| Trenutni taster | 1 | Koristiti par priključaka koji se spaja pritiskom; ista strana četvoronožnog tastera može već biti spojena. |
| Crvena LED dioda | 1 | Anoda A i katoda K; provjeriti polaritet stvarne komponente. |
| Otpornik 220 Ω | 1 | Po jedan otpornik za svaku LED granu; 220 Ω iz kompleta. |
| Spojni kablovi | 15 | M-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
| Stanje | LED i zvuk | Događaj za prelazak |
|---|---|---|
WARMUP | Oba izlaza ugašena. | Poslije 60 s prelazi u DISARMED. |
DISARMED | Oba izlaza ugašena. | Novi pritisak započinje EXIT_DELAY. |
EXIT_DELAY | LED 250 ms uključena, 250 ms ugašena. | Poslije 10 s prelazi u ARMED; pritisak otkazuje. |
ARMED | LED 50 ms uključena, 1950 ms ugašena. | PIR HIGH aktivira ALARM; pritisak isključuje. |
ALARM | LED 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.
| Od | Do | Opis veze |
|---|---|---|
ESP32.GPIO26 | R1.1 | Otpornik R1 od 1 kΩ ograničava struju baze. |
R1.2 | Q1.B | Baza dodatnog PN2222A tranzistora. |
Q1.B | R2.1 | R2 od 10 kΩ drži bazu nisko dok GPIO ne upravlja. |
R2.2 | ESP32.GND | Drugi kraj pull-down otpornika. |
Q1.E | ESP32.GND | Emiter prema zajedničkoj masi; provjeriti stvarni B/C/E raspored. |
ESP32.USB5V | BZ1.PLUS | Provjereni USB vod 5 V prema pozitivnom izvodu buzzera. |
D1.K | ESP32.USB5V | Katoda zaštitne 1N4148, označena prstenom, prema +5 V. |
BZ1.MINUS | Q1.C | Kolektor prekida struju aktivnog buzzera. |
D1.A | BZ1.MINUS | Anoda diode prema negativnom izvodu buzzera i kolektoru. |
ESP32.USB5V | U1.VCC | HC-SR501 se napaja sa provjerenog USB voda 5 V. |
ESP32.GND | U1.GND | Zajednička masa. |
U1.OUT | ESP32.GPIO33 | Izlaz PIR-a od 3,3 V; u kursu 15 koristi se GPIO33. |
ESP32.GPIO27 | SW1.CONTACT_A | Taster na ulaz sa INPUT_PULLUP. |
SW1.CONTACT_B | ESP32.GND | Drugi izvod odabranog para kontakata, koji se spaja pritiskom. |
ESP32.GPIO25 | R3.1 | Digitalni izlaz prema serijskom otporniku 220 Ω. |
R3.2 | D2.A | Otpornik prema anodi LED. |
D2.K | ESP32.GND | Katoda LED prema masi. |
- Isključi USB. Provjeri B, C i E konkretnog tranzistora u njegovom tehničkom listu; raspored nožica ne pretpostavljaj prema fotografiji.
- Spoji zajednički GND za ESP32, emiter Q1, PIR i ostale povratne veze.
- Poveži GPIO26 preko R1 od 1 kΩ sa bazom Q1. R2 od 10 kΩ poveži između baze i GND.
- Kolektor Q1 spoji na minus zujalice BZ1, a njen plus na potvrđeni USB priključak od 5 V na ploči.
- Diodu 1N4148 spoji paralelno sa zujalicom: anoda na njen minus, katoda sa označenom trakom na plus od 5 V.
- 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.
- Spoji GPIO27 preko tastera na GND. Kod četvoronožnog tastera odaberi kontakte koji se stvarno spajaju pritiskom.
- 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
#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
| Proba | Oč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
| Simptom | Provjera |
|---|---|
| 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.
