AUTOR: Buduran Cătălina-Andreea, 333CA
Prezentarea pe scurt a proiectului:
Proiectul este un detector de gaz/fum și flacără care monitorizează calitatea aerului într-un spațiu închis și declanșează avertizări sonore și vizuale în cazul detectării unor niveluri periculoase de fum sau gaze inflamabile, transmițând starea atmosferei spre un database hostat pe PC.
Scopul proiectului este prevenirea accidentelor casnice prin detectarea timpurie a scurgerilor de gaz sau a începuturilor de incendii, oferind un sistem de alertă rapid și accesibil.
Ideea de la care am pornit este necesitatea de a avea un sistem de siguranță accesibil pentru locuințe, în special în apartamente sau case care nu sunt dotate cu senzori de fum/gaz integrați, reducând pericolele.
Este util pentru alții, deoarece crește siguranța în locuințe, oferind un mijloc ieftin de prevenire a tragediilor cauzate de scurgeri de gaz sau incendii. Pentru noi, proiectul este o oportunitate de a pune în practică cunoștințele hardware și software dobândite, aplicate într-un context real și relevant.
Componentele detectorului:
Modul în care interacționează componentele:
Descriere detaliată și justificată a pinilor:
Componentă | Funcție | Observații | Link achiziție | Datasheet |
---|---|---|---|---|
Senzor MQ-2 | Detectare gaz/fum | Ieșire analogică | Optimus MQ-2 | MQ-2 PDF |
Senzor flacără | Detectare flacără | Ieșire analogică/digitală | Optimus Flacără | Senzor flacără |
LCD 16×2 I2C | Afișare mesaje | Comunicare I2C | LCD I2C | LCD |
Buzzer pasiv | Alertă sonoră | Controlat prin PWM | Buzzer pasiv | Buzzer |
LED roșu | Aprins la detecție | Pin digital | LED roșu | LED Roșu |
LED verde | Aprins când aerul e curat | Pin digital | LED verde | LED Verde |
Cablu USB | Transmitere date către laptop (UART) | Comunicare serială | Cablu USB | Cablu USB |
Arduino UNO | Microcontroler – control principal | Comunică cu toate componentele (senzori, buzzer, LED-uri, LCD) prin pini digitali, analogici și I2C. Rulează codul principal. | Arduino UNO | Arduino UNO |
Breadboard | Platformă de conectare fără lipire | Permite conectarea rapidă a componentelor. Distribuie 5V și GND către toată rețeaua | Breadboard | Breadboard |
Fire tată-tată | Conectare între componente și Arduino | Asigură conexiuni electrice fără lipire. Leagă pinii Arduino de senzori, buzzer, LED-uri | Fire tată-tată | - |
Proiectul este funcțional și implementează următoarele:
Proiectul meu nu folosește biblioteci externe Arduino. Toate funcționalitățile (PWM, UART, ADC, GPIO) au fost implementate folosind registre directe ale microcontrolerului ATmega328P, deoarece reflectă înțelegerea profundă a hardware-ului, dar și corelare directă cu conceptele din laborator. Proiectul este scris exclusiv cu registre AVR, fără funcții Arduino. Toate componentele hardware sunt controlate la nivel de low-level, iar proiectul este calibrat și funcțional pe o placă compatibilă Arduino.
Calibrarea senzorilor
Optimizări realizate
Laborator | Temă | Funcționalitate folosită în proiect |
Laboratorul 0 | GPIO | Control LED roșu (D8) și LED verde (D11), citire senzor flacără (D9) prin `PINB` | |
Laboratorul 1 | UART | Trimitere valori citite de la senzorii de gaz și flacără către laptop prin UART | |
Laboratorul 3 | Timere și PWM | Generare sunet buzzer prin Timer0 în modul Fast PWM pe pinul PD6 (`TCCR0A`, `OCR0A`) | |
Laboratorul 4 | ADC | Citire analogică de la senzorul MQ-2 (gaz/fum) prin canalul | |
Laboratorul 6 | I2C | LCD I2C |
Explicarea codului:
Componentă | Funcție din cod | |
Buzzer (PWM) | `pwm_start()` și `pwm_stop()` | Pornește/oprește semnalul sonor generat pe pinul D6 prin Timer0 (Fast PWM) |
Senzor gaz (ADC) | `adc_init()` și `citeste_adc()` | Inițializează convertorul analog-digital și citește tensiunea de la MQ-2 |
Serial (UART) | `uart_init()`,`uart_transmit()`,`uart_print()`,`uart_print_number()` | Trimite mesaje către laptop prin USB pentru a vizualiza starea senzorilor |
LED-uri și senzori | în `main()` | LED verde/roșu indică stare normală/pericol. Senzor flacără (digital pe D9) |
Interacțiunea dintre funcționalități
Validarea funcționării
#include <avr/io.h> #include <util/delay.h> #include “twi.h”
#define LCD_ADDR 0x27 #define LCD_BACKLIGHT 0x08 #define LCD_ENABLE 0x04 #define LCD_RS 0x01
void delay_ms_custom(uint16_t ms) {
for (uint16_t i = 0; i < ms; i++) { TCNT2 = 0; TIFR2 |= (1 << OCF2A);
while (!(TIFR2 & (1 << OCF2A))) { //astept (1ms) } }
}
void lcd_send_nibble(uint8_t nibble, uint8_t rs) {
uint8_t data = (nibble & 0xF0) | LCD_BACKLIGHT; if (rs) data |= LCD_RS;
twi_start(); twi_write(LCD_ADDR << 1); twi_write(data | LCD_ENABLE); _delay_us(1); twi_write(data & ~LCD_ENABLE); twi_stop();
}
void lcd_send_byte(uint8_t data, uint8_t rs) {
lcd_send_nibble(data & 0xF0, rs); lcd_send_nibble((data << 4) & 0xF0, rs); delay_ms_custom(1);
}
void lcd_command(uint8_t cmd) {
lcd_send_byte(cmd, 0);
}
void lcd_write_char(char c) {
lcd_send_byte(c, 1);
}
void lcd_print(const char* str) {
while (*str) lcd_write_char(*str++);
}
void lcd_clear() {
lcd_command(0x01); delay_ms_custom(2);
}
void lcd_set_cursor(uint8_t col, uint8_t row) {
uint8_t row_offsets[] = {0x00, 0x40}; lcd_command(0x80 | (col + row_offsets[row]));
}
void lcd_print_number(uint16_t val) {
char buf[6]; uint8_t i = 0;
if (val == 0) { lcd_write_char('0'); return; }
while (val > 0 && i < 5) { buf[i++] = '0' + (val % 10); val /= 10; }
while (i > 0) { lcd_write_char(buf[--i]); }
}
void lcd_init() {
delay_ms_custom(50); lcd_send_nibble(0x30, 0); delay_ms_custom(5); lcd_send_nibble(0x30, 0); delay_ms_custom(150); lcd_send_nibble(0x30, 0); delay_ms_custom(150); lcd_send_nibble(0x20, 0); delay_ms_custom(150);
lcd_command(0x28); lcd_command(0x0C); lcd_command(0x06); lcd_command(0x01); delay_ms_custom(2);
}
void pwm_start(uint8_t level) {
DDRD |= (1 << PD6); TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); TCCR0B = (1 << CS01) | (1 << CS00); OCR0A = level;
}
void pwm_stop() {
TCCR0A = 0; TCCR0B = 0; OCR0A = 0; PORTD &= ~(1 << PD6);
}
void adc_init() {
ADMUX = (1 << REFS0) | (1 << MUX0); ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
}
uint16_t citeste_adc() {
ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)); return ADC;
}
void uart_init() {
UBRR0 = 103; UCSR0B = (1 << TXEN0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
void uart_transmit(char c) {
while (!(UCSR0A & (1 << UDRE0))); UDR0 = c;
}
void uart_print(const char* s) {
while (*s) uart_transmit(*s++);
}
void uart_print_number(uint16_t n) {
char buffer[6]; uint8_t i = 0; if (n == 0) { uart_transmit('0'); return; } while (n > 0 && i < 5) { buffer[i++] = '0' + (n % 10); n /= 10; } while (i > 0) { uart_transmit(buffer[--i]); }
}
void timer2_init_ctc(void) {
TCCR2A = (1 << WGM21); TCCR2B = (1 << CS22); OCR2A = 188;
}
int main(void) {
timer2_init_ctc(); twi_init(); lcd_init(); adc_init(); uart_init();
// LED roșu (D8), verde (D11), flacara (D9), buzzer (D6) DDRB |= (1 << PB0) | (1 << PB3); DDRB &= ~(1 << PB1); DDRD |= (1 << PD6);
//buton (D3) DDRD &= ~(1 << PD3); PORTD |= (1 << PD3);
lcd_set_cursor(0, 0); lcd_print("Incalzire senzor..."); delay_ms_custom(20000); lcd_clear();
uint8_t pwm_level = 0; uint8_t alarma_oprita = 0; uint8_t buton_apasat_ultima = 0;
while (1) { uint8_t flacara = !(PINB & (1 << PB1)); uint16_t gaz_fum_val = citeste_adc(); uint8_t fum_detectat = gaz_fum_val > 300; uint8_t gaz_detectat = gaz_fum_val > 400; uint8_t pericol = flacara || gaz_detectat || fum_detectat;
uint8_t buton = !(PIND & (1 << PD3)); if (pericol && buton && !buton_apasat_ultima) { alarma_oprita = 1; } buton_apasat_ultima = buton;
if (!pericol) { alarma_oprita = 0; }
if (pericol) { PORTB |= (1 << PB0); PORTB &= ~(1 << PB3); } else { PORTB |= (1 << PB3); PORTB &= ~(1 << PB0); }
if (pericol && !alarma_oprita) { if (pwm_level < 255) pwm_level += 5; pwm_start(pwm_level); } else { pwm_level = 0; pwm_stop(); }
uart_print("Gaz: "); uart_print_number(gaz_fum_val); uart_print(" | Flacara: "); uart_print_number(flacara); uart_print(" | Alarma oprita: "); uart_print_number(alarma_oprita); uart_print("\r\n");
lcd_clear(); lcd_set_cursor(0, 0); if (!pericol) { lcd_print("Stare normala"); } else { if (flacara) { lcd_print("Pericol: FLACARA"); } else if (gaz_detectat) { lcd_print("Pericol: GAZ"); } else if (fum_detectat) { lcd_print("Pericol: FUM"); } }
lcd_set_cursor(0, 1); lcd_print("Alarma:"); lcd_print_number(alarma_oprita);
delay_ms_custom(300); }
return 0;
}