Aiuto su funzione matematica con 2 variabili di pressione per centralina meteo

Ciao a Tutti.

Chiedo consiglio ed aiuto per capire dove sto sbagliando. Sono un novello, ho acquistato lo starter kit originale Arduino e ho imparato abbastanza bene questo mondo! ma ora con le cose più serie trovo difficoltà.

Sto costruendo una centralina meteo. Rilevo la pressione relativa ogni 5 secondi e la metto su un LCD e tramite seriale con il monitor seriale.

Per capire l'evoluzione della pressione e del tempo, ho bisogno di capire in 12 ore di quanti hPa la pressione relativa è aumentata o diminuita. Per il test a banco attualmente effettuo la lettura ogni 30 secondi.

Ho 3 variabili in float: (provato anche con double)

dp1 pressione prima del Delay... (Leggo la pressione P e la sposto in dp1) dp2 pressione dopo il delay... (ritardo la rilettura con delay 30 secondi e scrivo il valore in dp2) dp = dp2-dp1. (differenza delle pressioni)

Il primo problema è che se effettuo una semplice sottrazione tra il primo valore ed il secondo, ho sempre un risultato sia sulla seriale sia sul LCD di zero, cioè visualizzo -0.00 oppure 0.00. Ma se le sommo o eseguo qualsiasi altra operazione che non sia una sottrazione, il risultato è veritiero, in pratica se eseguo una sottrazione non calcola nulla, ma se sommo tutto funziona.

il secondo problema (da risolvere successivamente) è che vorrei effettuare una lettura della pressione ogni 5 secondi, ma se ritardo di 12 ore usando il comando delay, il valore di lettura della pressione per 12h non cambia. Non saprei proprio come strutturare il programma per non avere il Delay di 12h che mette in pausa tutto il blocco dati... Ho pensato di usare millis(), ma non credo sia un trucco valido...

In effetti il millis() non è molto preciso e si azzera ogni 50 giorni circa, ma comunque aspettiamo l'esperto di turno.

Bcs85:
… Ho 3 variabili in float: (provato anche con double) …

… ho letto nella tua presentazione che hai un Genuino 101, stiamo parlando di un lavoro sviluppato su di esso o su altra scheda ? Perché l’implemnetazione dei double è differente …

E comunque, come ti ha chiesto “docsavage”, è meglio se metti il codice che stai usando (… mi raccomando, in conformità al regolamento, punto 7, racchiuso tra i tag CODE che, in fase di edit, ti inserisce il bottone </> … primo a sinistra).

Guglielmo

Bcs85: Per il test a banco attualmente effettuo la lettura ogni 30 secondi.

In 30 secondi la pressione non cambia, a meno che non ti trovi dentro una tempesta, è ovvio che se fai la sottrazione tra due valori identici il risultato è 0. Che sensore stai usando per la pressione atmosferica ?

Confermo, confronta la pressione atmosferica ogni 24H. Ciao

Scusatemi!

Avete ragione, mi sono dimenticato di dire che:

Attualmente sto sperimentando con la genuino 101
Uso un sensore di temperatura/pressione in I2C bosch BMP 180 con la libreria apposita.

Il codice è in pratica l’esempio originale della guida della libreria BMP 180.
solo che ho inserito la parte dell’ LCD, e dovrei inserire anche altre funzioni…

La pressione atmosferica varia di circa 3-4 fino a 5-6 hPa/24h, ma questo sensore ogni 5 secondi scrive sulla variabile p0 un valore con i decimali che oscillano.
Possiedo altre 2 centraline, una Netatmo e una vecchia WS2350. il sensore Bosch BMP180 I2C collegato alla genuino è preciso e pari al 100% alle altre due.

Comunque il problema non è l’attesa di un significativo cambio di pressione: ogni 5 secondi per esempio sul monitor e su LCD vedo: 1019.54, 1019,46, 1019,56, 1019,64… Penso sia normale che oscilli. Quello che conta in meteorologia sono i numeri prima della virgola, e la loro tendenza…

Per provare il mio sketch subito senza attendere un giorno (dato che sono giorni che ci provo ma non va) riduco il tempo a 30 secondi. Ogni 30 secondi Dovrei sempre vedere un valore decimale diverso, di poco ma diverso…

Se sommo dp1 e dp2 visualizzo correttamente le due variabili sommate, se sottraggo vedo sempre zero positivo o negativo, anche se i due operandi non sono uguali…
Esempio, se prima leggo 1013.20, poi dopo 30 secondi leggo 1013.25 dovrei trovarmi -0,05 hPa
Se metto una costante in sottrazione con dp1 o dp2, vedo la costante con segno negativo… (come se dp1 e dp2 fossero uguali a zero.

Il problema è come se non si potesse scendere sotto lo zero con i numeri negativi, ma le variabili float in teoria dovrebbero essere anche con segno. Inoltre se provo a sottrarre con due costanti fisse mettendo dp = 1000,05 - 1000,10 sull’LCD e sul monitor visualizzo correttamente -0,05…

Ecco il codice, è un po un taglia e cuci ed è fatto da un novello:

#include <SFE_BMP180.h>                    //libreria per lettura sensore
#include <Wire.h>                          //libreria originale arduino per bus I2C
#include <LiquidCrystal_I2C.h>                //libreria per display LCD I2C

LiquidCrystal_I2C lcd(0x27, 20, 4);

SFE_BMP180 pressure;                                //creo un oggetto chiamato pressione su libreria del pressostato 

#define ALTITUDE 44                              // definisco Altitude attuale dove mi trovo in metri, utile per calcolare la pressione relativa

void setup() {                                            

  
  while (!Serial);
  Serial.begin(9600);                                     //inizializzo la seriale per monitor PC
  Serial.println("IN AVVIO");                             //scrivo sul monitor PC l'avvio della lettura
  

  lcd.begin();
  lcd.clear();                                            //pulisco il display per riavvarlo
  lcd.print("Centralina Meteo");                          //scrivo sul display una scritta di avvio
  lcd.setCursor(0, 1);                                    //sposto il cursore sulla seconda colonna (seconda riga)
  lcd.print("by Luca 2016");                             //scritta di avvio sulla secona riga
  delay(2000);                                            //attendo 5 secondi questa pagina di avvio

  if (pressure.begin()) {                                //inizializzo sensore (questo è importante per ottenere valori di calibrazione memorizzati sul sensore)
  Serial.println ("Avvio effettuato correttamente");    //se l'inizializzazione ha successo, scrivo nel monitor l'avvenuta inizializzazione
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("Avvio sensore OK");
  delay(2000);
  lcd.clear();
  }
  else
  {
    Serial.println("Errore inizializzazione sensore");     //altrimenti scrivo errore inizializzazioni
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Errore inizializzazione");
    lcd.setCursor(0,1);
    lcd.print("sensore");
    while (1);                                            //se l'inizializzazione del programma è fallita con while(1) vado in pausa perenne.
  }
}

void loop()                                               // Loop del programma per ottenerei  i valori di pressione ogni 5 secondi .
{

  char status;
  double T, P, p0, a;
  float dp, dp1,dp2;

  Serial.println();
  Serial.print("Altitudine iniziale: ");
  Serial.print(ALTITUDE, 36);
  Serial.println(" metri ");

  // Se si vuole misurare l'altitudine e non la pressione è necessario fornire una pressione di riferimento nota .
  // Questo è mostrato alla fine dello sketch.
  // È necessario innanzitutto ottenere una misura di temperatura per eseguire una lettura della pressione .

  // Avvia una misurazione della temperatura :
  // Se la richiesta ha successo , viene restituito il numero di ms di attesa .
  // Se la richiesta non è riuscita, viene restituito 0


  status = pressure.startTemperature();
  if (status != 0)
  {
    // Attendere che la misura per completare:
    delay(status);


    // Recupera la misurazione della temperatura completato:
    // Si noti che la misura è memorizzato nella variabile di T.
    // Funzione restituisce 1 in caso di successo , 0 se il fallimento .

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      Serial.print("temperatura: ");
      Serial.print(T, 2);
      Serial.println("'C " );

     
      lcd.setCursor(5, 0);
      lcd.print("C");
      lcd.setCursor(3, 1);
      lcd.print(T);
      


      // Start lettura pressione atmosferica

      status = pressure.startPressure(3);
      if (status !=0)
      {
        // Attendi per la misura
        delay(status);

        // Calcolo pressione assoluta

        status = pressure.getPressure(P, T);
        if (status != 0)
        {
          // Print out the measurement:
          Serial.print("pressione assoluta: ");
          Serial.print(P, 2);
          Serial.println(" hP ");
          

          // calcolo pressione relativa alla quota  in metri impostata su variabile ALTITUDE

          p0 = pressure.sealevel(P, ALTITUDE); 
          Serial.print("pressione relativa: ");
          Serial.print(p0, 2);
          Serial.println(" hP ");

          l
         

          // Calcolo variazione altitudine

          a = pressure.altitude(P, p0);
          Serial.print("altitudine calcolata: ");
          Serial.print(a, 0);
          Serial.println(" metri ");
          }
        
        else Serial.println("errore retrieving pressure measurement\n");
      }
      
       else Serial.println("errore starting pressure measurement\n");
    }
    else Serial.println("errore retrieving temperature measurement\n");
  
  } else Serial.println("errore starting temperatura measurement\n");


//Calcolo variazione pressione su 12h.

      
          lcd.setCursor(11, 0);
          lcd.print("mBar");
          lcd.setCursor(10, 1);
          lcd.print(p0);
          
          dp1 = p0;
          delay(30000);
          dp2 = p0;
         
          dp = dp2-dp1;

      
      lcd.setCursor(0, 3);
      lcd.print("Diff. ");
      lcd.setCursor(14,3);
      lcd.print("mbar/h");

       lcd.setCursor(6,3);
       lcd.print(dp);


  }/code]

Scusa, ma la seconda lettura dov'è? Tu assegni a dp1 e a dp2 il valore di p0, senza che questo cambi in alcun modo tra le due assegnazioni, per cui la differenza è per forza zero!

docsavage: oltre alla mancata assegnazione lui si trova comunque al limite della precisione dei float tra 1000,20 e 1000,25 la differenza è alla sesta cifra significativa

... nel suo caso può aumentare la precisione usando i "double", difatti sta usando una Genunino 101 che NON è basata su MCU AVR, ma su una MCU Intel® Curie™ a 32 bit in cui i "double" sono implementati effettivamente come floating point a 64 bit ;)

Guglielmo

SukkoPera: Scusa, ma la seconda lettura dov'è? Tu assegni a dp1 e a dp2 il valore di p0, senza che questo cambi in alcun modo tra le due assegnazioni, per cui la differenza è per forza zero!

Ogni nuova lettura è dettata dal delay (30000)

leggo la pressione relativa su p0. la scrivo su dp1.

dopo 30 secondi rileggo la pressione p0. la scrivo su dp2

se metto sul monitor o sul LCD, le 2 variabili ogni 30 secondi sono diverse. Metti caso che leggo dp1 1020.10 e dp2 1020.15.

se sommo dp1 e dp2 ottengo 2040.25. Se sottraggo 0.00 oppure -0.00

Non è possibile, p0 ha lo stesso valore prima e dopo il delay(), cosa dovrebbe cambiarlo?

SukkoPera: Non è possibile, p0 ha lo stesso valore prima e dopo il delay(), cosa dovrebbe cambiarlo?

Se vuoi ti faccio un video. Metti che è come dici te, ma sull'LCD dato che i valori rimangono "fissi" e non viene aggiornato, la logica stranamente funziona...

