Autor: Susai Florian
Grupa: 332
Seria: CA
Facultatea: Automatică și Calculatoare, Universitatea Politehnica din București
Proiectul reprezintă un dispozitiv hardware inteligent de achiziție a datelor (edge device) destinat monitorizării continue a parametrilor de mediu dintr-un spațiu (interior sau exterior).
Ce face sistemul:
Scopul proiectului: Realizarea unei stații de mediu compacte, autonome și extensibile, care să demonstreze conceptul de edge computing pe un microcontroller cu resurse limitate (ATmega328P) — datele nu sunt trimise brute către cloud, ci procesate matematic local și transformate în informație utilă (alerte, stări calitative).
Ideea de pornire: Multe stații meteo de uz casnic afișează doar valori brute (temperatură, presiune), fără a oferi interpretări. Am pornit de la întrebarea: “Cum aș putea face un sistem care, pe lângă numere, să spună utilizatorului dacă este Confort, Atenție sau Pericol, și care să prezică o furtună înainte ca aceasta să apară?”. Răspunsul a fost combinarea senzorilor cu algoritmi clasici de procesare (Heat Index Rothfusz, derivata presiunii în timp).
De ce este util:
Arhitectura sistemului este modulară și ierarhică, organizată pe trei niveluri funcționale:
Legendă:
| Modul | Rol | Interfață cu Arduino | Tip semnal |
|---|---|---|---|
| Fotorezistor (LDR) | Măsoară luminozitatea ambientală | A1 (intrare analogică) | Tensiune divizor 0–5V |
| MQ-2 | Detectează gaze inflamabile / fum | A0 (intrare analogică) | Tensiune analogică (AO) |
| BMP280 | Măsoară presiune și temperatură | SDA→A4, SCL→A5 (I2C) | Date digitale I2C |
| HC-05 Bluetooth | Comunicație bidirecțională cu telefonul | TXD→D0(RX), RXD→D1(TX) | UART asincron |
| LCD 16×2 + adaptor I2C | Afișare locală a datelor procesate | SDA→A4, SCL→A5 (I2C) | Date digitale I2C |
| Arduino Uno (ATmega328P) | Unitate centrală de procesare | — | Coordonator |
| Alimentare USB 5V | Magistrală de putere | VIN/5V + GND | DC 5V |
Fluxul logic al sistemului este ciclic și pornește de la întreruperea generată de Timer1 (configurat în mod CTC la 1 Hz). La fiecare tact, ISR-ul setează un flag care semnalează loop-ului principal că este momentul pentru o nouă achiziție. Loop-ul citește pe rând cei doi senzori analogici (LDR pe A1 și MQ-2 pe A0), aplicând filtrul de medie mobilă pe câte un buffer circular de 16 eșantioane, apoi interoghează BMP280 pe magistrala I2C pentru a obține temperatura și presiunea. Datele brute sunt apoi procesate matematic: temperatura este transformată în indice de disconfort (stare textuală — Confort / Atenție / Pericol), iar presiunea este comparată cu istoricul ultimelor 30 de minute pentru a calcula tendința barometrică. În final, rezultatele sunt afișate pe LCD prin aceeași magistrală I2C și transmise serializat prin UART către modulul HC-05, care le retransmite via Bluetooth către aplicația de pe telefon.
Notă privind partajarea I2C: atât LCD-ul cât și BMP280 folosesc aceeași magistrală (pinii A4/A5), dar au adrese diferite (de obicei 0x27 pentru LCD și 0x76/0x77 pentru BMP280), deci nu există conflict. Magistrala este gestionată secvențial de biblioteca Wire.h.
Notă privind UART și HC-05: modulul Bluetooth este conectat pe pinii hardware D0 (RX) și D1 (TX). Acest lucru poate intra în conflict cu portul serial USB folosit pentru programare/debug. În varianta finală se folosește direct USART hardware; pentru debug în timpul dezvoltării se recomandă SoftwareSerial pe alți pini (de ex. D2/D3) sau deconectarea HC-05 pe perioada uploadului de cod.
LDR-ul formează împreună cu un rezistor de 10 kΩ un divizor de tensiune clasic: un capăt al LDR se leagă la 5V, celălalt capăt al LDR se conectează în nodul comun cu rezistorul de 10 kΩ (acesta merge la GND), iar tensiunea din nodul comun este preluată pe pinul A1 al Arduino. Când lumina ambientală este puternică, rezistența LDR scade și tensiunea pe A1 crește; pe întuneric, fenomenul este invers.
| Capăt | Conectare |
|---|---|
| Capăt 1 LDR | 5V |
| Capăt 2 LDR (jonctiune cu R 10kΩ) | A1 |
| Celălalt capăt al R 10kΩ | GND |
| Pin MQ-2 | Arduino Uno |
|---|---|
| VCC | 5V |
| GND | GND |
| AO (analog out) | A0 |
| DO (digital out) | – (neutilizat) |
| Pin BMP280 | Arduino Uno |
|---|---|
| VCC | 3.3V (sau 5V dacă modulul are regulator on-board) |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
| CSB | VCC (forțează modul I2C) |
| SDO | GND (selectează adresa 0x76) |
| Pin adaptor I2C LCD | Arduino Uno |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 (partajat cu BMP280) |
| SCL | A5 (partajat cu BMP280) |
| Pin HC-05 | Arduino Uno |
|---|---|
| VCC | 5V |
| GND | GND |
| TXD | D0 (RX) |
| RXD | D1 (TX) — prin divizor 1kΩ/2kΩ (RXD HC-05 este la 3.3V logic) |
| EN | – (neutilizat în mod normal) |
| STATE | – (neutilizat) |
Semnal LDR (ADC pe A1): Tensiunea variază între ~0.1V (întuneric, LDR ~1MΩ) și ~4.5V (lumină puternică, LDR ~1kΩ). ADC-ul pe 10 biți returnează valori între ~20 și ~920.
Semnal MQ-2 (ADC pe A0): După perioada de preheating (20–60 secunde), AO returnează o tensiune proporțională cu concentrația de gaz. Valoare de bază (aer curat): ~0.5–1V (~100–200 ADC). Prag tipic de alarmă: ~2.5V (~500 ADC).
Semnal I2C (SDA/SCL): Frecvență standard 100 kHz, formă de undă caracteristică start condition – address byte – ack – data – stop condition. Tranzacțiile către BMP280 (citire registre 0xF7–0xFC) și către LCD (comenzi 4-bit prin PCF8574) sunt secvențiale.
Semnal UART (HC-05): Baud rate implicit 9600 bps, 8N1. Pachet tipic de aproximativ 28 octeți (T:24.5|P:1012|Tr:Stable|L:85%), durată de transmisie ~30 ms.
| Librărie | Rol | Sursă |
|---|---|---|
Wire.h | Comunicație I2C (master) | inclusă în Arduino core |
LiquidCrystal_I2C.h | Driver pentru LCD 16×2 cu adaptor PCF8574 | Frank de Brabander (GitHub) |
Adafruit_BMP280.h | Driver BMP280 | Adafruit Industries |
Adafruit_Sensor.h | Interfață unificată senzori (dependență BMP280) | Adafruit Industries |
avr/io.h, avr/interrupt.h | Acces direct la registre AVR și ISR | AVR-libc (toolchain) |
SoftwareSerial.h | UART pe pini software (dezvoltare/debug) | inclusă în Arduino core |
Datele citite de la LDR și MQ-2 prin ADC prezintă fluctuații datorate zgomotului electric și variațiilor naturale. Pentru atenuare se folosește un buffer circular de N = 16 eșantioane menținut în memoria RAM a microcontrollerului. La fiecare nouă conversie ADC, valoarea cea mai veche din buffer este suprascrisă cu cea nouă, iar media aritmetică a celor 16 eșantioane este recalculată. Doar această medie este folosită mai departe în procesarea aplicației, valorile brute fiind ignorate. Costul de memorie este minim (32 octeți pentru un buffer de 16 valori uint16_t), iar latența de răspuns la o schimbare reală a mediului este de ordinul a 16 secunde (la o frecvență de eșantionare de 1 Hz), ceea ce este perfect acceptabil pentru parametri de mediu cu variație lentă.
Formula completă a lui Rothfusz folosește atât temperatură cât și umiditate. În absența senzorului de umiditate (BMP280 nu măsoară RH), se folosește o versiune redusă bazată doar pe temperatură, cu mapare pe stări calitative:
“Confort”“Atenție”“Pericol”Rezultatul este transmis ca etichetă text, nu ca valoare numerică, către aplicația Bluetooth — utilizatorul primește direct o stare interpretabilă, nu trebuie să știe ce înseamnă “31.4°C” în termeni de confort.
Presiunea atmosferică citită de BMP280 este memorată într-un buffer circular cu rezoluție de 1 minut (30 de eșantioane pentru a acoperi o fereastră de 30 de minute). La fiecare ciclu, sistemul calculează diferența ΔP între valoarea curentă și cea de acum 30 de minute. Interpretarea este următoarea:
“Înrăutățire”“Stabil”“Îmbunătățire”Această tehnică reproduce principiul barometrelor mecanice clasice, în care o scădere bruscă a presiunii este indicator clar de schimbare meteorologică în următoarele câteva ore.
Pentru a evita funcția delay() (blocantă, care ar bloca complet microcontrollerul în timpul așteptării), se folosește Timer1 hardware configurat în modul CTC (Clear Timer on Compare Match), cu prescaler 1024, pentru a genera o întrerupere la fiecare 1 secundă exactă. Calculul valorii registrului OCR1A este: 16 MHz / 1024 / 1 Hz – 1 = 15624. ISR-ul aferent (TIMER1_COMPA_vect) este intenționat foarte scurt — doar setează un flag global volatil; procesarea propriu-zisă (citirea ADC, comunicația I2C, transmisia UART) se face în loop-ul principal pentru a păstra timpul petrecut în ISR sub câteva microsecunde. Această abordare garantează o eșantionare precisă în timp, esențială pentru calculul corect al derivatei presiunii și al mediei mobile.
Datele transmise nu sunt trimise haotic, ci serializate într-un format text delimitat, ușor de parsat atât de aplicații generice (Serial Bluetooth Terminal pe Android) cât și de o aplicație custom. Formatul este: T:24.5|P:1012.3|Tr:Stable|L:85%|G:120, unde:
T — temperatură (°C)P — presiune (hPa)Tr — tendință barometrică (Stable / Rain / Improving)L — luminozitate normalizată (%)G — valoare gaz MQ-2 (ADC raw)
Fiecare pachet se termină cu caracterul newline (\n) pentru a permite parsarea linie-cu-linie pe partea de telefon.
Codul este împărțit în module separate, fiecare cu responsabilitate unică, pentru a facilita testarea și mentenanța:
main.cpp — bucla principală, gestionare flag-uri, dispatchingsenzori_adc.cpp/.h — citire LDR și MQ-2, filtru medie mobilăcomunicatie_usart.c/.h — init UART, RX/TX, parser comenzidisplay_i2c.cpp/.h — wrapper LiquidCrystal_I2C, layout ecransenzor_bmp280.cpp/.h — wrapper Adafruit_BMP280procesare_matematica.cpp/.h — Heat Index, derivată presiunetimer_orchestrator.c/.h — init Timer1 CTC, ISRSchema electrică prezintă toate conexiunile pin-cu-pin între Arduino Uno (ATmega328P) și cele patru module (LDR, MQ-2, BMP280, LCD I²C, HC-05), incluzând cele două divizoare de tensiune (LDR + 10kΩ pentru semnalul analogic pe A1, respectiv 1kΩ/2kΩ pentru protecția pinului RXD al HC-05 la nivel logic 3.3V).