problema display LCD

Ciao a tutti, ho scritto questo programma che consiste nel attivare o meno dei sistemi di riscaldamento o raffreddamento a seconda della temperatura rilevata (tramite LM35) e quella impostata tramite 3 pulsanti (set, up e down). In condizioni normali tutto funziona, riscontro un problema quando entro nel menu settaggio (while setting), in cui sul display compaiono caratteri incomprensibili e sembra che il programma vada in tilt. Allego il codice:

#include <LiquidCrystal.h>

LiquidCrystal lcd (10,9,5,6,7,8);

//variabili da settare
const int tempoSettaggio=5000;
const int range=1;
//variabili
int sens;
float temp;
byte tempset=25;
//temperatura range
byte Tmax=tempset+range;
byte Tmin=tempset-range;
//pulsanti
const int sets=13;
bool set=0;
bool set1=0;
const int ups=11;
bool up=0;
bool up1=0;
const int downs=12;
bool down=0;
bool down1=0;
//variabili di stato
bool setting=0;
bool riscaldamento=0;
bool raffreddamento=0;
//variabili-cronometro
unsigned long inizioSet;
//pin transistor
const int caldo=3;
const int freddo=4;
const int ledCaldo=1;
const int ledFreddo=2;

void setup(){
  lcd.begin(16,2);
  pinMode(sets, INPUT);
  pinMode(ups, INPUT);
  pinMode(downs, INPUT);
  pinMode(caldo, OUTPUT);
  pinMode(freddo, OUTPUT);
  pinMode(ledCaldo, OUTPUT);
  pinMode(ledFreddo, OUTPUT);
  lcd.clear();
}