Ma per fare come di ci te, come potrei fare?

Non è che è "come dico io" o "come dici tu". È il codice che parla, e qui:

          dp1 = p0;
          delay(30000);
          dp2 = p0;

Non c'è niente che aggiorna magicamente il valore di p0 tra la prima e la seconda assegnazione, punto. dp1 sarà [u]sempre[/u] uguale a dp2, per la proprietà transitiva dell'uguaglianza (ovvero: sono entrambi uguali a p0). Di conseguenza, la loro differenza sarà [u]sempre[/u] 0.

La parte che fa la lettura del sensore vera e propria è costituita da queste 3 righe e tutta la logica che c'è tra di loro:

status = pressure.startPressure(3);
status = pressure.getPressure(P, T);
p0 = pressure.sealevel(P, ALTITUDE);

Come vedi, è l'ultima riga che aggiorna il valore di p0, per cui cambia solo in quel punto del programma. Occorrerebbe ripetere tutto questo dopo il delay(), MA... ricorda che il loop() si ripete di continuo, per cui puoi sfruttare questa cosa a tuo vantaggio, prova a pensarci un attimo, poi ti diamo qualche suggerimento. Per inciso, questo è anche il motivo per cui sul display la pressione cambia, ovvero perché la scrittura su LCD la fai una volta sola nel loop(), dopo la misura effettiva.

SukkoPera: Non è che è "come dico io" o "come dici tu"

Non era mia intenzione di mettere in dubbio quello che dici tu, anzi è proprio il mio lavoro che mi è dubbioso.

Stasera provo a ragionare con la tua spiegazione. Vediamo cosa mi esce.

Grazie mille!

Quello che dico io puoi tranquillamente metterlo in dubbio, non sono (ancora) convinto di essere onniscente ;).

Però che il codice venga eseguito in un certo modo è fuor di dubbio... a meno di bug nel compilatore :D.

Ci sono riuscito!

Grazie @sukkopera e grazie a tutti voi.

In pratica partendo da questa osservazione:

Non c'è niente che aggiorna magicamente il valore di p0 tra la prima e la seconda assegnazione, punto. dp1 sarà sempre uguale a dp2, per la proprietà transitiva dell'uguaglianza (ovvero: sono entrambi uguali a p0). Di conseguenza, la loro differenza sarà sempre 0.

...non ho fatto altro che ripetere la lettura della pressione con un nuovo comando. E funziona!

Ora, dovrei imparare ad usare il millis(), per fare in modo che le letture di T e P si aggiornino ogni 5 secondi, e verificare la tendenza della pressione ogni 12h.

Grazie!

Bcs85: Ora, dovrei imparare ad usare il millis() ....

... per quello basta che studi prima QUI, poi QUI ed infine leggi anche QUI e QUI ... vedrai che ti sarà tutto chiaro :)

Guglielmo

Sì, ma farlo così fa abbastanza schifo, e ti complica a manetta la vita se vuoi fare quel che hai appena detto. Vedi se riesci a elaborare questo suggerimento:

float pPrecedente = -1;

void loop() {
  float pAttuale = ...;  // Qua fare tutto quanto necessario per leggere il sensore e memorizzare la pressione attuale
  if (pPrecedente >= 0) {
    float diff = pAttuale - pPrecedente;
    if (diff > 0) {
      // Pressione aumentata
    } else if (diff < 0) {
      // Pressione diminuita
    } else {
      // Pressione invariata
    }
  }

  pPrecedente = pAttuale;
  delay (30000);
}

Grazie ragazzi!

Attingendo un po di info da ciascuno di voi sono riuscito ad ottenere quello che volevo.

un paio di mesi circa pian piano ma ci sono riuscito.

Una domanda: come si gestisce più schede di programmazione dentro all'ide di Arduino? Vorrei semplificare il programma con più schede, ma ho provato ad aprirne una e quando vado a compilare mi da errore, nonostante reincluda void setup e void loop.