Centralina humidity temperatura suolo – lo sketch – parte II

Questo articolo segue il precedente articolo in cui hai iniziato l’analisi dello sketch Centralina humidity temperatura suolo – lo sketch.

Centralina humidity temperatura suolo pressione bmp085

In questo articolo analizzi la funzione loop() che a sua volta andrà a chiamare le altre funzioni necessarie al corretto funzionamento della tua centralina humidity temperatura suolo.

Lo sketch della centralina humidity temperatura suolo

/*
 * centralina humidity temperatura suolo con Arduino
 *
 * @author: Alfieri Mauro
 * Tw: @mauroalfieri
 * Web: www.mauroalfieri.it
*/

#include <Wire.h>
#include "RTClib.h"
#include <SdFat.h>
#include <dht11.h>
#include <SHT1x.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <LiquidCrystal.h>

#define CS 10
#define DHT11_PIN 15
#define SHT_dataPin  2
#define SHT_clockPin 3
#define BLAKLIGHT 16

#define BUTTON A0

int setModeTime=2000;
int setViewTime=2000;
unsigned long time=0;
unsigned long timeSet=0;

int SELECT[]  =  {720,760};
int LEFT[]    =  {480,520};
int RIGTH[]   =  {0,20};
int UP[]      =  {120,160};
int DOWN[]    =  {300,350};

RTC_DS1307 RTC;
dht11 DHT;
SHT1x sht1x(SHT_dataPin, SHT_clockPin);
LiquidCrystal lcd(8,9,4,5,6,7);
char buffer[50];
char lcdBuffer[16];

int  DHT_h;
int  DHT_t;
char BMP_p[10];
char SHT_t[10];
char SHT_h[10];

int current;

//File myFile;
SdFat sd;
SdFile myFile;
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

void setup () {
    Serial.begin(9600);
    // Serial.print("Initializing SD card...");

    pinMode( CS,OUTPUT );
    pinMode( BUTTON,INPUT ); 
    pinMode( BLAKLIGHT,OUTPUT );

    blacklightOn();
    lcd.begin(16, 2);
    lcd.setCursor(0,0);
    lcd.print("Mandorleto v1.0");
    lcd.setCursor(0,1);
    lcd.print("mauroalfieri.it");

    delay( 3000 );

    lcd.clear();  
    lcd.setCursor(0,0);
    lcd.print("Init SD Card...");
    lcd.setCursor(0,1);

    //if (!SD.begin(CS)) {
    if (!sd.begin(CS, SPI_HALF_SPEED)) {
       sd.initErrorHalt();
      // Serial.println("initialization failed!");
      lcd.print("... Failed   ");
      while(1);
    }
    // Serial.println("initialization done.");
    lcd.print("... Ready    ");

    delay( 2000 );

    lcd.clear(); 
    Wire.begin();
    RTC.begin();
    RTC.sqw(0);		//0 Led off - 1 Freq 1Hz - 2 Freq 4096kHz - 3 Freq 8192kHz - 4 Freq 32768kHz

    lcd.setCursor(0,0);
    lcd.print("Init BMP085 ...");
    lcd.setCursor(0,1);

    delay( 200 );

    if(!bmp.begin()) {
      Serial.print("BMP085 Failed");
      lcd.print("... Failed   ");
      while(1);
    }
    lcd.print("... Ready    ");

    delay( 2000 );
    lcd.clear(); 
    blacklightOff();
}

void loop () {
    if ( ctrlButton( analogRead( BUTTON ) ) == 0 || ctrlButton( analogRead( BUTTON ) ) > 1 ) { time = millis(); }

    DateTime now = RTC.now();

    if (time > 0 && setModeTime < (millis() - time) ) { blacklightOn(); now = setMode( now ); lcd.clear(); }
    if (( now.minute() == 00 ||  now.minute() == 15 ||  now.minute() == 30 || now.minute() == 45 ) && (now.minute() != current)) { blacklightOn(); current=now.minute(); saveData( now ); lcd.clear(); }   
    if ( ctrlButton( analogRead( BUTTON ) ) > 1 ) {  blacklightOn(); viewSensor(); lcd.clear(); }

    sprintf(lcdBuffer, "%02d/%02d/%04d", now.day(), now.month(), now.year() );
    lcd.setCursor(0,0);
    lcd.print(lcdBuffer);
    sprintf(lcdBuffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second() );
    lcd.setCursor(0,1);
    lcd.print(lcdBuffer);

    delay( 1000 );
    blacklightOff();
}

void blacklightOn()  {  digitalWrite( BLAKLIGHT,HIGH ); }
void blacklightOff() {  digitalWrite( BLAKLIGHT,LOW ); }

