Barometro Elettronico con ATmega 328

 

In questo articolo viene descritto come realizzare un barometro elettronico che svolge anche le funzioni di termometro, orologio e calendario, utilizzando il microcontrollore ATmega 328 e il sensore BM180 della Bosch. Il materiale necessario per realizzare il dispositivo è riportato nella seguente tabella

 

ComponentiQuantità
Microcontrollore ATmega328PU1
Sensore barometrico Bosch BM1801
Display LCD 20×4 retroilluminato1
Integrato HCF40601
Integrato HCF40401
Quarzo da 16 Mhz1
Quarzo da 32768 Hz1
Diodi led 3
Condensatori ceramici da 22 pF3
Condensatori ceramici da 10 pF1
Resistenze da 10 KΩ 1/4 W3
Resistenze da 15 KΩ 1/4 W1
Resistenze da 220 Ω 1/4 W3
Resistenze da 5Ω 1/4 W1
Resistenza da 10 MΩ (oppure 3 resistenze da 3,9MΩ + 1 resistenza da 100 KΩ1
Resistenze da 470KΩ 1/4 W1
Resistenze da 100Ω 1/4 W1
Cicalino Piezo1
Pulsanti N.A. per circuito stampato1

 

 

Guardando lo schema elettrico riportato in basso, vediamo lo stadio oscillatore composto dai due integrati HCF4060 e HCF4040 che inviano un segnale ad onda quadra alla frequenza di 1 Hz sul pin 14 del microcontrollore. Quindi ogni secondo leggeremo sul display il valore della pressione atmosferica (espressa in mbar) e della temperatura (espressa in gradi centigradi) provenienti dal sensore BM180  collegato ai pin 27 e 28. Inoltre, ogni 2,5 ore (o per un lasso di tempo che si può variare nel codice) viene fatta la misurazione tra il valore della pressione atmosferica attuale e quella precedente per monitorare se c’è stata una qualche variazione.

Se in questo lasso di tempo la pressione è rimasta stabile entrambi i led si accenderanno e sul display a destra verrà visualizzata una barra verticale. Se invece c’è stato un calo si accenderà il led rosso e sul display verrà visualizzata una freccia che punta verso il basso. Infine, si accenderà il led blu e comparirà una freccia che punta verso l’alto se c’è stato un aumento.  Una cosa importante da considerare quando si utilizza questo sensore è che nel codice, nelle impostazioni di inizializzazione, va specificata l’altitudine del luogo in cui ci si trova per la corretta misura della pressione. Questo parametro può essere ricavato da qualsiasi dispositivo GPS oppure semplicemente da Google Maps, nel mio caso il valore che ho dovuto impostare è 6 metri sul livello del mare. Per quanto riguarda il funzionamento del calendario, dell’orologio e della sveglia è tutto gestito dal codice e le relative impostazioni si effettuano con soli due tasti. Nello schema non ho incluso l’alimentatore stabilizzato a 5V e rimando in un’altra sezione del sito per questo tipo di circuito.

 

Foto del sensore Bosch BM180Sensore bmp 180

Schema barometro arduino atmega328

 

Di seguito lo sketch completo. Da notare l’uso delle librerie < SFE_BM180>  e  <Wire> scaricabili a fondo pagina

 

#include <SFE_BMP180.h>
#include <Wire.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 13);
SFE_BMP180 pressure;

int ledGiu = A1;
int ledSu = A2;

int conta;
int  bottone = 7;
int set = 1;
int seg = 8;

byte ore, minuti, secondi, o1, o2, m1, m2, s1, s2, num, funzione;
float altitudine, temperatura, pressione, pressioneSLDM, PressPrev;
int anno = 2016;
byte giorno = 1;
byte mese = 1;
byte gg1, gg2, ms1, ms2;
int hp = 10;
byte hha, mma, hha1, hha2, mma1, mma2;
byte alarm;
int differenzaPressione;


void diminuzione() {

  byte freccia[8] = {
    0b01110,
    0b01110,
    0b01110,
    0b01110,
    0b01110,
    0b11111,
    0b01110,
    0b00100
  };

  lcd.createChar(0, freccia);

  lcd.setCursor(19, 2);
  lcd.write(byte(0));
  lcd.setCursor(19, 3);
  lcd.write(byte(0));
}

void aumento() {
  byte freccia[8] = {
    0b00100,
    0b01110,
    0b11111,
    0b01110,
    0b01110,
    0b01110,
    0b01110,
    0b01110
  };
  lcd.createChar(0, freccia);
  lcd.setCursor(19, 2);
  lcd.write(byte(0));
  lcd.setCursor(19, 3);
  lcd.write(byte(0));
}


void stabile() {

  byte customChar[8] = {
    0b11111,
    0b11111,
    0b00000,
    0b11111,
    0b11111,
    0b00000,
    0b11111,
    0b11111
  };
  lcd.createChar(0, customChar);
  lcd.setCursor(19, 2);
  lcd.write(byte(0));
  lcd.setCursor(19, 3);
  lcd.write(byte(0));

}

void leggi_BMP180(float* altit, float* temp, float* press, float* press0) {
  char status;
  double A, T, P, p0;
  A = 6.0;// Altitudine della stazione di misura in metri. Può essere ricavata da un GPS
  status = pressure.startTemperature();
  delay(status);
  status = pressure.getTemperature(T);
  status = pressure.startPressure(3);
  delay(status);
  status = pressure.getPressure(P, T);
  p0 = pressure.sealevel(P, A);
  *altit = A;
  *temp = T;
  *press = P;
  *press0 = p0;
}



void setup() {

  pinMode(set, INPUT);
  pinMode(seg, INPUT);
  pinMode(bottone, INPUT);
  pinMode(ledGiu, OUTPUT);
  pinMode(ledSu, OUTPUT);
  pinMode(hp, OUTPUT);

  lcd.begin(20, 4);
  conta = 0;

  secondi = 0;
  minuti = 25;
  ore = 8;
  funzione = 0;
  num = 0;

  hha = 7;
  mma = 0;
  alarm = 0;


  if (pressure.begin()) {

    lcd.setCursor(0, 0);
    lcd.print("Barometro/Termometro");
    lcd.setCursor(0, 1);
    lcd.print("Elettronico");
    lcd.setCursor(0, 2);
    lcd.print("By Mario de Nichilo");

    leggi_BMP180(&altitudine, &temperatura, &pressione, &pressioneSLDM);
    PressPrev = pressione; // memorizzo la prima lettura del sensore

    delay(3000);
    lcd.clear();

  }
}



void orologio() {

  if (secondi > 59) {
    secondi = 0;
    minuti = minuti + 1;
  }
  if (minuti > 59) {
    minuti = 0 ;
    ore = ore + 1;
    tone(10, 1887, 22);
  }
  if (ore > 23) {
    ore = 0;

    // regolazione calendario


    bool bisestile = (anno > 1584 && ((anno % 400 == 0) || (anno % 4 == 0 && anno % 100 != 0)));
    giorno++;

    if ((mese == 1) && (giorno > 31)) {
      giorno = 1;
      mese = 2;
    }
    if ((mese == 2) && (bisestile == true) && (giorno > 29)) {
      giorno = 1;
      mese = 3;
    }
    if ((mese == 2) && (bisestile == false) && (giorno > 28)) {
      giorno = 1;
      mese = 3;
    }
    if ((mese == 3) && (giorno > 31)) {
      giorno = 1;
      mese = 4;
    }
    if ((mese == 4) && (giorno > 30)) {
      giorno = 1;
      mese = 5;
    }
    if ((mese == 5) && (giorno > 31)) {
      giorno = 1;
      mese = 6;
    }
    if ((mese == 6) && (giorno > 30)) {
      giorno = 1;
      mese = 7;
    }
    if ((mese == 7) && (giorno > 31)) {
      giorno = 1;
      mese = 8;
    }
    if ((mese == 8) && (giorno > 31)) {
      giorno = 1;
      mese = 9;
    }
    if ((mese == 9) && (giorno > 30)) {
      giorno = 1;
      mese = 10;
    }
    if ((mese == 10) && (giorno > 31)) {
      giorno = 1;
      mese = 11;
    }
    if ((mese == 11) && (giorno > 30)) {
      giorno = 1;
      mese = 12;
    }
    if ((mese == 12) && (giorno > 31)) {
      giorno = 1;
      mese = 1;
      anno++;
    }


  }

  s2 = secondi / 10;
  s1 = secondi - (s2 * 10);

  lcd.setCursor(19, 0);
  lcd.print(s1);
  lcd.setCursor(18, 0);
  lcd.print(s2);

  lcd.setCursor(17, 0);
  lcd.print(":");


  m2 = minuti / 10;
  m1 = minuti - (m2 * 10);


  lcd.setCursor(16, 0);
  lcd.print(m1);
  lcd.setCursor(15, 0);
  lcd.print(m2);

  lcd.setCursor(14, 0);
  lcd.print(":");


  o2 = ore / 10;
  o1 = ore - (o2 * 10);
  lcd.setCursor(13, 0);
  lcd.print(o1);
  lcd.setCursor(12, 0);
  lcd.print(o2);


}


void misurazione() {

  leggi_BMP180(&altitudine, &temperatura, &pressione, &pressioneSLDM);
  lcd.setCursor(0, 2);
  lcd.print(temperatura);
  lcd.setCursor(8, 2);
  lcd.print(char(223));
  lcd.setCursor(9, 2);
  lcd.print("C");
  lcd.setCursor(0, 3);
  lcd.print(pressione);
  lcd.setCursor(8, 3);
  lcd.print("mBar");

}

void calendario() {

  gg2 = giorno / 10;
  gg1 = giorno - (gg2 * 10);

  lcd.setCursor(0, 0);
  lcd.print(gg2);
  lcd.setCursor(1, 0);
  lcd.print(gg1);

  lcd.setCursor(2, 0);
  lcd.print(".");

  ms2 = mese / 10;
  ms1 = mese - (ms2 * 10);

  lcd.setCursor(3, 0);
  lcd.print(ms2);
  lcd.setCursor(4, 0);
  lcd.print(ms1);

  lcd.setCursor(5, 0);
  lcd.print(".");

  lcd.setCursor(6, 0);
  lcd.print(anno);


}


void loop() {

  if ((digitalRead(seg) == HIGH) && (funzione == 0)) {

    misurazione();
    secondi = secondi + 1;
    orologio();
    calendario();
    conta = conta + 1;

    tone(10, 1500, 3); //1700

    while ((hha == ore) && (mma == minuti) && (alarm == 1) && (digitalRead(seg) == HIGH)) {
      tone(10, 1887, 100);

    }


    while (digitalRead(seg) == HIGH) { // sincronia col clock esterno
      secondi = secondi;
    }
  }



  // regolazione orologio

  if (digitalRead(set) == HIGH) {
    lcd.clear();
    funzione++;
    delay(250);
    if (funzione == 9) {
      funzione = 0;
    }
    delay(200);
  }

  // Regoloazione  ore
  if (funzione == 1) {
    lcd.setCursor(0, 1);
    lcd.print("impostazione ore ");

    while ((digitalRead(bottone) == HIGH) && (funzione == 1)) {
      ore++;
      if (ore > 23) {
        ore = 0;
      }
      o2 = ore / 10;
      o1 = ore - (o2 * 10);
      lcd.setCursor(13, 2);
      lcd.print(o1);
      lcd.setCursor(12, 2);
      lcd.print(o2);
      delay(250);
    }
  }


  // Regolazione minuti

  if (funzione == 2) {
    lcd.setCursor(0, 1);
    lcd.print("impostazione min ");

    while ((digitalRead(bottone) == HIGH) && (funzione == 2)) {
      minuti++;
      if (minuti > 59) {
        minuti = 0;
      }

      m2 = minuti / 10;
      m1 = minuti - (m2 * 10);

      lcd.setCursor(13, 2);
      lcd.print(m1);
      lcd.setCursor(12, 2);
      lcd.print(m2);
      delay(200);
    }
  }


  // Regolazione calendario


  // Regolazione anno

  if (funzione == 3) {
    lcd.setCursor(0, 1);
    lcd.print("impostazione anno  ");

    lcd.setCursor(13, 2);
    lcd.print(anno);

    while ((digitalRead(bottone) == HIGH) && (funzione == 3)) {
      anno++;
      if (anno > 2050) {
        anno = 2016;
      }


      lcd.setCursor(13, 2);
      lcd.print(anno);

      delay(200);
    }
  }

  // Regolazione mese

  if (funzione == 4) {
    lcd.setCursor(0, 1);
    lcd.print("impostazione mese  ");

    ms2 = mese / 10;
    ms1 = mese - (ms2 * 10);
    lcd.setCursor(12, 2);
    lcd.print(ms2);
    lcd.setCursor(13, 2);
    lcd.print(ms1);

    while ((digitalRead(bottone) == HIGH) && (funzione == 4)) {
      mese++;
      if (mese > 12) {
        mese = 1;
      }

      ms2 = mese / 10;
      ms1 = mese - (ms2 * 10);
      lcd.setCursor(12, 2);
      lcd.print(ms2);
      lcd.setCursor(13, 2);
      lcd.print(ms1);

      delay(200);
    }
  }


  // Regolazione giorno

  if (funzione == 5) {
    lcd.setCursor(0, 1);
    lcd.print("impostazione giorno  ");

    gg2 = giorno / 10;
    gg1 = giorno - (gg2 * 10);
    lcd.setCursor(13, 2);
    lcd.print(gg2);
    lcd.setCursor(14, 2);
    lcd.print(gg1);

    while ((digitalRead(bottone) == HIGH) && (funzione == 5)) {
      giorno++;

      bool bisestile = (anno > 1584 && ((anno % 400 == 0) || (anno % 4 == 0 && anno % 100 != 0)));
      if ((mese == 1) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 2) && (bisestile == true) && (giorno > 29)) {
        giorno = 1;
      }
      if ((mese == 2) && (bisestile == false) && (giorno > 28)) {
        giorno = 1;
      }
      if ((mese == 3) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 4) && (giorno > 30)) {
        giorno = 1;
      }
      if ((mese == 5) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 6) && (giorno > 30)) {
        giorno = 1;
      }
      if ((mese == 7) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 8) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 9) && (giorno > 30)) {
        giorno = 1;
      }
      if ((mese == 10) && (giorno > 31)) {
        giorno = 1;
      }
      if ((mese == 11) && (giorno > 30)) {
        giorno = 1;
      }
      if ((mese == 12) && (giorno > 31)) {
        giorno = 1;
      }

      gg2 = giorno / 10;
      gg1 = giorno - (gg2 * 10);
      lcd.setCursor(13, 2);
      lcd.print(gg2);
      lcd.setCursor(14, 2);
      lcd.print(gg1);
      delay(200);
    }
  }


  // Regolazione sveglia

  if (funzione == 6) {
    lcd.setCursor(0, 1);
    lcd.print("ora sveglia    ");


    hha2 = hha / 10;
    hha1 = hha - (hha2 * 10);
    lcd.setCursor(12, 2);
    lcd.print(hha2);
    lcd.setCursor(13, 2);
    lcd.print(hha1);

    while ((digitalRead(bottone) == HIGH) && (funzione == 6)) {
      hha++;
      if (hha > 23) {
        hha = 0;
      }
      hha2 = hha / 10;
      hha1 = hha - (hha2 * 10);
      lcd.setCursor(12, 2);
      lcd.print(hha2);
      lcd.setCursor(13, 2);
      lcd.print(hha1);

      delay(200);
    }
  }


  if (funzione == 7) {
    lcd.setCursor(0, 1);
    lcd.print("min sveglia    ");

    mma2 = mma / 10;
    mma1 = mma - (mma2 * 10);
    lcd.setCursor(12, 2);
    lcd.print(mma2);
    lcd.setCursor(13, 2);
    lcd.print(mma1);

    while ((digitalRead(bottone) == HIGH) && (funzione == 7)) {
      mma++;
      if (mma > 59) {
        mma = 0;
      }
      mma2 = mma / 10;
      mma1 = mma - (mma2 * 10);
      lcd.setCursor(12, 2);
      lcd.print(mma2);
      lcd.setCursor(13, 2);
      lcd.print(mma1);
      delay(200);
    }
  }


  // attivazione della sveglia

  if (funzione == 8) {
    lcd.setCursor(0, 1);
    lcd.print("attiva sveglia    ");


    if ((digitalRead(bottone) == HIGH) && (funzione == 8)) {
      alarm = !alarm;

      delay(300);
    }

    if (alarm == 1) {

      lcd.setCursor(12, 2);
      lcd.print("ON ");
    } else {
      lcd.setCursor(12, 2);
      lcd.print("OFF");
    }

  }



  if (conta >= 9000) { // confronto valore ogni 2,5 ore ( 9000 sec )

    differenzaPressione = int(pressione) - int(PressPrev);

    if (differenzaPressione == 0)  {

      lcd.setCursor(13, 3);
      lcd.print(pressione - PressPrev);
      stabile();
      digitalWrite(ledSu, HIGH);
      digitalWrite(ledGiu, HIGH);

      PressPrev = pressione;
      conta = 0;
    }


    if ((pressione > PressPrev))  {

      differenzaPressione = int(pressione) - int(PressPrev);
      lcd.setCursor(13, 3);
      lcd.print(differenzaPressione);
      aumento();
      digitalWrite(ledSu, HIGH);
      digitalWrite(ledGiu, LOW);

      PressPrev = pressione;
      conta = 0;
    }

    if ((pressione < PressPrev) )  {

      differenzaPressione = int(pressione) - int(PressPrev);
      lcd.setCursor(13, 3);
      lcd.print(differenzaPressione);
      digitalWrite(ledGiu, HIGH);
      digitalWrite(ledSu, LOW);
      diminuzione();
      PressPrev = pressione;
      conta = 0;
    }

  }

}

 

 

Foto del barometro in funzioneArduino barometro

 

 

Video dimostrativo

 

Qui sotto è possibile scaricare i file del progetto

 

Schema+Sketch

Libreria Sensore : BMP180_Breakout_Arduino_Library-master

Libreria Wire. h : wire