Ciljevi učenja
- Kombinovati uslove mraka i pokreta za uključivanje LED.
- Provjeriti polaritet DO i filtrirati promjene najmanje 100 ms.
- Produžavati zadržavanje od 10 s pri svakom opaženom PIR HIGH.
- Poništiti zadržavanje kada se prihvati svijetlo.
- Razlikovati PIR izlaz od pouzdanog dokaza prisustva osobe.
Prije početka
Kursevi 07 i 09: modul svjetla, PIR senzor, digitalno očitavanje i praćenje rezultata u Serial Monitoru.
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 model automatskog svjetla koje reaguje na mrak i pokret zajedno. Žuta LED predstavlja rasvjetu. PIR senzor prijavljuje pokret, a digitalni izlaz modula sa fotootpornikom govori da li je osvjetljenje prešlo podešeni prag. Po danu pokret ne uključuje LED. U mraku je uključuje, a poslije prestanka signala pokreta svjetlo ostaje uključeno još deset sekundi.
Program treba da riješi i manje očigledan slučaj: ako prostor postane svijetao, ranije zapamćeno zadržavanje mora se poništiti. Ponovno zamračivanje tada ne uključuje LED bez novog prisutnog signala PIR-a. Tako povezujemo dva uslova, vremensko filtriranje i pamćenje događaja u jednu razumljivu cjelinu. LED je nastavni prikaz; u ovoj vježbi ne priključujemo stvarnu rasvjetu.
Šta ćeš naučiti
- Kombinovati digitalne ulaze izrazom koji zahtijeva ispunjenost oba uslova.
- Razlikovati sirovi signal modula od prihvaćenog, stabilnog stanja.
- Napraviti zadržavanje izlaza koje svaki novi signal pokreta produžava.
- Poništiti zapamćeni događaj kada drugi uslov prestane da važi.
- Provjeriti polaritet digitalnog izlaza, umjesto pretpostavljanja značenja
HIGH. - Tumačiti ograničenja PIR senzora i digitalnog praga osvjetljenja.
Predznanje
Prethodno završi kurs 07 o modulu svjetla i kurs 09 o PIR senzoru. Potrebno je znati razliku između priključka za napajanje i GPIO-a, pravilno povezati LED sa serijskim otpornikom i pratiti ispis u Serial Monitoru. Pripremi oba senzora pojedinačno prije njihovog spajanja u ovaj projekat. Ako jedan modul daje neočekivane rezultate samostalno, složeniji program neće riješiti pogrešno povezivanje ili podešavanje praga.
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. |
| 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. |
| Modul senzora svjetlosti sa digitalnim izlazom | 1 | Modul sa fotootpornikom i komparatorom, potvrđen za 3,3 V; VCC/GND/DO. AO se ne koristi. Polaritet DO provjeriti. |
| Žuta LED dioda | 1 | Anoda A i katoda K. |
| Otpornik 220 Ω | 1 | Po jedan otpornik za svaku LED granu; 220 Ω iz kompleta. |
| Spojni kablovi | 12 | M-M ili F-M prema priključcima ploče. Okvirna količina; zavisi od rasporeda i vrste priključaka. |
Koristimo klasičnu ploču ESP32-WROOM-32, referentni HC-SR501 i modul fotootpornika sa priključcima VCC, GND i DO. Analogni izlaz AO ostaje nepovezan. Modul svjetla mora podržavati napajanje od 3,3 V i imati izlaz bez višeg napona prema ESP32. HC-SR501 u ovom primjeru koristi provjereni USB vod od 5 V, uz izlaz logike 3,3 V.
Fotografija kompleta ne potvrđuje raspored pinova, oznaku komparatora niti polaritet svakog primjerka. Provjeri oznake konkretnih modula. Za ovaj kurs nisu potrebni dodatni tranzistor ili dioda. Žuta LED i otpornik od 220 Ω čine jedini izlazni krug.
Dva uslova i tri vremenska pravila
Program prvih 60 sekundi drži LED ugašenom dok se PIR smiruje. Filter svjetla radi i tokom tog čekanja: prihvata novi nivo tek kada ostane nepromijenjen najmanje 100 ms, a do tada zadržava prethodno prihvaćeno stanje. To smanjuje reakcije na kratke promjene oko praga. Referentno podešavanje je #define DARK_LEVEL HIGH: zaklonjen fotootpornik treba da daje HIGH, a osvijetljen LOW. Kod modula sa obrnutim ponašanjem mijenja se ta konstanta.
| Uslov poslije početnog čekanja | Ponašanje LED |
|---|---|
| Prihvaćeno stanje je svijetlo. | Ugašena; prethodno zadržavanje se briše. |
Mrak i PIR HIGH. | Uključena; početak zadržavanja stalno se obnavlja. |
Mrak, PIR LOW, aktivno zadržavanje kraće od 10 s. | Ostaje uključena. |
Mrak, PIR LOW, bez zadržavanja ili poslije isteka. | Ugašena. |
PIR prijavljuje promjene infracrvenog zračenja u svom vidnom polju. Njegov izlaz može ostati visok i nakon što se osoba zaustavi ili ode, zavisno od podešavanja modula. Naših deset sekundi računa se od posljednjeg opaženog HIGH, pa se nadovezuje na ponašanje modula. Sistem ne dokazuje da je prostor prazan kada LED prestane svijetliti.
Šema i povezivanje
Šema povezivanja
PIR OUT je na GPIO33, a fotoosjetljivi DO na GPIO32. PIR se napaja sa provjerenog USB5V voda, fotoosjetljivi modul sa 3V3. DARK_LEVEL je HIGH za referencu; stvarni polaritet provjeri. Ne usmjeravaj indikacionu LED prema senzoru svjetlosti.
| Od | Do | Opis veze |
|---|---|---|
ESP32.USB5V | U1.VCC | HC-SR501: provjereni vod 5 V izveden sa USB napajanja ploče. |
ESP32.GND | U1.GND | Zajednička masa. |
U1.OUT | ESP32.GPIO33 | PIR OUT, logika 3,3 V, prema GPIO33. |
ESP32.3V3 | U2.VCC | Fotoosjetljivi modul potvrđen za 3,3 V. |
ESP32.GND | U2.GND | Zajednička masa. |
U2.DO | ESP32.GPIO32 | Digitalni izlaz; polaritet mraka provjeriti. AO ostaje nepovezan. |
ESP32.GPIO25 | R1.1 | Izlaz za LED (žuta) prema otporniku 220 Ω. |
R1.2 | D1.A | Serijski otpornik prema anodi A. |
D1.K | ESP32.GND | Katoda K prema masi. |
- Odspoji USB. Identifikuj 3V3, GND i potvrđeni USB vod od 5 V na konkretnoj ploči. Oznaka GPIO25 nije fizički dvadeset peti kontakt.
- Spoji GND oba senzora i katodu LED na zajedničku masu ESP32.
- Poveži VCC modula svjetla U2 na 3V3, a njegov DO na GPIO32. AO ostavi slobodan.
- Poveži VCC PIR modula U1 na provjerenih USB 5 V, a OUT na GPIO33. Provjeri da OUT odgovara logici 3,3 V.
- Poveži GPIO25 → R1, 220 Ω → anoda žute LED D1. Katoda ide na GND.
- Pregledaj cijeli sklop, naročito razdvajanje 5 V napajanja PIR-a od 3,3 V napajanja modula svjetla. Tek zatim priključi USB.
Postavi fotootpornik tako da ga sama LED ne osvjetljava. U suprotnom se može napraviti povratna sprega: LED se uključi, senzor vidi svjetlo, program ugasi LED, pa senzor opet vidi mrak. Ne priključuj drugo nezavisno napajanje od 5 V paralelno sa USB napajanjem ploče.
Priprema Arduino okruženja
U Arduino IDE-u 2.x odaberi esp32 by Espressif Systems 3.3.12, ploču ESP32 Dev Module i odgovarajući port. Otvori dark_motion_light/dark_motion_light.ino. Dodatne biblioteke nisu potrebne. Serial Monitor postavi na 115200 baud.
Prvo provjeri sirovi nivo ulaza pri osvjetljavanju i zaklanjanju fotootpornika. Podesi trimer modula tako da jasno razlikuje ta dva uslova. Ako mrak daje LOW, postavi DARK_LEVEL na LOW, ponovo učitaj program i ponovi probu. Ovaj prag je podešavanje komparatora; očitavanje DO nije mjerenje u luksima.
Kompletan Arduino program
#include <Arduino.h>
constexpr uint8_t PIR_PIN = 33;
constexpr uint8_t LIGHT_PIN = 32;
constexpr uint8_t LED_PIN = 25;
#ifndef DARK_LEVEL
#define DARK_LEVEL HIGH // Change to LOW only after checking your module.
#endif
constexpr uint32_t WARMUP_MS = 60000;
constexpr uint32_t LIGHT_FILTER_MS = 100;
constexpr uint32_t HOLD_MS = 10000;
constexpr uint32_t REPORT_MS = 500;
bool lightRawHigh = true;
bool lightStableHigh = true;
bool lightStableValid = false;
bool warmingUp = true;
bool holdActive = false;
bool ledOn = false;
uint32_t bootAt = 0;
uint32_t lightChangedAt = 0;
uint32_t lastMotionAt = 0;
uint32_t lastReportAt = 0;
void updateLightFilter(uint32_t now) {
const bool readingHigh = digitalRead(LIGHT_PIN) == HIGH;
if (readingHigh != lightRawHigh) {
lightRawHigh = readingHigh;
lightChangedAt = now;
}
if (static_cast<uint32_t>(now - lightChangedAt) >= LIGHT_FILTER_MS) {
lightStableHigh = lightRawHigh;
lightStableValid = true;
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
pinMode(PIR_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
bootAt = lightChangedAt = lastReportAt = millis();
lightRawHigh = lightStableHigh = digitalRead(LIGHT_PIN) == HIGH;
Serial.println("Dark + motion light: PIR warmup 60 s, LED OFF.");
Serial.println("Check DO polarity; cover the light sensor and observe DO.");
}
void loop() {
const uint32_t now = millis();
updateLightFilter(now);
const bool pirHigh = digitalRead(PIR_PIN) == HIGH;
const bool dark = lightStableValid &&
lightStableHigh == (DARK_LEVEL == HIGH);
if (warmingUp && static_cast<uint32_t>(now - bootAt) >= WARMUP_MS) {
warmingUp = false;
holdActive = false; // Motion from the warmup period is never replayed.
Serial.println("Warmup complete.");
}
if (warmingUp || !lightStableValid || !dark) {
holdActive = false;
ledOn = false;
} else {
if (pirHigh) {
holdActive = true;
lastMotionAt = now; // Each observed HIGH extends the hold.
} else if (holdActive && static_cast<uint32_t>(now - lastMotionAt) >= HOLD_MS) {
holdActive = false;
}
ledOn = holdActive;
}
digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
if (static_cast<uint32_t>(now - lastReportAt) >= REPORT_MS) {
lastReportAt = now;
Serial.print("DO="); Serial.print(lightRawHigh ? "HIGH" : "LOW");
Serial.print(" stable="); Serial.print(lightStableValid ? (lightStableHigh ? "HIGH" : "LOW") : "WAIT");
Serial.print(" dark="); Serial.print(dark ? "YES" : "NO");
Serial.print(" PIR="); Serial.print(pirHigh ? "HIGH" : "LOW");
Serial.print(" phase="); Serial.print(warmingUp ? "WARMUP" : "READY");
Serial.print(" LED="); Serial.println(ledOn ? "ON" : "OFF");
}
}
Za početnu probu zadrži 60 s smirivanja, 100 ms stabilizacije digitalnog svjetlosnog ulaza i 10 s zadržavanja poslije PIR signala. Klikni Verify, zatim Upload.
Kako čitati program
Funkcija updateLightFilter() odvojeno prati sirovi nivo svjetlosnog ulaza, vrijeme njegove posljednje promjene i prihvaćeno stanje. Pri svakom prelasku sirovog nivoa ponovo počinje interval stabilizacije. Tek neprekinutih 100 ms dopušta promjenu prihvaćenog značenja „mrak” ili „svijetlo”. lightStableValid potvrđuje da je barem jedan nivo prošao provjeru. Kratko zaklanjanje zato ne mora promijeniti izlaz.
Početno čekanje ima prednost nad svim pravilima uključivanja. Pokret tokom tog intervala ne prenosi se kao aktivno zadržavanje u kasniji rad. Poslije čekanja, HIGH sa PIR-a u prihvaćenom mraku aktivira zadržavanje i obnavlja vrijeme posljednjeg opaženog pokreta pri svakom prolazu petlje.
Posebna logička oznaka holdActive pamti da zadržavanje stvarno postoji, a lastMotionAt čuva posljednji opaženi HIGH. Sam vremenski pečat nula nije dovoljan: deset sekundi nakon pokretanja ne smije nastati privid ranijeg pokreta. Kada se prihvati svijetlo, oznaka zadržavanja se briše. Ako se zatim vrati mrak uz PIR LOW, nema događaja koji bi uključio LED.
Intervali se računaju oduzimanjem vrijednosti millis() tipa uint32_t, bez dugih blokirajućih pauza. Serial ispis približno svakih 500 ms služi posmatranju; njegova učestalost ne određuje reakciju LED. Razlikuj trenutak promjene senzora, trenutak prihvatanja filtera i kasniji ispis koji ih prikazuje.
Eksperiment i opažanja
Resetuj ploču, sačekaj početnih 60 s i mirno posmatraj senzor. Po mogućnosti podesi kratko zadržavanje HC-SR501 prema dokumentaciji modula. Za svaku probu zapiši sirovi DO, prihvaćeno osvjetljenje, PIR nivo i stanje LED.
| Proba | Očekivanje i objašnjenje |
|---|---|
| Pokret u svijetlom prostoru. | LED ostaje ugašena jer nije ispunjen uslov mraka. |
| Zakloni senzor duže od 100 ms i izazovi pokret. | LED se uključuje kada su oba uslova prihvaćena. |
PIR postane LOW dok traje mrak. | LED ostaje uključena još približno 10 s od posljednjeg opaženog HIGH. |
Ponovo izazovi PIR HIGH tokom zadržavanja. | Vrijeme zadržavanja se obnavlja. |
| Osvijetli senzor tokom zadržavanja. | Poslije stabilnih 100 ms LED se gasi i pamćenje se briše. |
Vrati mrak dok PIR ostaje LOW. | Staro zadržavanje ne oživljava; LED ostaje ugašena. |
| Osvijetli senzor samo 50 ms. | Prihvaćeno stanje ostaje isto ako nijedan novi nivo ne traje dovoljno dugo. |
Ovo su očekivanja za provjeru na radionici, a ne izvještaj o izvršenoj fizičkoj probi. Uz ispis od 500 ms možeš propustiti kratku sirovu promjenu, iako ju je petlja obradila.
Najčešći problemi
| Simptom | Šta provjeriti |
|---|---|
| LED radi samo po svjetlu. | Uporedi stvarni DO u mraku sa DARK_LEVEL; promijeni konstantu kada je polaritet obrnut. |
| LED se ritmično sama uključuje i isključuje. | Odmakni fotootpornik od LED i provjeri prag komparatora. |
| LED se ne gasi deset sekundi poslije odlaska. | Pogledaj PIR nivo: njegov interni tajmer možda još drži HIGH. |
| PIR daje događaje odmah poslije uključenja. | Sačekaj početni interval; provjeri položaj, modul i njegovo napajanje. |
| Ni u mraku ni pri pokretu nema svjetla. | Provjeri oba ulaza, polaritet LED, serijski otpornik i zajednički GND. |
| Zamračivanje kratko nakon osvjetljavanja ništa ne uključuje. | To je očekivano ako je zadržavanje obrisano i PIR ostaje LOW. |
Samostalni zadaci
- Skrati programsko zadržavanje sa 10 s na 3 s. Ne mijenjaj početno čekanje niti filter svjetla.
- Prati vremenski primjer: u mraku je posljednji PIR
HIGHopažen u 80. sekundi; prihvaćeno svijetlo nastaje u 82. sekundi, a mrak se vraća u 83. sekundi uz PIRLOW. Odredi stanje LED poslije svakog događaja. - Objasni zašto filter od 100 ms nije isto što i histereza sa dva različita praga osvjetljenja.
Razrađena rješenja
Promijeni HOLD_MS sa 10000 na 3000, odnosno postavi constexpr uint32_t HOLD_MS = 3000;. Ako je posljednji HIGH opažen u 80. sekundi i mrak se ne promijeni, LED se gasi približno u 83. sekundi. To ne skraćuje interni izlazni impuls PIR modula; skraćuje samo dodatno čekanje našeg programa.
U drugom zadatku LED u 80. sekundi svijetli. U 82. sekundi gasi se čim program prihvati svijetlo i briše se aktivno zadržavanje. U 83. sekundi ostaje ugašena: povratak mraka nije novi signal pokreta. Isti ishod važi i sa originalnim zadržavanjem od deset sekundi.
Vremenski filter traži da jedan digitalni nivo traje dovoljno dugo. Histereza bi koristila različite ulazne i izlazne pragove, na primjer dva različita nivoa osvjetljenja. Digitalni DO ne daje brojčanu osvijetljenost potrebnu da u ovom programu samostalno zadamo takva dva praga.
Provjera znanja
Da li HIGH uvijek znači mrak? Ne. Značenje zavisi od modula i podešavanja; konstanta mora odgovarati provjerenom ponašanju.
Zašto ne provjeravamo samo dark && motion? Takav izraz bi odmah ugasio LED kada PIR padne na LOW; dodatno pamćenje omogućava zadržavanje.
Šta se dešava pri neprekidnom PIR HIGH u mraku? LED ostaje uključena, a početak dodatnog čekanja stalno se pomjera.
Da li ugašena LED potvrđuje da nema osobe? Ne. PIR reaguje na promjene, a mirna osoba može ostati neprijavljena.
Zašto jasno svijetlo briše ranije pamćenje? Time sprečavamo da prethodni događaj ponovo uključi LED poslije kasnijeg zamračivanja bez aktuelnog PIR signala.
Primarni izvori
- SunFounder: modul fotootpornika, napajanje i polaritet DO.
- SunFounder: HC-SR501, napajanje i izlazni nivo.
- SunFounder: princip PIR senzora i vremenska podešavanja.
- Arduino: digitalRead().
- Arduino: millis().
- Espressif: digitalni ulazi i izlazi.
