Integrare Shield Ethernet a progetto già funzionante

Salve a tutti!
Mi presento...
Sono un nuovo iscritto del forum, nonché un novizio anche in tema Arduino.
Che però, sotto consiglio di un amico, ed il recente avvicinarmi al mondo dell'automazione, ho deciso di provare a realizzare un piccolo progettino per il monitoraggio del livello dell'acqua nel mio autoclave.
Vi illustro brevemente il funzionamento.

Il progetto si compone di 4 stadi:

  • Logica: per la logica ho utilizzato un Arduino UNO al quale ho connesso una scheda da 8 relè. Ho integrato anche una porta USB-B da pannello per flashare eventuali modifiche al SW e un altro interruttore a chiave per effettuare il reset.
  • Output: per visualizzare lo stato del sistema ho connesso 1 display LCD il quale mostra prima una sorta di boot, poi il nome del sistema e infine lo stato. Una lampadina per indicare che Arduino è acceso. E una torretta di segnalazione verde/rossa per indicare lo stato del sistema.
  • Input: per prelevare i dati ho utilizzato un banale sensore ad ultrasuoni che tramite una serie di calcoli ripartisce le misure in livelli e stati.

La macchina è suddivisa in 2 unità:

  • 1 Unita: alimentazione, logica, output
  • 2 Unità: input

Dopo aver testato il sistema per diverse settimane ho voluto acquistare una Ethernet Shield per espandere le sue potenzialità. Ciò che mi interessava fare era quello di creare una sorta di Web Server locale in HTML dove andare a visualizzare semplicemente gli stati della macchina. Così dopo aver provato assieme al mio amico il funzionamento di base della Shield l'abbiamo integrata. Una volta passati i cavi e richiuso il pannello andiamo per flashare il nuovo SW da noi modificato sulla base dei tanti web server e con nostra spiacevole sorpresa niente andava come doveva.

Questo è il codice dopo l'aggiunta della Shield:

#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>

#include <LiquidCrystal.h>
  const int Trig = 13, Echo = 12, Green = 8, Max = 7, Min = 6;
  const int rs = 0, en = 1, d4 = 2, d5 = 3, d6 = 4, d7 = 5;
  const int minimo = 90, massimo = 50;
  LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

byte avvio[8] = {
        B11111,
        B00000,
        B11111,
        B11111,
        B11111,
        B11111,
        B00000,
        B11111
};

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

IPAddress ip(192, 168, 178, 49);

EthernetServer server(80);

void setup() {

  Ethernet.begin(mac, ip);
  server.begin();
  
  lcd.createChar(1, avvio);
  pinMode(Trig,OUTPUT);
  pinMode(Echo,INPUT);
  pinMode(Min,OUTPUT); 
  pinMode(Max,OUTPUT);
  pinMode(Green,OUTPUT);
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.print("  CMV  SISTEMI  ");
  delay(1000);
    for(int i=-1;i<15;i++) {
      lcd.setCursor(i+1,1);
      lcd.write(1);
      delay(500);
    }
  delay(1000);
  lcd.clear();
  delay(250);
  lcd.setCursor(0,0);
  lcd.print("  MONITORAGGIO  ");
  delay(200);
  lcd.setCursor(0,1);
  lcd.print(" RISERVA IDRICA ");
  delay(4000);
  lcd.clear();
}