void loop(){
  sens=analogRead(A0);
  temp=sens*0.48828125;
  lcd.home();
  lcd.print("temp:");
  lcd.print(temp);
  lcd.setCursor(0,1);
  lcd.print("set to set temp");
  set=digitalRead(sets);
  riscaldamento=0;
  digitalWrite (caldo,LOW);
  digitalWrite (ledCaldo,LOW);
  raffreddamento=0;
  digitalWrite (freddo,LOW);
  digitalWrite (ledFreddo,LOW);
  if (temp<Tmin){
    riscaldamento=1;
    lcd.clear();
  }
  if (temp>Tmax){
    raffreddamento=1;
    lcd.clear();
  }
  if(set!=set1){
    if(set){
      setting=1;
      lcd.clear();
      tempset=temp;
      inizioSet=millis();
    }
    set1=set;
  }
  while(riscaldamento==1 && temp<tempset){
    digitalWrite(caldo,HIGH);
    lcd.home();
    lcd.print("riscaldando");
    lcd.setCursor(0,1);
    lcd.print("temp: ");
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  while(raffreddamento==1 && temp>tempset){
    digitalWrite(freddo,HIGH);
    lcd.home();
    lcd.print("raffreddando");
    lcd.setCursor(0,1);
    lcd.print("temp: ");
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  while(setting){
    set=digitalRead(sets);
    up=digitalRead(ups);
    down=digitalRead(downs);
    lcd.home();
    lcd.print("set temp: ");
    lcd.print(tempset);
    if(set!=set1){
      if(set){
        setting=0;
        lcd.clear();
        Tmax=tempset+range;
        Tmin=tempset-range;
      }
      set1=set;
    }
    if(up!=up1){
      if(up){
        tempset++;
        inizioSet=millis();
      }
      up1=up;
    }
    if(down!=down1){
      if(down){
        tempset--;
        inizioSet=millis();
      }
      down1=down;
    }
    if(millis()-inizioSet>tempoSettaggio){
      setting=0;
      lcd.clear();
      lcd.print("time is up");
      Tmax=tempset+range;
      Tmin=tempset-range;
    }
  }
}

Se vi servono altre informazioni per capire il problema fatemelo sapere per favore. Ci tengo a precisare che non uso una scheda Arduino Uno ma prodotta da “keystudio” (l’ho comprata come compatibile). Potrebbe essere un problema della scheda o ci sono errori nel codice?

Non è che va in tilt, è che dentro al while esegui migliaia di volte al secondo le istruzioni:

    lcd.home();
    lcd.print("set temp: ");
    lcd.print(tempset);

e lo schermo non può stare appresso a questo refresh così rapido.
Devi mostrare il valore solo quando cambia, magari impostando una funzione apposita che chiami quando occorre, ad esempio:

...
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  if (setting) {
    showTemp();
    while(setting){
      set=digitalRead(sets);
      up=digitalRead(ups);
      down=digitalRead(downs);
      if(set!=set1){
        if(set){
          setting=0;
          lcd.clear();
          Tmax=tempset+range;
          Tmin=tempset-range;
          break;
        }
        set1=set;
      }
      if(up!=up1){
        if(up){
          tempset++;
          showTemp();
          inizioSet=millis();
        }
        up1=up;
      }
      if(down!=down1){
        if(down){
          tempset--;
          showTemp();
          inizioSet=millis();
        }
        down1=down;
      }
      if(millis()-inizioSet>tempoSettaggio){
        setting=0;
        lcd.clear();
        lcd.print("time is up");
        Tmax=tempset+range;
        Tmin=tempset-range;
        break;
      }
    }
  }
}

void showTemp() {
  lcd.clear();
  lcd.print("set temp: ");
  lcd.print(tempset);
}

ciao doc, grazie per il consiglio, però sul display compaiono caratteri davvero strani (una volta ho visto il pi greco :confused: ), quindi non credo sia dovuto a quello, mi sembra proprio che “impazzisca”. è possibile che è un problema della scheda?

Nel codice non vedo nulla che possa fare cose del genere, ma io non ho mai "stressato" così tanto l'LCD :wink:
Inoltre vedo che usi una connessione diretta dell'LCD, per cui magari è anche un problema di cablaggi non saprei dirti. In ogni caso non lo "stressare" inutilmente, prova il codice che ti ho modificato (ma mettici anche un "delay(100)" dentro ognuna delle if() per fare un minimo di debounce) e dimmi se in quel modo vedo lo stesso caratteri "strani" (nel caso, fai una foto dello schermo e postala qui come allegato).

PS ti consiglio per il futuro di prendere sempre LCD con interfaccia I2C, usi solo 2 pin e non tutti quelli, e ci puoi comunque collegare vari device I2C sugli stessi pin! Puoi anche acquistare la sola interfaccia ed applicarla al tuo LCD se hai pratica col saldatore, altrimenti prenditene uno già pronto, che è la cosa migliore.
Tra l'altro se nonti serve liberare comunque i pin, esistono anche shield come QUESTA che integrano display e ben 6 pulsanti!...

Va bene, allora appena possibile farò le correzioni che mi hai consigliato e farò sapere l'esito. Si, già sono a conoscenza dell'interfaccia I2C, ma essendo agli inizi voglio prima capire almeno a grandi linee come funzionano i singoli i componenti prima di usare la "pappa già pronta". Comunque grazie mille per il consiglio, sicuramente provvederò ad acquistarne una. Mi sono dimenticato di dire che ho fatto il circuito anche su tinkercad per capire se era un problema del circuito pratico o di codice e lì funziona perfettamente. Grazie e buona serata.

docdoc:
Non è che va in tilt, è che dentro al while esegui migliaia di volte al secondo le istruzioni:

    lcd.home();

lcd.print("set temp: ");
    lcd.print(tempset);



e lo schermo non può stare appresso a questo refresh così rapido. 
Devi mostrare il valore solo quando cambia, magari impostando una funzione apposita che chiami quando occorre, ad esempio:



...
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  if (setting) {
    showTemp();
    while(setting){
      set=digitalRead(sets);
      up=digitalRead(ups);
      down=digitalRead(downs);
      if(set!=set1){
        if(set){
          setting=0;
          lcd.clear();
          Tmax=tempset+range;
          Tmin=tempset-range;
          break;
        }
        set1=set;
      }
      if(up!=up1){
        if(up){
          tempset++;
          showTemp();
          inizioSet=millis();
        }
        up1=up;
      }
      if(down!=down1){
        if(down){
          tempset--;
          showTemp();
          inizioSet=millis();
        }
        down1=down;
      }
      if(millis()-inizioSet>tempoSettaggio){
        setting=0;
        lcd.clear();
        lcd.print("time is up");
        Tmax=tempset+range;
        Tmin=tempset-range;
        break;
      }
    }
  }
}

void showTemp() {
  lcd.clear();
  lcd.print("set temp: ");
  lcd.print(tempset);
}

Buonasera (doc), ho provato ad apportare la modifica che mi hai suggerito ma non cambia nulla, forse è un problema di cablaggio, nei prossimi giorni provo a rivedere il tutto e vi faccio sapere.

Cintala, non è necessario riportare tutto il testo precedente per rispondere con due righe! Cerchiamo di mantenere pulita la discussione, senza inutili ripetizioni. Una persona che legge la discussione prima si scorre tutto il testo ripetuto, poi legge "ho apportato la modifica che mi hai suggerito" e si rende conto di aver riletto inutilmente tutto lo stesso programma che aveva letto all'inizio! :slight_smile:

Si ma puoi/dovresti prima cercare di capire cosa “si impalla”, per vedere se si blocca del tutto Arduino o se invece semplicemente è in uno stato per cui non risponde.

Ad esempio oltre a fare quella modifica (che fa scrivere sull’LCD solo quando serve, quindi applicala), aggiungi un po’ di righe per scrivere sulla seriale cosa succede ossia cosa riceve e cosa fa. Insomma, il “classico debug di Arduino”… :wink:

Questo perché tu lì dentro hai svariati cicli “while” e basta che uno di questi non soddisfi più le condizioni di uscita ed ecco che ti si “impalla” tutto perché non fa altro che quello che sta scritto lì dentro.
Metti una Serial.println prima di ognuno di quei while per scrivere sulla seriale quale while sta per eseguire: se vedi il monitor seriale quando “si impalla” dovresti trovare qual è la while() dalla quale non esce più.
Ad esempio:

#include <LiquidCrystal.h>

LiquidCrystal lcd (10,9,5,6,7,8);

//variabili da settare
const int tempoSettaggio=5000;
const int range=1;
//variabili
int sens;
float temp;
byte tempset=25;
//temperatura range
byte Tmax=tempset+range;
byte Tmin=tempset-range;
//pulsanti
const int sets=13;
bool set=0;
bool set1=0;
const int ups=11;
bool up=0;
bool up1=0;
const int downs=12;
bool down=0;
bool down1=0;
//variabili di stato
bool setting=0;
bool riscaldamento=0;
bool raffreddamento=0;
//variabili-cronometro
unsigned long inizioSet;
//pin transistor
const int caldo=3;
const int freddo=4;
const int ledCaldo=1;
const int ledFreddo=2;

void setup(){
  Serial.begin(9600);
  Serial.println("setup");
  lcd.begin(16,2);
  pinMode(sets, INPUT);
  pinMode(ups, INPUT);
  pinMode(downs, INPUT);
  pinMode(caldo, OUTPUT);
  pinMode(freddo, OUTPUT);
  pinMode(ledCaldo, OUTPUT);
  pinMode(ledFreddo, OUTPUT);
  lcd.clear();
}

void loop(){
  sens=analogRead(A0);
  temp=sens*0.48828125;
  lcd.home();
  lcd.print("temp:");
  lcd.print(temp);
  lcd.setCursor(0,1);
  lcd.print("set to set temp");
  set=digitalRead(sets);
  riscaldamento=0;
  digitalWrite (caldo,LOW);
  digitalWrite (ledCaldo,LOW);
  raffreddamento=0;
  digitalWrite (freddo,LOW);
  digitalWrite (ledFreddo,LOW);
  if (temp<Tmin){
    riscaldamento=1;
    lcd.clear();
  }
  if (temp>Tmax){
    raffreddamento=1;
    lcd.clear();
  }
  if(set!=set1){
    if(set){
      setting=1;
      lcd.clear();
      tempset=temp;
      inizioSet=millis();
    }
    set1=set;
  }
  Serial.println("primo while");
  while(riscaldamento==1 && temp<tempset){
    digitalWrite(caldo,HIGH);
    lcd.home();
    lcd.print("riscaldando");
    lcd.setCursor(0,1);
    lcd.print("temp: ");
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  Serial.println("secondo while");
  while(raffreddamento==1 && temp>tempset){
    digitalWrite(freddo,HIGH);
    lcd.home();
    lcd.print("raffreddando");
    lcd.setCursor(0,1);
    lcd.print("temp: ");
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
    lcd.print(temp);
    sens=analogRead(A0);
    temp=sens*0.48828125;
  }
  Serial.println("settings");
  if (setting) {
    showTemp();
    Serial.println("while setting");
    while(setting){
      set=digitalRead(sets);
      up=digitalRead(ups);
      down=digitalRead(downs);
      if(set!=set1){
        if(set){
          setting=0;
          lcd.clear();
          Tmax=tempset+range;
          Tmin=tempset-range;
          break;
        }
        set1=set;
      }
      if(up!=up1){
        if(up){
          tempset++;
          showTemp();
          inizioSet=millis();
        }
        up1=up;
      }
      if(down!=down1){
        if(down){
          tempset--;
          showTemp();
          inizioSet=millis();
        }
        down1=down;
      }
      if(millis()-inizioSet>tempoSettaggio){
        setting=0;
        lcd.clear();
        lcd.print("time is up");
        Tmax=tempset+range;
        Tmin=tempset-range;
        break;
      }
    }
  }
}

void showTemp() {
  lcd.clear();
  lcd.print("set temp: ");
  lcd.print(tempset);
  Serial.print("tempset="); Serial.println(tempset);
}

Prova e facci sapere.

PS e comunque il tutto andrebbe gestito diversamente, con una cosiddetta “macchina a stati finiti” ma significa rivedere tutto il codice.

Mah... Quando faccio delle impostazioni con un encoder, faccio sempre un ciclo strettissimo (while che esce premendo il pulsante) in cui visualizzo continuamente il valore, che varia appena ruoto l'encoder, e non ho mai avuto problemi. Certamente, però, è inutile riscrivere continuamente
lcd.print("set temp: ");

>cintala_: REGOLAMENTO, punto 16.12 ... ho provveduto a bannare l'utente "cintala" e ti prego di NON creare più account duplicati. Grazie.

Guglielmo

Daniele, ti regalo il primo Karma per la correttezza, la precisione e la comprensibilità di ciò che scrivi.
Grazie! :slight_smile: