Dispozitiv de monitorizare a sanatatii si alcoolemiei

Autor: Atomei Alexandru-Constantin

Grupa: 334CD

Introducere

Proiectul consta intr-un dispozitiv portabil care integreaza un senzor de pulsoximetrie și un senzor de alcool. Cu ajutorul pulsoximetrului se masoara în timp real ritmul cardiac (BPM) și nivelul de saturație a oxigenului din sange (SpO₂), iar cu ajutorul senzorului de alcool se determina concentrația de alcool din aerul expirat. Datele sunt afișate pe un ecran LCD TFT, iar utilizatorul poate schimba modul de functionare al dispozitivului printr-un buton dedicat. În cazul depășirii unui prag de alcoolemie prestabilit, un buzzer emite un semnal de avertizare.

Scopul proiectului este de a oferi o soluție practică de auto-monitorizare a starii de sanatate și a nivelului de alcool, ajutand astfel la prevenirea incidentelor cauzate de lipsa de informare. Dispozitivul poate fi util atat pentru persoanele preocupate de sanatatea lor, cat si pentru șoferi care vor să evite sancțiunile legale.

Inspirat de dorinta de a avea control total asupra propriei stari, mi-am imaginat un dispozitiv care să imbine două functii: monitorizarea continua a semnelor vitale şi testarea alcoolemiei, pentru evitarea deciziilor riscante. Am realizat ca, de multe ori, nu avem la indemana un instrument rapid care sa ne spuna ca avem o problema – fie că e vorba de un atac de panica/efort mult prea ridicat, fie ca ne intoarcem acasa dupa o seara în oras in care am baut.

Astfel, am decis sa proiectez un sistem compact, user-friendly, care sa puna la dispozitie date importante despre corpul nostru, combinand utilitatea medicala cu responsabilitatea sociala.

Descriere generală

Proiectul are la baza un microcontroller ESP32, care face legatura intre tot hardware-ul si gestioneaza atat achizitia de date, cat si interactiunea cu utilizatorul.

Conectate la el sunt urmatoarele componente:

  • Senzor de pulsoximetrie - Măsoară ritmul cardiac și saturația de oxigen în sânge. Comunica cu ESP32 prin magistrala I2C.
  • Senzor de gaz - Detectează vapori de alcool în aer. Semnalul analogic de la MQ-3 intră pe ADC-ul ESP32-ului, care traduce tensiunea masurata in concentratie estimata de alcool.
  • Display LCD TFT - Ecran color conectat prin interfaţa SPI la ESP32, pe care sunt afișate în timp real valorile de puls, SpO2 si concentratia de alcool.
  • Buzzer - Legat la un pin PWM al ESP32, emite tonuri de alarma atunci cand o valoare masurata trece de un prag prestabilit (de exemplu, nivelul de alcool sau saturatia de oxigen scazuta).
  • Buton - Folosit pentru comutarea modului de functionare intre masurarea pulsoximetriei si alcoolemiei.

Hardware Design

Schema electrica

Bill of Materials

Nume componenta Model Protocol Link achizitie Datasheet
Microcontroller ESP32-WROOM-32 - Optimus Digital Datasheet ESP32
Senzor pulsoximetrie MAX30102 I2C eMAG Datasheet MAX30102
Senzor gaz MQ-3 ADC Optimus Digital Datasheet MQ-3
Display LCD TFT 128x128px 1.44 inch ST7735S SPI eMAG -
Buzzer Buzzer pasiv 5V PWM - -
Buton Push Button - - -
Rezistori - - - -

Conexiuni componente

Din punct de vedere al legaturilor, componentele sunt conectate astfel:

  • ESP32-ul reprezinta punctul de conexiune central pentru toate modulele.
  • Display-ul LCD este conectat prin SPI la microcontroller, utilizand pinii D18(SCK), D23(MOSI), D4(DC), D2(RESET) si D5(CS).Alimentarea este facuta prin pinul de 3V3, iar backlighting-ul este conectat la o rezistenta de 100Ω, pentru a aduce curentul care trece la 33mA si luminozitatea sa fie destul de buna.
  • Senzorul de pulsoximetrie(MAX30102) este conectat prin I2C la ESP32, pinii folositi fiind D22(SCL), D21(SDA), iar alimentarea fiind facuta tot de la pinul de 3V3.
  • Senzorul de alcool(MQ-3) este conectat analogic la ESP32, utilizand pinul D34.Pentru acesta, alimentarea este facuta de la pinul de VIN al microcontroller-ului, intrucat are nevoie de 5V pentru a functiona corect.Din aceasta cauza si pentru ca pinii ESP32-ului lucreaza la 3V3, iesirea analogica a senzorului trece printr-un divizor de tensiune format din 2 rezistoare de 1KΩ.
  • Butonul este conectat la pinul D19 al microcontroller-ului.
  • Buzzer-ul este conectat la pinul D15 al ESP32-ului si este controlat prin PWM.

Poze

Software Design

Descrierea codului aplicaţiei (firmware):

  • Mediu de dezvoltare: VSCode cu PlatformIO
  • Librării şi surse 3rd-party: Adafruit ST7735/ST7789 pentru , MAX3010x Sensor
  • Aplicatia a fost dezvoltata avand la baza framework-ul de Arduino, dar am incercat pe cat am putut sa ma folosesc si de ESP-IDF, dar am intampinat destul de multe probleme legate de compabilitati..
Intrerupere + timer
void IRAM_ATTR isr_button(void* arg) {
  button_time = esp_timer_get_time() / 1000;
  if (button_time - last_button_time > 250) {
    buttonPressed = true;
    last_button_time = button_time;
  }
}

Intreruperea e folosita pentru a detecta corect apasarea butonului, care determina schimbarea starii device-ului intre pulsoximetru si alcooltest, iar interogarea timer-ului intern al ESP32-ului pentru a scapa de debouncing.

GPIO + PWM
// Setup buzzer PWM
ledc_timer_config_t ledc_timer = {
    .speed_mode = LEDC_LOW_SPEED_MODE,
    .duty_resolution = LEDC_TIMER_8_BIT,
    .timer_num = LEDC_TIMER_0,
    .freq_hz = 2000,
    .clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
 
ledc_channel_config_t ledc_channel = {
    .gpio_num = buzzerPin,
    .speed_mode = LEDC_LOW_SPEED_MODE,
    .channel = buzzerChannel,
    .timer_sel = LEDC_TIMER_0,
    .duty = 0,
    .hpoint = 0
};
ledc_channel_config(&ledc_channel);
 
// Set GPIO19 as input
GPIO.enable_w1tc = (1 << 19); // Clear output enable (input mode)
 
// Enable pull-up
GPIO.pin[19].pad_driver = 0; // Normal output (not open-drain)
REG_SET_BIT(GPIO_PIN_MUX_REG[19], FUN_PU); // Enable pull-up (register macro)
 
// Set interrupt type: negative edge
GPIO.pin[19].int_type = 1;
 
// Enable GPIO interrupt for GPIO19
GPIO.pin[19].int_ena = 1;     // Enable interrupt for CPU 0
 
// Register the ISR
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, 0, isr_button, NULL, NULL);
 
// Enable global GPIO interrupts
ets_intr_unlock();

Initializarea butonului si al PWM-ului pentru buzzer sunt realizate utilizand ESP-IDF + lucru direct pe registrii ESP-ului(lucru care mi-a dat batai de cap foarte mari, pentru restul implementarilor am decis sa raman la ESP-IDF si framework-ul de Arduino). Pinul la care e legat butonul este initializat ca input, intreruperea e setata pe falling edge si e activata rezistenta de pull-up interna corespunzatoare. Pentru PWM, este folosit timer-ul LEDC pe 8 biti.

