Autor: Socea Mihai Grupa 332CD
Am realizat un sistem de deschidere / inchidere automata a unei usi prin calcularea distantei dintre obiect si senzor.
Daca distanta se modifica drastic ( persoana se apropie de usa, prin intermediul unui servomotor usa se va deschide.
Scopul proiectului este sa creez un design simplu si eficient pentru un lucru folosit de milioane de oameni.
Flux operațional:
Proiectul realizează un mecanism de deschidere şi închidere automată a unei uşi folosind un senzor ultrasonic şi un servomotor SG90 controlate de un Arduino Nano. Uşa rămâne blocată (închisă) în mod normal; la detectarea unei variaţii bruște de distanţă faţă de senzor mai mare de 100 cm, sistemul o deblochează (deschide) automat. După 5 secunde fără nicio nouă variaţie majoră de distanţă, uşa se retrage în poziţia de “închis” automat pentru siguranţă.
</note>
Nr. crt. | Componentă | Tip de semnal / protocol | Pini Arduino folosiți |
---|---|---|---|
1 | Arduino Nano ATmega328P | GPIO, PWM, I²C | – |
2 | Senzor ultrasonic HC-SR04 | GPIO (Digital Input/Output) | D8 (TRIG), D9 (ECHO) |
3 | Servomotor SG90 | PWM | D10 |
4 | LED alb (închis) | GPIO – ieșire digitală | D3 |
5 | LED alb (deschis) | GPIO – ieșire digitală | D4 |
6 | Buzzer activ 5 V | GPIO – ieșire digitală | D6 |
7 | Buton tactil (push-button 6×6×6) | GPIO (INPUT_PULLUP) | D7 |
8 | Modul RTC DS3231 cu baterie tampon | I²C | A4 (SDA), A5 (SCL) |
9 | EEPROM AT24C256 | I²C | A4 (SDA), A5 (SCL) |
10 | Rezistor 220 Ω | Limitare curent LED | În serie cu LED-urile pe D3 & D4 |
11 | Breadboard HQ + fire jumper | – | – |
Componentă / Aspect | Detalii |
---|---|
IDE | Arduino IDE |
Microcontroler | Arduino Nano (ATmega328P + CH340) |
Compilator | AVR-GCC (prin Arduino Toolchain) |
Limbaj | C/C++ cu acces direct la registre |
Biblioteci | Fără librării externe (I2C, PWM, GPIO, Timere implementate manual) |
Funcționalitate |
---|
Control tastatură matricială 4×4 (scanare + debouncing) |
Verificare PIN + contor de greșeli |
Blocare automată după 10s de la deblocare (millis()) |
Servomotor SG90 acționat manual (fără Servo.h) |
LED-uri pentru semnalizare (GPIO) |
Buzzer pasiv cu secvențe sonore (tone() manual) |
Afișare mesaje pe LCD 1602 (I2C low-level TWI) |
Laborator | Concept | Aplicație în proiect |
---|---|---|
Lab 0 | GPIO | Configurarea pinilor TRIG (OUTPUT) și ECHO (INPUT) pentru senzorul ultrasonic, precum și controlul LED-urilor de stare (LED_OPEN_PIN, LED_CLOSED_PIN) și al butonului de reset. |
Lab 2 | Întreruperi | Măsurarea precisă a duratei semnalului ECHO folosind Input Capture pe Timer1 (INT0/Input Capture) în loc de funcția blocking pulseIn(), pentru calcularea distanței. |
Lab 3 | Timere & PWM | Generarea semnalului PWM pentru controlul servomotorului SG90 (Timer1 Fast PWM, 600 µs = 0°, 1500 µs = 90°) și crearea tonurilor pentru buzzer (Timer0 CTC pentru 262 Hz/175 Hz). |
Lab 6 | I2C (fără librării) | Comunicare low-level cu modulul RTC DS3231 și cu EEPROM-ul extern AT24C256 prin TWI, pentru salvarea timestamp-urilor și a istoricului stării ușii (open/closed). |
initUltrasonic()
Configurează Timer1 în modul Input Capture și interrupt INT0 pentru măsurarea duratei semnalului ECHO. PIN-ul TRIG este setat ca OUTPUT, iar ECHO ca INPUT. La fiecare front de atac pe ECHO (ICES1 = 1), se capturează valoarea în ICR1; la frontul de coborâre (ICES1 = 0), se reia capturarea și se calculează distanța în centimetri folosind formula dist_cm = (ICR1_value * 0.666) / 58.
readDistance()
Trimite un impuls de 10 μs pe TRIG_PIN (bitul corespunzător este setat HIGH timp de delayMicroseconds(10), apoi LOW) și așteaptă completarea Input Capture (flag ICIF1). După ce ICR1 este citit, normalizează valoarea ținând cont de prescaler (8) și convertește în cm. Returnează distanța măsurată sau -1 dacă nu s-a recepționat semnal în timeout.
setDoorPosition(uint16_t pulse_us)
Configurează Timer1 în Fast PWM (WGM13:0 = 14, CS11 = 1) cu ICR1 = 19999 (periodă 20 ms). Pune OCR1A = (pulse_us * 2) (0.666 μs/tick la F_CPU = 16 MHz și prescaler = 8 → 1 tick ≈ 0.5 μs, ajustat experimental). Pentru deschis, apelează setDoorPosition(1500), iar pentru închis, setDoorPosition(600). Nu utilizează nicio librărie externă.
saveStateToEEPROM(bool state)
Inițializează interfața I2C (TWBR = 72, TWCR = (1«TWEN)), trimite START, adresa EEPROM-ului extern (0xA0), adresa internă de scriere (ADDR_IS_OPEN), apoi octetul state ? 1 : 0. După fiecare octet transmis (TWINT = 1), verifică codul de stare TWSR și, la final, trimite STOP. Astfel păstrează starea ușii (0 = închis, 1 = deschis) în memorie nevolatilă externă.
loadStateFromEEPROM()
Inițializează TWI, transmite START, adresa EEPROM (0xA0) și offsetul 0, apoi transmite REPEATED START, adresa pentru citire (0xA1), citește un octet (prin generarea NACK la final), și oprește TWI. Apoi, dacă valoarea citită este 1, apelează setDoorPosition(1500), aprinde LED_OPEN (PORTD |= (1«LED_OPEN_PIN)) și stinge LED_CLOSED; în caz contrar, setează setDoorPosition(600), aprinde LED_CLOSED și stinge LED_OPEN.
handleAutoClose()
Verifică în bucla principală dacă isOpen == true și (millis() - lastChangeTs) > CLOSE_DELAY_MS. Dacă da, apelează setDoorPosition(600) (închide), stinge LED_OPEN și aprinde LED_CLOSED, apelează playTone(175, 500), apelează saveStateToEEPROM(false), și actualizează isOpen = false și lastChangeTs = millis().
playTone(uint16_t freq, uint16_t duration_ms)
Configurează Timer0 în modul CTC (WGM01 = 1, prescaler = 64). Calculează OCR0A = (F_CPU / (2 * 64 * freq)) - 1. Activează OCIE0A pentru toggling în ISR(TIMER0_COMPA_vect): la fiecare comă, toggl-ează pinul buzzer (PORTB ^= (1«BUZZER_PIN)). După duration_ms (verificat cu millis()), dezactivează OCIE0A, oprește Timer0 (CS00..2 = 0) și resetează pinul buzzer pe LOW.
logEventToEEPROM(uint8_t eventCode)
Configurează interfața SPI (SPCR = (1«MSTR)|(1«SPE)|(1«SPR0), DDRB |= (1«PB3)|(1«PB5)|(1«PB7) pentru MOSI/SCK/CS). Trimite START pe CS (PB2 = 0), apoi trimite adresa paginii și offset-ul, apoi trimite eventCode și eventual timestamp primit din rtc_getTime(). Așteaptă SPIF după fiecare octet, apoi trimite STOP (PB2 = 1). Dacă adresa ajunge la limita paginii (64 B), incrementează la următoarea pagină (circular).
rtc_getTime()
Configurează TWI (TWBR = 72, TWCR = (1«TWEN)), transmite START, adresa DS3231 (0xD0), comanda de citire (0x00), apoi citește 7 octeți BCD (secunde, minute, ore, zi, dată, lună, an) cu ACK pentru fiecare, iar la ultimul octet cu NACK. Convertește fiecare octet de la BCD la decimal și returnează structura cu ora curentă.
Validarea funcțională a fost realizată fizic, cu testarea tuturor scenariilor:
Distanță > DELTA_THRESHOLD → readDistance() detectează delta semnificativă, setDoorPosition(1500) (deschis), LED_OPEN_PIN HIGH, LED_CLOSED_PIN LOW, saveStateToEEPROM(true), playTone(262, 200), logEventToEEPROM(0x01).
Inactivitate > CLOSE_DELAY_MS → handleAutoClose() închide ușa (setDoorPosition(600)), LED_CLOSED_PIN HIGH, LED_OPEN_PIN LOW, playTone(175, 500), saveStateToEEPROM(false), logEventToEEPROM(0x02).
Buton de reset (INT1) → ISR(INT1_vect) inițiază direct setDoorPosition(600), LED_CLOSED_PIN HIGH, LED_OPEN_PIN LOW, playTone(175, 300), openTs = millis(), saveStateToEEPROM(false), logEventToEEPROM(0x03).
Timeout ADC Low Battery → dacă ADC_read(A0) < THRESHOLD_ADC, se aprinde un LED roșu de avertizare, se trimite prin UART mesajul „LOW BATTERY”, playTone(300, 1000), logEventToEEPROM(0x04).
Componentă | Metodă de calibrare | Rezultat / Valoare finală |
---|---|---|
Servomotor SG90 | Test empiric PWM manual | 600 µs = 0° (închis), 1500 µs = 90° (deschis) |
Tastatură 4×4 | Ajustare debounce cu millis() | Debounce = 50 ms |
LCD 1602 I2C | Ajustare timpi între comenzi și date | Funcționare stabilă, fără caractere corupte |
Buzzer piezoelectric | Reglare durată şi frecvenţă tonuri | Ton pozitiv: 262–330 Hz; eroare: 262–175 Hz |
• Sistemul de deschidere/închidere funcționează stabil și complet automatizat.
• Detectarea variației bruște de distanță (>100 cm) activează servo-motorul cu precizie.
• Ușa rămâne blocată până la detectarea unui delta >100 cm, apoi se deschide instantaneu.
• Închiderea automată după 5 s de inactivitate este realizată non-blocant (millis()).
• LED-urile albe indică clar starea: unul pentru „închis”, celălalt pentru „deschis”.
• Buzzer-ul emite un semnal scurt la deschidere și un semnal lung la închidere automată.
• Butonul de reset forțează imediat închiderea ușii și resetează timer-ul de auto-lock.
• Comunicația cu senzorul ultrasonic se face low-level, fără librării suplimentare.
• Toate componentele (ultrasonic, servo, LED, buzzer, buton) au fost testate fizic și redate în condiții reale.
Am realizat de la zero o ușă inteligentă cu Arduino, trecând prin planificarea logicii, achiziția componentelor și documentarea din surse online și tutoriale YouTube. Experiența practică a fost instructivă și motivantă și m-a ajutat să înțeleg întregul proces de dezvoltare embedded cap-coadă.