void loop() {
  //Rele Segnalazione 5V
  digitalWrite(Green,LOW);
  //Avvio Server 
  EthernetClient client = server.available();
  if (client) {
      boolean blank = true;
      while (client.connected()) {
          if (client.available()) {
               char c = client.read();
               if ((c == '\n') && blank){
                  client.println("HTTP/1.1 200 OK");
                  client.println("Content-Type: text/html");
                  client.println("Connection: close");  // the connection will be closed after completion of the response              
                  client.println();
                  client.println("<!DOCTYPE HTML>");
                  client.println("<html>");
                  client.println("<H1>PROVA</H1>");                          
                  client.println("</html>");
                  break;
               }

               if (c == '\n') {
                   blank = true; 
               } else if (c != '\r') {
                   blank = false; 
               }
          }   
      }
      delay(1);
      client.stop();
      Ethernet.maintain();
  }  
  //Attivazione Sensore
  digitalWrite(Trig, LOW);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);
  //Calcolo distanza e livello
  long durata = pulseIn(Echo, HIGH);
  long distanza = durata/58.31; 
  int livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100          
  delay(500);

  String liv = (String)livello;

    while(livello > 100){
    lcd.setCursor(0,0);
    lcd.print("    ANOMALIA    ");
    delay(250);
    lcd.setCursor(0,1);
    lcd.print("  Livello: " + liv + "%");
    delay(100);
    digitalWrite(Min,LOW);
    delay(500);
    digitalWrite(Max,LOW);
    delay(100);
    digitalWrite(Green,LOW);
    digitalWrite(Trig, LOW);
    digitalWrite(Trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(Trig, LOW);
    durata = pulseIn(Echo, HIGH);
    distanza = durata/58.31; 
    livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100
    liv = (String)livello;
   }
  
  //Aggiornamento Display con Stato Autoclave
  if(distanza > minimo) {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: VUOTO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,LOW);
     delay(500);
     digitalWrite(Max,HIGH);
  }
  else{
    if(distanza < massimo) {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: PIENO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,HIGH);
     delay(500);
     digitalWrite(Max,LOW);
    }
    else {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: MEDIO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,LOW);
     delay(500);
     digitalWrite(Max,HIGH);
     }
   }
   
 }

Abbiamo provato e riprovato ma ogni volta o il programma si blocca in anomalia, o il display non stampa niente, ma sopratutto sulla Shield si accendono tutte le luci tranne quella di TX ed L (non link quella va) e quindi non si connette.

Tengo molto a questo progetto, visto che ci ho speso anche qualche soldino. Il mio amico dice che forse per il mio scopo era meglio un PLC :smiley: , io invece sperò che voi possiate aiutarmi.

Temo che l'utilizzo smodato del delay() sia tra le cause principali del funzionamento diverso da quello che vi aspettate.
Inoltre non vedo l'istruzione che inizializza l'ethernet shield *Ethernet.init(PIN_CS); *

Ma questa sintassi funziona o da problemi:

int livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100         
  delay(500);

  String liv = (String)livello;   // <<- cast esplicito da int to String

Ciao.

cotestatnt:
Temo che l'utilizzo smodato del delay() sia tra le cause principali del funzionamento diverso da quello che vi aspettate.
Inoltre non vedo l'istruzione che inizializza l'ethernet shield Ethernet.init(PIN_CS);

Quali delay() secondo te dovremmo rimuovere?
No effettivamente non è presente tale istruzione, anche perché essendoci basati al 90% sull'esempio di Arduino, non vedendola riportata non l'abbiamo utilizzata.
Dove andrebbe inserita? E a cosa serve di preciso?

Maurotec:
Ma questa sintassi funziona o da problemi:

int livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100         

delay(500);

String liv = (String)livello;   // <<- cast esplicito da int to String




Ciao.

Si nel codice senza la parte ETH funziona perfettamente ed è proprio la porzione di calcolo del livello.

richardtdj:
Quali delay() secondo te dovremmo rimuovere?

Se dipendesse da me, tutti. O perlomeno tutti quelli usati nel loop().
Anche quel while(livello > 100) è bloccante, quindi fintanto che livello>100 il micro farà solo quel gruppo di istruzioni.

L'istruzione init() c'è negli esempi, ma va de-commentata perché ovviamente il numero di pin da passare come argomento dipende dalla shield usata. Quelle più comuni, come scritto, usano il pin D10.

cotestatnt:
Se dipendesse da me, tutti. O perlomeno tutti quelli usati nel loop().
Anche quel while(livello > 100) è bloccante, quindi fintanto che livello>100 il micro farà solo quel gruppo di istruzioni.

L'istruzione init() c'è negli esempi, ma va de-commentata perché ovviamente il numero di pin da passare come argomento dipende dalla shield usata. Quelle più comuni, come scritto, usano il pin D10.