void buzzer_task(void *param) {
    int freq;
 
    while (1) {
        if (xQueueReceive(buzzerQueue, &freq, portMAX_DELAY)) {
            ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, freq);
            ledc_set_duty(LEDC_LOW_SPEED_MODE, buzzerChannel, 128);
            ledc_update_duty(LEDC_LOW_SPEED_MODE, buzzerChannel);
 
            vTaskDelay(pdMS_TO_TICKS(100));
 
            ledc_set_duty(LEDC_LOW_SPEED_MODE, buzzerChannel, 0);
            ledc_update_duty(LEDC_LOW_SPEED_MODE, buzzerChannel);
        }
    }
}
if (buttonPressed) {
    int note = NOTE_D4;
    xQueueSend(buzzerQueue, &note, 0);
 
    change_state();
}

La fiecare apasare a butonului este actionat si buzzer-ul prin modificarea duty cycle-ului pe o perioada scurta. Am decis sa creez un task separat pentru buzzer, deoarece aparea un delay sesizabil la schimbarea afisajului din cauza delay-ului.

SPI

SPI-ul e initializat prin libraria Adafruit_ST7735 a display-ului. La schimbarea valorilor de pe ecran, acesta nu se redeseneaza in totalitate, ci doar partea care necesita modificari.

I2C

I2C-ul e initializat prin libraria Wire.h din Arduino. Transmiterea si primirea de informatii este realizata prin libraria MAX3010x a senzorului de pulsoximetrie. Codul pentru prelucrarea datelor este preluat dintr-un exemplu pus la dispozitie in aceasta librarie.Referinta este la finalul paginii.

ADC
double measure_alcohol() {
    const int measurementDuration = 500;
    const int sampleInterval = 50;
    const int numSamples = measurementDuration / sampleInterval;
    int samples[numSamples];
 
    unsigned long startTime = millis();
    int sampleCount = 0;
 
    while (millis() - startTime < measurementDuration && sampleCount < numSamples) {
        samples[sampleCount++] = analogRead(MQ3_PIN);
        delay(sampleInterval);
    }
 
    float mean = 0.0;
    for (int i = 0; i < sampleCount; ++i) {
        mean += samples[i];
    }
    mean /= sampleCount;
 
    double Vout = static_cast<double>(mean) * (5 / 4096.0);
    double Rs = RL * (5 - Vout) / Vout;
 
    double ratio = Rs / R0;
 
    // Apply the log-log relationship to get ppm
    double ppm = pow(10, -1.76 * log10(ratio) + 2.3);
 
    // Convert to mg/L (ethanol molecular weight = 46.07 g/mol)
    double mgL = (ppm * 46.07 / 24.45) / 1000.0;
 
    return mgL;
}

Pentru citirea senzorului de alcool prin ADC m-am folosit de functia de analogRead() din Arduino(din nou, am incercat sa folosesc varianta din ESP-IDF, dar obtineam rezultate diferite si nu mai erau calibrate..). Calculele pentru transformari au fost gasite prin diferite articole pe care le voi referentia la finalul paginii.

Rezultate Obţinute

Aici gasiti demo-ul proiectului: https://www.youtube.com/watch?v=yMKbu_0QTNY

Download

Jurnal

  • 16.04.2025 - Alegere tema proiect si confirmare.
  • 28.04.2025 - Toate componentele au fost cumparate si primite.
  • 29.04.2025 - Creare pagina de documentatie.
  • 30.04.2025 - Completarea primului draft pentru pagina de documentatie.
  • 13.05.2025 - Finalizare milestone de hardware.
  • 17.05.2025 - Finalizare prima versiune de software functional.
  • 21.05.2025 - Finalizare milestone de software.
  • 25.05.2025 - Finalizare documentatie.

Bibliografie/Resurse

pm/prj2025/vstoica/alexandru.atomei03.txt · Last modified: 2025/05/27 23:12 by alexandru.atomei03
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0