DateTime setMode( DateTime now ) {
    boolean setModeVal = true;
    int setModeLevel = 0;

    int _day = now.day();
    int _month = now.month();
    int _year = now.year();
    int _hour = now.hour();
    int _min = now.minute();
    int _sec = now.second();

    lcd.clear();
    lcd.setCursor(0,0);
    sprintf(lcdBuffer,  "%s: %02d", "Giorno", _day);
    delay( 1000 );
    timeSet = millis();

    while ( setModeVal ) {
      if ( ctrlButton( analogRead( BUTTON ) ) >= 1 ) { timeSet = millis(); } 
      lcd.setCursor(0,0);

      // Set Day
      if ( setModeLevel == 0 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _day < 31) { _day++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _day > 1) { _day--; }

        sprintf(buffer,  "%s: %02d", "Giorno", _day);
      }
      // Set Month
      if ( setModeLevel == 1 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _month < 12) { _month++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _month > 1) { _month--; }

        sprintf(buffer,  "%s: %02d", "Mese", _month);
      }
      // Set Year
      if ( setModeLevel == 2 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _year < 9999) { _year++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _year > 1900) { _year--; }

        sprintf(buffer,  "%s: %02d", "Anno", _year);
      }
      // Set Hour
      if ( setModeLevel == 3 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _hour < 24) { _hour++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _hour > 1) { _hour--; }

        sprintf(buffer,  "%s: %02d", "Ora", _hour);
      }
      // Set Minute
      if ( setModeLevel == 4 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _min < 60) { _min++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _min > 1) { _min--; }

        sprintf(buffer,  "%s: %02d", "Minuti", _min);
      }
      // Set Second
      if ( setModeLevel == 5 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _sec < 60) { _sec++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _sec > 0) { _sec--; }

        sprintf(buffer,  "%s: %02d", "Secondi", _sec);
      }

      lcd.print( buffer );
      if ( ctrlButton( analogRead( BUTTON ) ) == 4 && setModeLevel > 0) { lcd.clear(); setModeLevel--;  }
      if ( ctrlButton( analogRead( BUTTON ) ) == 5 && setModeLevel < 5 ) { lcd.clear(); setModeLevel++;  }
      // if ( setModeLevel > 5 ) { setModeLevel=0; }

      if ((timeSet > 0 && (setModeTime*2) < (millis() - timeSet)) || ( ctrlButton( analogRead( BUTTON ) ) == 1) ) {
         RTC.adjust(DateTime(_year, _month, _day, _hour, _min, _sec));
         setModeVal = false;
      }
      delay(200);
    }

    return RTC.now();
}

void readSensor() {
   int chk = DHT.read(DHT11_PIN);
   if ( chk != DHTLIB_OK ) {
     lcd.clear();
     lcd.setCursor(0,0);
     lcd.print("DHT11 (Aria)");
     lcd.setCursor(0,1);
     switch (chk){
         case DHTLIB_OK:  
                 lcd.print("SUCCESS");
                 break;
         case DHTLIB_ERROR_CHECKSUM: 
                 lcd.print("Checksum error");
                 break;
         case DHTLIB_ERROR_TIMEOUT: 
                 lcd.print("Time out error");
                 break;
         default: 
                 lcd.print("Unknown error");
                 break;
      }
      delay( setViewTime );
    }
    DHT_h=DHT.humidity;
    DHT_t=DHT.temperature;
    // -----------------------------------------------------------------------
    sensors_event_t event;
    bmp.getEvent(&event);
    if (event.pressure) { dtostrf(event.pressure, 5, 2, BMP_p); }    
    // -----------------------------------------------------------------------
    dtostrf(sht1x.readHumidity(), 5, 2, SHT_h);
    dtostrf(sht1x.readTemperatureC(), 5, 2, SHT_t);
}

void viewSensor() {
  lcd.clear(); readSensor();

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("DHT11 (Aria)");
  lcd.setCursor(0,1);
  sprintf(lcdBuffer,  "%s %02d", "Humidty", DHT_h);
  lcd.print(lcdBuffer);

  delay( setViewTime );

  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("DHT11 (Aria)");
  lcd.setCursor(0,1);
  sprintf(lcdBuffer,  "%s %02d", "Temp.", DHT_t);
  lcd.print(lcdBuffer);

  delay( setViewTime );

  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("BMP085 Pressione");
  lcd.setCursor(0,1);
  sprintf(lcdBuffer,  "%s %s", "Pressione", BMP_p);
  lcd.print(lcdBuffer);

  delay( setViewTime );

  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("SHT (Suolo)");
  lcd.setCursor(0,1);
  sprintf(lcdBuffer,  "%s %s", "Humidity", SHT_h);
  lcd.print(lcdBuffer);

  delay( setViewTime );

  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("SHT (Suolo)");
  lcd.setCursor(0,1);
  sprintf(lcdBuffer,  "%s %s", "Temp.", SHT_t);
  lcd.print(lcdBuffer);

  delay( setViewTime ); 
  lcd.clear();   
}