Insomma è un po' tutto un casino...
Partiamo dalla INIT. Ho impostato il PIN 10 che è libero, però ho letto che per l'SPI Arduino usa anche il 13,12,11 ma se i primi 2 li usa il sensore è un problema?
Adesso visto che di (livello <> 100) ce ne sono di diversi e che ripeto hanno sempre funzionato, mi vien da pensare che forse è anche un problema di posizionamento della parte di server nel loop. Dovrei mettere quelle istruzioni in che parte per far si che se il sistema è connesso invii i dati, senno semplicemente funzioni e mostri l'output sul display e la torretta?

richardtdj:
Insomma è un po' tutto un casino...
Partiamo dalla INIT. Ho impostato il PIN 10 che è libero, però ho letto che per l'SPI Arduino usa anche il 13,12,11 ma se i primi 2 li usa il sensore è un problema?

E' un problema si, a meno che il sensore non sia con interfaccia SPI non puoi far condividere i pin, devi spostare i pin che usi in modo che quelli usati dalla shield non siano in uso per le tue altre necessità (sensori, pulsanti, display, ecc.)
Altra cosa, l'uso della classe String dovresti evitarla come la peste, cerca sul forum ci sono tantissime discussioni in merito e dai un occhio anche qui
Anch'io ti suggerisco di rivedere la logica di funzionamento in modo che non ci siano (o quantomeno siamo sono in punti strettamente necessari) porzioni di codice bloccante

Allora ragazzi ci sono stati degli sviluppi...
Ho approfondito la questione INIT e SPI così dopo aver integrato la prima istruzione nel voi usando il pin 10 ed aver spostato il sensore dal 13/12 lasciando libero anche l’11 ed eliminando un pin del relè, riposizionato il segmento di code del loop qualcosa è successo.
La scheda si è connessa con l’IP da me assegnato e sono riuscito a far stampare in LAN su HTML il livello calcolato tramite la stringa.
Adesso stasera cercherò di pulire il code e risolvere un altro problema.
Ovvero:
Il sistema parte... finto boot —> nome —> stato e livello
Se cambia il livello o lo stato gli output analogici lo mostrano, ma il sito invece anche se lo refresho mostra solo se è pari a 100.

Inizio anche a valutare l’acquisto di un mega per pilotare delle elettrovalvole.

>richardtdj: in conformintà al REGOLAMENTO, punto 15 e suoi sottopunti, qui NON sono permesse discussioni che coinvolgono tensioni oltre la bassissima tensione. Ora, dal tuo post iniziale, non si capisce bene se tu alimenti solo con degli alimentatori da 230V a bassissima tensione o intervieni anche su tale tensione a 230V con dei relé, per cui, onde evitare la chiusura immediata del thread ti chiedo cortesemente di specificare bene la cosa ed eventualmente, per tagliare la testa al toro, di eliminare qualsiasi riferimento alla tensione di rete dal tuo post modificandolo. Grazie.

Guglielmo

Scusate non sapevo...
Provvedo subito a correggere il post.

richardtdj:
Provvedo subito a correggere il post.

... perfetto, GRAZIE !!! :slight_smile:

Guglielmo

Ragazzi con questo code sono riuscito quindi a far funzionare la shield, creare una pagina HTML sulla mia rete LAN ed accedervi mostrando alcuni dati. C'è solo un problema... nel testare il tutto ho visto che quando entra in anomalia la pagina web non riesce a caricare, se invece il livello torna a 100 va perfettamente. Quale ciclo è sbagliato se di ciò si tratta?

#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>

  const int Trig = 9, Echo = 8, Max = 7, Min = 6;
  const int rs = 0, en = 1, d4 = 2, d5 = 3, d6 = 4, d7 = 5;
  const int minimo = 90, massimo = 50;
  
  LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

byte avvio[8] = {
        B11111,
        B00000,
        B11111,
        B11111,
        B11111,
        B11111,
        B00000,
        B11111
};

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

IPAddress ip(192, 168, 178, 49);

EthernetServer server(80);

void setup() {
  
  Ethernet.init(10);
  Ethernet.begin(mac, ip);
  server.begin();
  
  lcd.createChar(1, avvio);
  
  pinMode(Trig,OUTPUT);
  pinMode(Echo,INPUT);
  pinMode(Min,OUTPUT); 
  pinMode(Max,OUTPUT);
  
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.print("  CMV  SISTEMI  ");
  delay(1000);
    for(int i=-1;i<15;i++) {
      lcd.setCursor(i+1,1);
      lcd.write(1);
      delay(500);
    }
  delay(1000);
  lcd.clear();
  delay(250);
  lcd.setCursor(0,0);
  lcd.print("  MONITORAGGIO  ");
  delay(200);
  lcd.setCursor(0,1);
  lcd.print(" RISERVA IDRICA ");
  delay(4000);
  lcd.clear();
}

void loop() {
  
  //Attivazione Sensore
  digitalWrite(Trig, LOW);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);
  
  //Calcolo distanza e livello
  long durata = pulseIn(Echo, HIGH);
  long distanza = durata/58.31; 
  int livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100          
  delay(500);

  String liv = (String)livello;

    while(livello > 100){
    lcd.setCursor(0,0);
    lcd.print("    ANOMALIA    ");
    delay(250);
    lcd.setCursor(0,1);
    lcd.print("  Livello: " + liv + "%");
    delay(100);
    digitalWrite(Min,LOW);
    delay(500);
    digitalWrite(Max,LOW);
    delay(100);
    digitalWrite(Trig, LOW);
    digitalWrite(Trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(Trig, LOW);
    durata = pulseIn(Echo, HIGH);
    distanza = durata/58.31; 
    livello = 100 - (((distanza-15)*100)/110) ;   // (distanza-15) : livello = 110 : 100
    liv = (String)livello;
   }

  //Aggiornamento Display con Stato Autoclave
  if(distanza > minimo) {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: VUOTO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,LOW);
     delay(500);
     digitalWrite(Max,HIGH);
  }
  else{
    if(distanza < massimo) {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: PIENO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,HIGH);
     delay(500);
     digitalWrite(Max,LOW);
    }
    else {
     lcd.setCursor(0,0);
     lcd.print("AUTOCLAVE: MEDIO ");
     delay(250);
     lcd.setCursor(0,1);
     lcd.print("  Livello: " + liv + "%");
     delay(100);
     digitalWrite(Min,LOW);
     delay(500);
     digitalWrite(Max,HIGH);
     }
   }

   //Avvio Server
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          //Pagina HTML
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  
          client.println("Refresh: 5");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<head>");
          client.println("<title> Sistema Di Monitoraggio Riserva Idrica </title>");
          client.println("</head>");
          client.println("<body>");
          client.println("<h2 align='center'><font color='gray'> CMV Sistemi </font></h2>");
          client.println("<h1 align='center'> Sistema Di Monitoraggio Riserva Idrica </h1>");
          client.println("
");
          client.println("<p table align='center'>");
          client.println("<tr><b>Autoclave: </b></tr>");
          client.print("<tr>"); 
          //client.print state
          client.print("</tr>");
          client.println("
");
          client.println("<tr><b>Autoclave: </b></tr>");
          client.print("<tr>"); 
          //client.print(liv);
          client.print("%");
          client.print("</tr>");
          client.println("</p>");
          client.println("</body>");
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        } else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

Ha indicato il motivo @cotestatnt al post #4 il while è bloccante, ovvero finché stai li dentro Arduino non può far altro e quindi l'adattatore web non risponderà mai.
Non sei su un PC dove c'è multithreading, concorrenza ecc. Arduino fa una cosa alla volta, velocemente ma solo una.
Devi riprogettare il codice in modo che se rilevi l'anomalia la gestisci ma senza l'uso di while o codice che blocca l'esecuzione in un punto.
Per semplicità dovresti concepire il codice sfruttando come unico ciclo il loop stesso, ovvero nienete while bloccanti, delay, ecc.
Altra cosa che rinnovo e poi non ripeterò più, se continua ad usare la classe String poi ti ritroverai che quando il prodotto è operativo "stranmente" dopo un periodo di funzionamento più o meno lungo si bloccherà a casaccio, quando sperimenterai queste situazioni almeno saprai il perché :wink:

fabpolli:
se continua ad usare la classe String poi ti ritroverai che quando il prodotto è operativo "stranmente" dopo un periodo di funzionamento più o meno lungo si bloccherà a casaccio

Pur concordando completamente sul fatto che poteva evitare di usarla (visto che in pratica la usa solo per una conversione int-to-string), per come è utilizzata in questo caso specifico e particolare, dubito che avrà mai dei problemi.
E' una variabile locale che al massimo può assumere una lunghezza di 4 byte (terminatore di stringa incluso) visto che il valore passato va da 0 a 100 e non viene mai concatenata con altro.

Si ora la usa per quello, poi quando vorrà comporre una pagina web più "figa" penso proprio che le String prolifereranno a dismisura :slight_smile:

Allora ragazzi!
Stamani mi ci son messo di punta e grazie anche ai vostri consigli ho capito che il loop era pieno zeppo di problemi.
Infatti dopo aver scollato il sensore dalla cisterna ed averlo posto al suo fianco per ricalcarne l'altezza, nel simulare una misura con una tavoletta di legno ho riscontrato ciò:
Misure falsate, relè che cambiavano di stato quando non dovevano, display che mostrava strani caratteri, ecc.
Adesso, dopo aver dato una ripulita al code vorrei rivedere proprio l'algoritmo di calcolo dei livelli e degli stati.
Avevo pensato ad un qualcosa del genere:

  • Viene effettuata la misurazione (ogni tot. secondi)
  • Viene preso il dato della misurazione ed elaborato estrapolandone 1 variabile per lo stato (PIENO, MEDIO, VUOTO, ANOMALIA) e 1 variabile per il livello (xxx%)
  • In base a queste variabili viene fatto un controllo e vengono stampate sul display, pagina HTML e attivati i relativi pin ai relè
  • Il ciclo continua all'infinito per garantire sempre una corretta misurazione

Adesso...
Non avendo questa grande esperienza con Arduino ed il C avevo provato ad utilizzare stringhe, if, else, ecc.
Ma grazie a voi ho capito che non sia proprio la soluzione migliore.
Per cui vi chiedo, secondo voi quali sarebbero le variabili giuste da utilizzare e come potrei impostare questi cicli per far si che tutto funzioni e sia altrettanto semplice?
Forse chiedo troppo? :roll_eyes:

Generalmente si opta per evitare i delay quando non indispesabili e al loro posto strutturare il codice con una logica basata sull'uso della funzione millis(), nel tuo caso ad esempio per leggere il sensore ogni tot secondi per rendere non bloccante il tutto dovresti porprio sfruttare la logica di millis().
If, else, switch, while e for vanno benissimo sono che vanno usati con criterio ovvero, se devi fare la scansione di tutti gli elementi di un array ben venga il while o il for, ma se usi il while per stare in un certo punto del codice devi farlo sapendo cosa comporta, ovvero null'altro potrà esser fatto finché non si esce da quel while. Di per se non è errato, se ad esempio non devi continuare a far altro finché non è stato premuto un pulsante allora potrebbe anche andare bene, anche se consiglio sempre si usare una strada non bloccante.
In questi casi quel che devi usare (e cercare sul forum perché ci sono svariate discussioni in merito) è una macchina a stati finiti, per esempio un programma che deve aspettare che venga premuto il pulsante A, quando è stato premuto aspetta che sia premuto il pulsante B, e solo allora parte a far quel che deve puoi vederlo tipo così:

void loop()
{
   switch(STATO_OPERATIVO)
  {
     case ASPETTO_A:
        if (pulsanteAPremuto)
        {
            STATO_OPERATIVO = ASPETTO_B
        }
        break;
      case ASPETTO_B:
        if (pulsanteAPremuto)
        {
            STATO_OPERATIVO = VIA
        }
        break;
      case VIA:
        varie funzioni, operazioni ecc.
        ...        
        programma terminato torno ad aspettare 
        STATO_OPERATIVO = ASPETTO_A
        break;
  }
  ..altre operazioni eseguite sempre (Es. aggiornare ora su lcd)...
}

Come puoi vedere nulla è bloccante e il loop continua a girare in attesa degli eventi
Altra cosa, il non uso della classe String, qui puoi optare per due strade, la prima usare la classe SafeString come indicato in precedenza oppure fare uno sforzo e imparare ad usare le stringhe classiche del C (array di char) con le relative funzioni di manipolazione (Es. strcmp, strncpy, strncat, ecc.) a quel punto non avrai i problemi legati all'utilizzo della classe String (Blocchi improvvisi, ecc.)
Altra cosa importante, l'LCD... non aggiornare mai i dati visualizzati se non quando questi cambiano sembra uno sforzo inutile ma in realtà non lo è anzi, migliora i tempi di risposta del programma, evita sfarfallamenti vari ecc.
Prendiamo ad esempio che tu stampi l'ora sull'LCD, potresti aggiornare il dato ad ogni giro di loop, ovvero svariate volte al secondo. Sicuro vedresti sfarfallare l'LCD e avresti aggiornamenti non necessari che in molti casi portano a blocchi improvvisi o alla comparsa di caratteri strani sull'LCD stesso (ma molto dipende dall'lcd, dallalibreria usate, ecc.), quindi se pensiamo di stampare ore e minuti solo quando questi cambiano ti basta usare delle variabili di appoggio per memorizzare quello che hai visualizzato se l'ora o il minuto cambiano allora e solo allora andrai ad aggiornare l'LCD, es:

if(ora_attuale!=ora_visualizzata)
{
  lcd.setCursor(0,0)
  lcd.print(ora_attuale)
  ora_visualizzata=ora_attuale;
}

if(min_attuale!=min_visualizzato)
{
  lcd.setCursor(0,3)
  lcd.print(min_attuale)
  min_visualizzato=min_attuale;
}

in tal modo aggiornerai il display solo ogni minuto e per la sola porzione che serve, ovvero per 59 minuti solo i due caratteri dei minuti e una volta all'ora anche i primi due caratteri dell'ora. Gli eventuali : che separano ore e minuti li stamperai solo una volta all'inizio.
Ovvio che se la maggior parte dei dati variano (es. cambi di schermate nei setup o cose del genere) allora ben venga una bella clear()
Altra cosa da tenere sempre a mente, su micro con poche risorse l'ottimizzazione è una cosa da tenere sempre a mente, quindi usare i tipi di dato corretti, ovvero se devi memorizzare lo stato di un pin che può essere 0 o 1 basta e avanza un byte o un bool inutile scomodare un int che, di fatto, ti fa buttare via un byte.
Hai valori di un sensore da 0 a 255, stessa cosa usa un byte e non un long, un int, ecc.
Visto che stai approcciando ad una completa ristesura del codice inizia per gradi, ovvero la gestione del sensore, quando lettura e cambi di stato (OK, ERRORE, BASSO, Ecc.) funzionano allora passa alla funzione succesiva (Es. stampare su lcd). Se riesci a rendere le varie operazioni atomiche, incluse in una funzone poi estendere il codice sarà più facile.
Se non si è esperti è sempre bene ripartire da un programma vuoto per gestire le varie cose, ti permette di imparare e se qualcosa non va dipenderà dal codice e non da altre operazioni svolte da altre porzioni, esempio per gstire bene l'lcd fatti un programma a parte che ti consenta di impratichirti al meglio nela sua gestione e poi integralo in quello principale e così via.
Chiaro che avendo le idee chiare si può andare più spediti ma se non le sia hanno si rischi di creare codice incasinato che poi funziona reggendosi con le pezze.

Ho visto dopo il tuo codice, no non è un buon inizio perché usi i delay anche quando non espressamente necessario. Impara la logica di millis, per capire le basi con cui si usa millis() consiglio prima la lettura di QUESTO post esplicativo, dopo di che lo studio di come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... alla fine il tutto dovrebbe essere più chiaro :slight_smile:

Grazie a tutti ragazzi!
Quanta roba... :smiley: ma la studierò e cercherò di applicarla al meglio possibile.
L'unica cosa, non utilizzo pulsanti ma do solo corrente ad Arduino e poi deve fare tutto da solo. Cambia qualcosa?
Vi tengo aggiornati! :wink:

I pulsanti era un esempio fatto per cercare di spiegare il concetto di macchina a stati finiti e possibili "stati" di attesa. Se non hai pulsanti i tuoi stati dipenderanno sono dai dati in arrivo dal sensore ad esempio ma il succo non cambia