Scrittura su LCD 20x4

Buongiorno a tutti,

sono 2 giorni che sto cercando un errore, ma proprio non sono riuscito a trovarlo. La parte del programma incriminato è questa:

  if (HC12.available() ) {

    X  = HC12.readString();//read string

    Serial.println(X);

    int value = X.toInt();

    ctr_btt = (value / 10000);
    t = (((value - (ctr_btt * 10000)) / 100) - 49);
    h = (((value - (ctr_btt * 10000)) - ((t + 49) * 100)) / 1);

    // Controlla temperatura max/min
    if (t > t_max) {
      t_max = t;
      EEPROM.write(1, t_max);
      delay (200);
    }
    if (t_min > t) {
      t_min = t;
      Serial.println("cambio EEPROM");
      EEPROM.write(2, t_min);
    }
    Serial.print("2 controllo t_min: ");
    Serial.println(t_min);


    // trasformo l'ora in char per controllare l0ultima trasmissione
    sprintf_P(OraString, PSTR("%02d:%02d"), (hour()), (minute()));
    lcd.setCursor(0, 3);  // Set the cursor to col 0, row 3
    lcd.print(OraString);
    Serial.println(OraString);


   
    lcd.setCursor(0, 1);  // Set the cursor to col 0, row 1
    if (t < 10) {
      lcd.print ("Temp.: " + String(t) + char(0xDF) + "- Umid.:" + String(h) + "%");
    } else {
      lcd.print ("Temp.:" + String(t) + char(0xDF) + "- Umid.:" + String(h) + "%");
    }

    lcd.setCursor(2, 2);  // Set the cursor to col 2, row 2
    if (ctr_btt < 2) {
      lcd.print("Oggi - max.: " + String(t_max) + " " + char(0xDF) + "C ");

      lcd.setCursor(9, 3);  // Set the cursor to col 5, row 3
      lcd.print("min.: " + String(t_min) + " " + char(0xDF) + "C " );
    } 

    t_min = EEPROM.read(2);
    Serial.print("3 controllo t_min: ");
    Serial.println(t_min);
  }

in pratica ricevo, via HC12, su auduino genuino UNO una stringa di 5 cifre che splitto per recuperare i valori di temperatura ed umidità da trasferire su LCD.

Funziona tutto con l’eccezione del valore t_min che, pur essendo corretto su EEPROM e sulla seriale di controllo, su LCD viene visualizzato come .

Qualcuno mi può indicare dove sbaglio?

Saluti - Enrico

Non usare la classe String: scrivi solo una volta le parti di testo fisse e poi inserisci i valori numerici.
N.B.: su EEPROM non puoi scrivere impunemente valori negativi! :slight_smile:

Inoltre, l'aggiornamento del display va effettuato non più di due (o tre) volte al secondo: di più è inutile e appesantisce e rallenta inutilmente il ciclo.

D'accordo; sto cercando da tempi di eliminare la classe String, non ci sono ancora riuscito, ma … ci lavoro.

Per quanto riguarda l'aggiornamento dello LCD viene fatto ogni 8 minuti ca,, unica eccezione la data/ora.

Grazie per l'informazione sulla EEPROM, non lo sapevo! Aggiungerò anche in questo caso 50 per evitare valori negativi.

Non mi spiego, comunque, il perché la variabile t_min non venga visualizzata in modo corretto su LCD!

Grazie comunque + un felice inizio anno.

Enrico

Non è che t_min è unsigned? :slight_smile:

 Una sola volta scrivi :
lcd.setCursor(0,1); lcd.print("Temp.:   °C   Umid.:
  %");

e poi ciclicamente:
lcd.setCursor(7,1); lcd.print(t);
lcd.setCursor(18,1); lcd.print(h); 

Naturalmente, se un valore può essere di due
o tre cifre, qualora sia di due devi precederlo
con un lcd.print(' ');

Per risparmiare RAM, poi, puoi usare la macro F().

Auguri anche a te e a tutti di un sereno e gioioso tempo di Natale e un buon anno nuovo!

t_min, così come t_max è un int.

int t_max;
int t_min;
int t;
int h;

La cosa strana è che con serial.print il valore di t_min mi esce corretto!

Enrico

L’errore si verifica tra òa riga 135 e la riga 187 (range tra gli ====/ controllo 2 e controllo 4):

  if (HC12.available() ) {

    X  = HC12.readString();//read string

    Serial.println(X);

    int value = X.toInt();

    ctr_btt = (value / 10000);
    t = (((value - (ctr_btt * 10000)) / 100) - 49);
    h = (((value - (ctr_btt * 10000)) - ((t + 49) * 100)) / 1);

    // Controlla temperatura max/min
    if (t > t_max) {
      t_max = t;
      EEPROM.write(1, t_max);
      delay (200);
    }
    if (t_min > t) {
      t_min = t;
      Serial.println("cambio EEPROM");
      EEPROM.write(2, t_min);
    }
//=======================================================
    Serial.print("2 controllo t_min: ");
    Serial.println(t_min);

    // trasformo l'ora in char per controllare l0ultima trasmissione
    sprintf_P(OraString, PSTR("%02d:%02d"), (hour()), (minute()));
    lcd.setCursor(0, 3);  // Set the cursor to col 0, row 3
    lcd.print(OraString);
    Serial.println(OraString);

    // controllo se devo registrare su SD
    if (SD_OK == 1) {
      ctrwrite();
    }

    // scrivo la temperatura
    if (t < 10) {
      lcd.setCursor(7, 1);  // Set the cursor to col 0, row 7
    } else {
      lcd.setCursor(6, 1);  // Set the cursor to col 0, row 6
    }
    lcd.print (t);

    // scrivo l'umidità
    lcd.setCursor(17, 1);  // Set the cursor to col 0, row 17
    lcd.print (h);

    // scrivo la temperatura max e min odierna o l'avviso di cambio batteria
    lcd.setCursor(2, 2);  // Set the cursor to col 2, row 2
    if (ctr_btt < 2) {
      lcd.print F("Oggi - max.: ");
      delay (50);
      lcd.setCursor(16, 2);  // Set the cursor to col 16, row 2
      lcd.print (t_max);
      delay (50);
      lcd.setCursor(18, 2);  // Set the cursor to col 18, row 2
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 2);  // Set the cursor to col 19, row 2
      lcd.print F("C");
      delay (50);
      lcd.setCursor(9, 3);  // Set the cursor to col 9, row 3
      lcd.print("min.: " );
      delay (50);
      lcd.setCursor(16, 3);  // Set the cursor to col 16, row 3
      lcd.print (t_min);
      delay (50);
      lcd.setCursor(18, 3);  // Set the cursor to col 18, row 3
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 3);  // Set the cursor to col 19, row 3
      lcd.print F("C");
      delay (50);
Serial.print("4 controllo t_min: ");
    Serial.println(t_min);
//================================================================      
    } else {
      lcd.print(F(" ATTENZIONE: Livello") );
      lcd.setCursor(0, 3);
      lcd.print(F("batteria < a 5 volt " ));
    }
    t_min = EEPROM.read(2);
    Serial.print("3 controllo t_min: ");
    Serial.println(t_min);
  }

Cosa può esserer successo?

Saluti

// lcd.print F("C"); // sbagliato
lcd.print (F("C")); // corretto

Ciao.

e questo implica che l'ultima versione non compila e quindi siamo fermi alla versione precedente
OK, se lo OP mette tutto il programma io ho un'idea della causa, ma devo verificarla,

non parlo a region non veduta

Tutti quei delay(50), poi, a che servono?...

x Datman: li ho messi x dare il tempo di scrivere/leggere al programma (ero alla disperazione!!) con l’idea di eliminarli a poco a poco eliminato l’errore,
Ecco l’ultima versione:

/*
   Versione da provare
*/

#include <EEPROM.h>
#include <DS3232RTC.h> //http://github.com/JChristensen/DS3232RTC
#include <Time.h>      //http://www.arduino.cc/playground/Code/Time  
#include <Wire.h>      //http://arduino.cc/en/Reference/Wire
#include <TimeLib.h>

// SD
#include <SD.h>
#include <SPI.h>

//HC-12
#include <VirtualWire.h>
#include <SoftwareSerial.h>

// Creazione oggetto SD
File file;

// Crea il collegamento HC-12
SoftwareSerial HC12(3, 2); // RX, TX

#include <PCF8574_HD44780_I2C.h>

// Address 0x27, 20 chars, 4 line display
PCF8574_HD44780_I2C lcd(0x27, 20, 4);

// Definizioni variabili
String X ;
int t_max;
int t_min;
int t;
int h;
int t_max_old;
int t_min_old;
int oldmyday;
char c_newday[3];
char c_month[3];
char c_year[5];
char c_day[3];
char c_hour[3];
char c_minute[3];
char c_second[3];
char DataOraString[20];
char OraString[5];
int ctr_btt;
int ctr_day;

#define countof(a) (sizeof(a) / sizeof(a[0]))

void setup(void)
{
  HC12.begin(9600);
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC

  lcd.init();           // LCD Initialization
  lcd.backlight();      // Backlight ON

  Serial.println (F("** Basato su RX_Prova_19 - Arduino UNO **"));

  // leggo un valore sulla EEPROM
  t_max_old = (EEPROM.read(1) - 50);
  delay(500);
  t_min_old = (EEPROM.read(2)- 50);
  delay(500);

  // Imposta la comunicazione SD
  if (!SD.begin(10)) {
    Serial.println("Errore SD");
  }
  
  lcd.clear();
  t_max = (EEPROM.read(1) - 50);
  delay (200);
  t_min = (EEPROM.read(2) - 50);
  delay (200);

  // preparo la maschera per i valori di temp e umidità su LCD
  lcd.setCursor(1, 1);  // Set the cursor to col 0, row 1
  lcd.print (F("Temp:"));
  lcd.setCursor(8, 1);  // Set the cursor to col 8, row 1
  lcd.print (char(0xDF));
  lcd.setCursor(9, 1);
  lcd.print (F("C Umid:"));
  lcd.setCursor(19, 1);  // Set the cursor to col 19, row 1
  lcd.print (F("%"));
}

void loop(void)
{
  // Controlla la presenza della SD
  int SD_OK;
  if (!SD.begin(10)) {
    Serial.println("SD non presente");
    SD_OK = 0;
  } else {
    SD_OK = 1;
  }

  // imposta la comunicazione HC-12
  if (HC12.available() ) {

    X  = HC12.readString();//read string

    Serial.println(X);

    int value = X.toInt();

    ctr_btt = (value / 10000);
    t = (((value - (ctr_btt * 10000)) / 100) - 49);
    h = (((value - (ctr_btt * 10000)) - ((t + 49) * 100)) / 1);

    // Controlla temperatura max/min
    if (t >= t_max) {
      t_max = t;
      EEPROM.write(1, (t_max + 50));
      delay (200);
    }
    if (t_min >= t) {
      t_min = t;
      Serial.println (F("cambio EEPROM"));
      EEPROM.write(2, (t_min + 50));
    }

    // scrivo la temperatura
    if (t < 10) {
      lcd.setCursor(7, 1);  // Set the cursor to col 0, row 7
    } else {
      lcd.setCursor(6, 1);  // Set the cursor to col 0, row 6
    }
    lcd.print (t);

    // scrivo l'umidità
    lcd.setCursor(17, 1);  // Set the cursor to col 0, row 17
    lcd.print (h);

    // scrivo la temperatura max e min odierna o l'avviso di cambio batteria
    lcd.setCursor(2, 2);  // Set the cursor to col 2, row 2
    if (ctr_btt < 2) {
      lcd.print (F("Oggi - max.: "));
      delay (50);
      lcd.setCursor(16, 2);  // Set the cursor to col 16, row 2
      lcd.print (t_max);
      delay (50);
      lcd.setCursor(18, 2);  // Set the cursor to col 18, row 2
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 2);  // Set the cursor to col 19, row 2
      lcd.print (F("C"));
      delay (50);
      lcd.setCursor(9, 3);  // Set the cursor to col 9, row 3
      lcd.print("min.: " );
      delay (50);
      lcd.setCursor(16, 3);  // Set the cursor to col 16, row 3
      lcd.print (t_min);
      delay (50);
      lcd.setCursor(18, 3);  // Set the cursor to col 18, row 3
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 3);  // Set the cursor to col 19, row 3
      lcd.print (F("C"));
      delay (50);
      Serial.print("4 controllo t_min: ");
      Serial.println(t_min);
    } else {
      lcd.print(F(" ATTENZIONE: Livello") );
      lcd.setCursor(0, 3);
      lcd.print(F("batteria < a 5 volt " ));
    }

    // trasformo l'ora in char per controllare l0ultima trasmissione
    sprintf_P(OraString, PSTR("%02d:%02d"), (hour()), (minute()));
    lcd.setCursor(0, 3);  // Set the cursor to col 0, row 3
    lcd.print(OraString);

    // controllo se devo registrare su SD
    if (SD_OK == 1) {
      ctrwrite();
    }
  }

  // trasformo la data/ora in char
  sprintf_P(DataOraString, PSTR("%02d/%02d/%4d %02d:%02d:%02d"), (day()), (month()), (year()), (hour()), (minute()), (second()));
  
  // Scrivo la data/ora su LCD
  lcd.setCursor(0, 0);
  lcd.print(DataOraString);
  
  delay (1000);
}

void ctrwrite() {
  oldmyday = EEPROM.read(0);
  if (day() != oldmyday) {
    writeSD();
    EEPROM.write(0, day());
    delay (10);
  }
}

void writeSD()
{
  Serial.println("Apro SD");

  // controllo se il file esiste
  if (SD.exists("Valori.txt"))
  {
    file = SD.open("Valori.txt", FILE_WRITE);
  } else {
    // lo creo e inserisco la testata
    file = SD.open("Valori.txt", FILE_WRITE);
    file.write("Data");
    file.write("/");
    file.write("temp. max");
    file.write("/");
    file.write("temp. min");
    file.write("\n" ); // vado a capo per dati
  }
  delay (100);
  int newday  = (day() - 1);

  // trasformo i vali della data in char
  char DataString[11];
  sprintf_P(DataString, PSTR("%02d.%02d.%4d"), (newday), (month()), (year()));

  // scrivo la data
  file.write(DataString);
  file.write("/");
  delay (100);

  // scrivo la temperatura max registrata
  char newt_max[3];
  snprintf_P( newt_max,
              countof(newt_max),
              PSTR("%02u"),
              (t_max));
  file.write(newt_max);
  file.write("/");
  delay (100);

  // scrivo la temperatura min registrata
  char newt_min[3];
  snprintf_P( newt_min,
              countof(newt_min),
              PSTR("%02u"),
              (t_min));
  file.write(newt_min);
  file.write("/");
  delay (100);

  // vado a capo per altri dati
  file.write("\n" );
  delay (100);
  file.close();
  Serial.println("chiudo SD");

  // aggiungo 50 °C per evitare negativi e inserisco i valori sulla EEPROM
  EEPROM.write(1, (t_max + 50));
  delay (100);
  EEPROM.write(2, (t_min + 50));
  delay (100);

  // ripato con le temperatura max/min
  t_max = t;
  t_min = t;
}

è ancora da “pulire”. Penso inoltre di eliminare scritture/letture ridondanti su EEPROM e di suddividere ulteriormente il loop.

x Maurotec/Standardoil → aggiunto le parentesi, comunque anche prima compilava senza dare errori!

Saluti

Enrico

x Maurotec/Standardoil --> aggiunto le parentesi, comunque anche prima compilava senza dare errori!

Per noi "errore" significa che il compilatore ha trovato un errore e infatti avrebbe dovuto dare errore.

L'errore si verifica tra òa riga 135 e la riga 187 (range tra gli ====/ controllo 2 e controllo 4):

Non da errore perché la macro 'F' include () nella espansione. Ma ciò io non potevo ricordarlo.

Io qui di seguito non trovo errori nel codice:

lcd.setCursor(16, 3);  // Set the cursor to col 16, row 3
      lcd.print (t_min);
      delay (50);
      lcd.setCursor(18, 3);  // Set the cursor to col 18, row 3
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 3);  // Set the cursor to col 19, row 3
      lcd.print (F("C"));
      delay (50);
      Serial.print("4 controllo t_min: ");
      Serial.println(t_min);

Se questa:

Serial.println(t_min);

stampa -5
anche questa deve stamparti lo stesso valore:

lcd.print (t_min);

Prova ad eliminare ciò che segue, cioè:

#if (0)      
      lcd.setCursor(18, 3);  // Set the cursor to col 18, row 3
      lcd.print (char(0xDF));
      delay (50);
      lcd.setCursor(19, 3);  // Set the cursor to col 19, row 3
      lcd.print (F("C"));
      delay (50);
 #endif

Ciao.

quindi tu pensi che venga sovrascritto da "°C"
puo' essere, ma perché non lo fa alla t_max....
comunque nemmeno io trovo errori nel programma, non capisco proprio
prima sospettavo una stringa non terminata che sbordasse, ma visto il programma non è così

Per togliersi qualche dubbio basterebbe stampare una sola volta la maschera e poi solo i valori, come ho suggerito ieri sera.

Pazzesco, è bastato togliere queste righe:

/*    // trasformo l'ora in char per controllare l0ultima trasmissione
    sprintf_P(OraString, PSTR("%02d:%02d"), (hour()), (minute()));
    lcd.setCursor(0, 3);  // Set the cursor to col 0, row 3
    lcd.print(OraString);
*/
    // controllo se devo registrare su SD

e tutto è andato a posto!!

Qualcuno sa spiegarmi il perché?

x Datman: non posso stampare nel setup l'intera maschera in quanto potrei dover variare (con if) le righe 2 e 3. Inoltre lo LCD non riesce a stampare il carattere ° ma devo inserirlo con char(0xDF).

Ancora un augurio a tutti di un felice e sereno 2020.

Enrico

ricontrolla la dimensione dell'array di char OraString, potresti aver sbagliato il conto e risulta corto, ma non mi spiego ancora tutto......

Dovrebbe essere di 7 ed occupare 5 caselle dell'LCD, in ogni caso coprirebbe la scritta "min." e non dovrebbe coinvolgere la variabile che è in posizione 16,3.

Enrico

beh, io ti ho detto di ricontrollare la dimensione, ma non lo hai fatto:
tu alla riga 48 del tuo programma lo hai dichiarato char OraStringa[5]
siccome poi ci scrivi due cifre, un duepunti e altre due cifre la lunghezza minima da considerare è 6 (e il perchè te lo vai a cercare)
e quindi quando vai a toccare quell'array fai danni in memoria
nei mesi passati hai già fatto danni del genere, forse sarebbe il caso di mettersi a studiare

Grazie, nella definizione non avevo considerato i 2 punti!! certo che ci vuole un terminatore di array!! accidenti!

Ora provo a reinserire le righe e correggere l’array!

saluti

grazie per il Karma che mi sono meritato........