void saveData( DateTime now ) {
    readSensor();
    sprintf(buffer,  "%02d/%02d/%d %02d:%02d:%02d %02d %02d %s %s %s", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), DHT_h, DHT_t, BMP_p, SHT_h, SHT_t );

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Salvataggio dati");
    if (myFile.open("dati.log", O_RDWR | O_CREAT | O_AT_END)) {
      myFile.println(buffer);
      myFile.close();      
      lcd.setCursor(0,1);
      lcd.print("SD Write Success");
    } else {
      sd.errorHalt("opening dati.log for write failed");       
      lcd.setCursor(0,1);
      lcd.print("SD Write Error");
    }
    delay(1000);
}

int ctrlButton( int button ) {

  if ( SELECT[0] <= button && button <= SELECT[1] ) { return 1; }
  if ( LEFT[0] <= button && button <= LEFT[1] )     { return 2; }
  if ( RIGTH[0] <= button && button <= RIGTH[1] )   { return 3; }
  if ( UP[0] <= button && button <= UP[1] )         { return 4; }
  if ( DOWN[0] <= button && button <= DOWN[1] )     { return 5; }

  return 0;
}

come sai la prima parte dello sketch puoi leggerlo nell’articolo di introduzione allo sketch, oggi analizzerai le funzioni loop(), blacklightOn(), blacklightOff(), setMode() lasciando per un prossimo articolo le funzioni di raccolta dati e salvataggio su SD Card.

Inizia dalla loop() alla linea 115: definisci la funzione loop();

linee 116-117: controlla la pressione dei pulsanti richiamando la funzione ctrlButton(), già utilizzata in precednti articoli dedicati alla key pad LCD il cui valore di ritorno è un numero da 0 ( nessun pulsante premuto ) a 5 ( pressione del pulsante DOWN ). In queste righe verifichi che il pulsante premuto sia diverso da 1 e in tal caso assegni il tempo corrente al alla variabile time.

linea 119: imposta la data e l’ora nell’istanza now di tipo DateTime;

linee 121-122: trascorso un tempo superiore a quello che hai impostato nella variabile setModeTime accendi il display richiamando la funzione blacklightOn() e richiama la funzione setMode() il cui scopo è consentirti di impostare data ed ora corrente senza collegare Arduino al Pc. Il risultato dell’impostazione di data ed ora viene riassegnato all’istanza now e procedi a pulire il display LCD;

linee 123-125: controlla il trascorrere dei minuti della RTC ed ogni 15 minuti se il valore di now.minute() è differente dal valore contenuto nella variabile current :

  • accende il display LCD ( BlaklightOn() )
  • assegna il minuto corrente alla variabile current
  • richiama saveData() per il salvataggio dei dati rilevati dalle sonde
  • pulisce il display LCD

L’epsediente della variabile current impedisce che se il salvataggio duri meno di un minuto la centralina humidity temperatura suolo salvi più righe per il medesimo minuto;

linee 126-127: se premi un pulsante di quelli che riportano valori superiori ad 1 ( LEFT,RIGHT,UP,DOWN ) accendi il display, richiami la funzione di visualizzazione dei dati rilevati dalla centralina humidity temperatura suolo attraverso i suoi sensori e pulisci il display LCD;

linee 129-135: componi le due righe con la data e l’ora corrente e le visualizzi sul display LCD;

linee 137-138: attendi un tempo pari ad un secondo e spegni il display LCD richiamando la funzione blacklightOff().

void blacklightOn()  {  digitalWrite( BLAKLIGHT,HIGH ); }
void blacklightOff() {  digitalWrite( BLAKLIGHT,LOW ); }

le due funzioni blacklightOn e blacklightOff hanno il compito di accendere e spegnere la retro illuminazione del display LCD in modo da rendere tale operazione del tutto indipendente dal tipo di display utilizzato e dal pin a cui è connessa la retro illuminazione.

linea 141: accende la retro illuminazione portando a livello HIGH il pin BLAKLIGHT;

linea 142: spegne la retro illuminazione portando a livello LOW il pin BLAKLIGHT;

DateTime setMode( DateTime now ) {
    boolean setModeVal = true;
    int setModeLevel = 0;

    int _day = now.day();
    int _month = now.month();
    int _year = now.year();
    int _hour = now.hour();
    int _min = now.minute();
    int _sec = now.second();

    lcd.clear();
    lcd.setCursor(0,0);
    sprintf(lcdBuffer,  "%s: %02d", "Giorno", _day);
    delay( 1000 );
    timeSet = millis();

    while ( setModeVal ) {
      if ( ctrlButton( analogRead( BUTTON ) ) >= 1 ) { timeSet = millis(); } 
      lcd.setCursor(0,0);

      // Set Day
      if ( setModeLevel == 0 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _day < 31) { _day++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _day > 1) { _day--; }

        sprintf(buffer,  "%s: %02d", "Giorno", _day);
      }
      // Set Month
      if ( setModeLevel == 1 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _month < 12) { _month++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _month > 1) { _month--; }

        sprintf(buffer,  "%s: %02d", "Mese", _month);
      }
      // Set Year
      if ( setModeLevel == 2 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _year < 9999) { _year++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _year > 1900) { _year--; }

        sprintf(buffer,  "%s: %02d", "Anno", _year);
      }
      // Set Hour
      if ( setModeLevel == 3 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _hour < 24) { _hour++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _hour > 1) { _hour--; }

        sprintf(buffer,  "%s: %02d", "Ora", _hour);
      }
      // Set Minute
      if ( setModeLevel == 4 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _min < 60) { _min++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _min > 1) { _min--; }

        sprintf(buffer,  "%s: %02d", "Minuti", _min);
      }
      // Set Second
      if ( setModeLevel == 5 ) {
        if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _sec < 60) { _sec++; }
        if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _sec > 0) { _sec--; }

        sprintf(buffer,  "%s: %02d", "Secondi", _sec);
      }

      lcd.print( buffer );
      if ( ctrlButton( analogRead( BUTTON ) ) == 4 && setModeLevel > 0) { lcd.clear(); setModeLevel--;  }
      if ( ctrlButton( analogRead( BUTTON ) ) == 5 && setModeLevel < 5 ) { lcd.clear(); setModeLevel++;  }
      // if ( setModeLevel > 5 ) { setModeLevel=0; }

      if ((timeSet > 0 && (setModeTime*2) < (millis() - timeSet)) || ( ctrlButton( analogRead( BUTTON ) ) == 1) ) {
         RTC.adjust(DateTime(_year, _month, _day, _hour, _min, _sec));
         setModeVal = false;
      }
      delay(200);
    }

    return RTC.now();
}

la funzione setMode( DateTime now ) accetta come valore in ingresso l’istanza now e restituisce un’istanza di tipo DateTime dopo l’impostazione della data e dell’ora corrente.

Trovi le descrizione della funzione setMode() in altri articoli dedicati all’RTC

In pratiica il risultato che otterrai è che alla pressione del pulsante SELECT per un tempo maggiore a quello impostato nella variabile setModeTime lo sketch richiama questa funzione.

La pressione dei pulsanti UP e DOWN ti sposta tra i menu nella sequenza: GIORNO -> MESE -> ANNO -> ORA -> MINUTI -> SECONDI mentre i pulsanti LEFT e RIGHT servono ad incrementare e decrementare il valore da impostare per ogni voce del sottomenu.

Per salvare i valori impostati è necessario non toccare alcun pulsante per un tempo doppio del valore impostato nella variabile setModeTime o premere il pulsante SELCT in modo che il controllo alla linea 220 provveda a salvare i valori impostati nella RTC Shield ed uscire dalla modalità di impostazione della data e dell’ora.

In questo video puoi vedere come si imposta la data e l’ora per la centralina humidity temperatura suolo.

Buon monitoraggio !!!

Cortesemente, prima di inserire i commenti leggi il regolamento

Permanent link to this article: http://www.mauroalfieri.it/elettronica/centralina-humidity-temperatura-suolo-lo-sketch-parte-ii.html

4 comments

Skip to comment form

    • Eliseo on 19 settembre 2014 at 12:16
    • Reply

    Buongiorno,
    Seguo molto le sue lezioni ed i suoi esempi riguardo Arduino, e la ringrazio molto per questo aiuto.
    Avrei però bisogno di un consiglio.
    Devo fare un programma simile a questo, cioè gestire lcd e pulsanti. Volevo sapere se esiste un metodo più semplice per la gestione del menù e l’interazione con esso attraverso i pulsanti.
    GRAZIE

    1. Ciao Eliseo,
      grazie per i complimenti.
      L’unico modo che conosco è questo, non escludo ne esistano altri, tuttavia avessi avuto a disposizione un metodo più semplice lo avrei di certo usato.
      Se trovi un metodo più semplice e ti va di condividerlo gli posso dedicare un progetto.

    • Eliseo on 20 settembre 2014 at 11:03
    • Reply

    Ho trovato la libreria menwiz, però nonostante gli esempi faccio fatica a capire come funziona e soprattutto se mi permette o meno di risparmiare memoria. Mi servirebbe un menu con 5 pagine totali, 3 di programmazione e 2 di visualizzazione….

    1. Ciao Eliseo,
      non la conoscevo, se ho tempo la guardo, intanto se approfondisci il suo funzionamento sono a disposizione per condividerlo con altri appassionati.

Lascia un commento

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.