Multitasking Arduino utilizzo di millis - Aiuto

Buona sera a tutti,
Sto cercando di sviluppare un progetto che dovrebbe:

  • Rilevare temperatura ed umidità da alcuni sensori Dht11;
  • Visualizzare i dati rilevati su un LCD;
  • Salvare i dati rilevati Online - Tramite invio dei dati con board Enc28j60

Inizialmente ho realizzato due sketch di prova, uno per la visualizzazione ed uno per il salvataggio.
Dopo ho unito i due sketch rendendomi conto che non funziona come dovrebbe... Non veniva inviato nessun dato.
Ho pensato che il problema fosse dovuto al fatto che utilizzavo la funzione [delay per la parte che riguarda la visualizzazione] e [millis per il salvataggio], perciò ho tentato di capire come utilizzare millis, ma probabilmente invano visto che i dati vengono inviati solo una volta ogni tanto :~ :~

Ecco quì di seguito lo sketch che ho creato, sapreste aitarmi per risolvere il problema?
Ho provato in tantissimi modi, ma non sono stato capace di risolvere il problema :roll_eyes:

#include <EtherCard.h>
#include "DHT.h"

// LCD
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

#define DHTPIN0 6     // what pin we're connected to
#define DHTPIN1 5     // what pin we're connected to
#define DHTPIN2 4     // what pin we're connected to
#define DHTPIN3 3     // what pin we're connected to
#define DHTPIN4 2     // what pin we're connected to
#define DHTPIN5 7     // what pin we're connected to
#define DHTPIN6 8     // what pin we're connected to

#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT11   // DHT 11 

DHT dht0(DHTPIN0, DHTTYPE);
DHT dht1(DHTPIN1, DHTTYPE);
DHT dht2(DHTPIN2, DHTTYPE);
DHT dht3(DHTPIN3, DHTTYPE);
DHT dht4(DHTPIN4, DHTTYPE);
DHT dht5(DHTPIN5, DHTTYPE);
DHT dht6(DHTPIN6, DHTTYPE);
// --------------------------------------------------

// ENC28J60
static byte mac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte ip[] = {192,168,1,7};
byte Ethernet::buffer[700];

#define ENC28J60_CS 10
 
char website[] PROGMEM= "www.fabbricaopensource.altervista.org"; // www.TUO_SITO_WEB.it 
char buffer[70];

unsigned long time_last = 0; 
boolean flag;
byte interval = 5; // seconds - intervello di tempo tra un invio di dati ed il successivo verso il server

static void response_callback (byte status, word off, word len){
Serial.println();
Serial.println( (char *) Ethernet::buffer + off);
Serial.println();
}

void setup (){
  Serial.begin(9600);
  // SENSORS
  dht0.begin();
  dht1.begin();
  dht2.begin();
  dht3.begin();
  dht4.begin();
  dht5.begin();
  dht6.begin();
//-------------------------------------------------------------------
// ENC28J60
Serial.print("Verifica Enc28j60 ... ");
if ( ether.begin( sizeof Ethernet::buffer, mac, ENC28J60_CS) ){
  Serial.println("\tsuccess");
}
else{
  Serial.println("\tfailed"); 
}
Serial.print("Setting IP ... ");
 
if ( ether.dhcpSetup() ) {
Serial.println("\t\tsuccess"); 
}
else{
if ( ether.staticSetup(ip) ){
  Serial.println("\t\tsuccess");
}
 
else{
  Serial.println("\t\tfailed");
}
}
Serial.print("Verifica sito web ... ");
 
if (ether.dnsLookup( website )){
  Serial.println("\tsuccess");
}
 
else{
  Serial.println("\tfailed");
}
 
 
Serial.println();
Serial.print("Setup eseguito in :");
Serial.print(millis()/1000);
Serial.println("s");
Serial.println();
Serial.println();
}
 
void loop(){
  //SENSORS
  // data read:
  float t0 = dht0.readTemperature();
  float t1 = dht1.readTemperature();
  float t2 = dht2.readTemperature();
  float t3 = dht3.readTemperature();
  float t4 = dht4.readTemperature();
  float t5 = dht5.readTemperature();
  float t6 = dht6.readTemperature();

  float h0 = dht0.readHumidity();
  float h1 = dht1.readHumidity();
  float h2 = dht2.readHumidity();
  float h3 = dht3.readHumidity();
  float h4 = dht4.readHumidity();
  float h5 = dht5.readHumidity();
  float h6 = dht6.readHumidity();
  // --------------------------------------------------------------
 // --------------------------------------------------------------
ether.packetLoop(ether.packetReceive());
 //if (millis()/1000 > time_last){
   if ( (time_last = millis()/1000) % interval == 0 ){
   flag = true;
 }
//}
if (flag) {
  flag = false;
  //float temperature = dht.readTemperature();
  char s_t1[5]; // 5 caratteri (5 char) perché il nostro numero decimale (float) è formato da: [ un intero a due cifre, un punto, un decimale, ed in fine si aggiungerà il terminatore di stringa (cioè \0) ]
  dtostrf(t0, 4, 1, s_t1);
 
  //float humidity = dht.readHumidity();
  char s_h1[5]; // 5 caratteri (5 char) perché il nostro numero decimale (float) è formato da: [ un intero a due cifre, un punto, un decimale, ed in fine si aggiungerà il terminatore di stringa (cioè \0) ]
  dtostrf(h0, 4, 1, s_h1);
 
  sprintf(buffer, "t1=%s&u1=%s", s_t1, s_h1);
  // Serial.print("sensor[]=temperature&value[]=%s&sensor[]=humidity&value[]=%s");
  ether.browseUrl(PSTR("/work/pag/save.php?"), buffer, website, response_callback);
  Serial.print(t0); 
 }
  if (t0 != '0'){
// 1
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 1:");
  lcd.setCursor(3, 1);
  lcd.print(t0, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h0, 0);
  lcd.print(" %");
 delay(1000);
}

if (t1 != '0'){
// 2
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 2:");
  lcd.setCursor(3, 1);
  lcd.print(t1, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h1, 0);
  lcd.print("%");
 delay(1000);
}
if (h2 != '0.00'){
// 3
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 3:");
  lcd.setCursor(3, 1);
  lcd.print(t2, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h2, 0);
  lcd.print("%");
 delay(1000); 
}/*
if (t3 != 'nan'){
// 4
    lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 4:");
  lcd.setCursor(3, 1);
  lcd.print(t3, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h3, 0);
  lcd.print("%");
 delay(1000);
}

if (t4 > '0'){
// 5
    lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 5:");
  lcd.setCursor(3, 1);
  lcd.print(t4, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h4, 0);
  lcd.print("%");
 delay(1000);
}

if (t5 > '0'){
// 6
    lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 6:");
  lcd.setCursor(3, 1);
  lcd.print(t5, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h5, 0);
  lcd.print("%");
 delay(1000);
}
if (t6 > '0'){
// 7
    lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Sensore 7:");
  lcd.setCursor(3, 1);
  lcd.print(t6, 0);
  lcd.print(" C");
  lcd.print((char)223);
  lcd.print(" ");
    lcd.print(h6, 0);
  lcd.print("%");
 delay(1000);
}
*/
  
}

Vi ringrazio in anticipo per l'aiuto che potrete darmi.
A presto,
Ivan.

Secondo me il problema è qui:

if ( (time_last = millis()/1000) % interval == 0 ){
   flag = true;
 }

millis()/1000 è la divisione di un unsigned long con un int, quindi il risultato potrebbe essere un float, tuttavia il problema credo sia il calcolo del resto. Cioè il % interval. ho visto che hai definito

byte interval = 5; // seconds - intervello di tempo tra un invio di dati ed il successivo verso il server

interval come byte. Non sono sicuro che l'espressione venga interpretata correttamente.

Se fai una divisione fra interi il risultato sarà sempre un intero, il compilatore tronca eventuali decimali. Inoltre se ci fossero decimali, il modulo non andrebbe bene perché il modulo opera solo su interi.
Casomai il problema potrebbe essere nel test usato, l'uguaglianza. Solo e solo se hai il giusto valore di millis il test è vero, quindi puoi saltarti dei risultati. Con i tempi non si usa mai l'uguaglianza ma i confronti <= (minore o uguale) oppure >= (maggiore o uguale).

Ti do anche un link di un articolo per approfondire:
http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

Se poi necessiti di uno scheduler, ne ho scritto uno semplice basato proprio su millis, si chiama looper e lo trovi sempre sul mio sito.

leo72:
Ti do anche un link di un articolo per approfondire:
http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

Meglio ancora, http://www.leonardomiliani.com/2012/leos-1-0-3-e-leos-2-1-1/ :slight_smile:

Come detto, gli basterebbe il looper. Meglio non rischiare usando task molto complessi negli interrupt. Il looper fa dietro le quinte ciò che l'utente dovrebbe fare con uno o una serie di check sui millis trascorsi.

Grazie per la risposta!
ho scaricato looper e lo sto per provare, ma prima, prendendo uno spezzone dell' esempio:

//every 10 secs pause/restart the second task
    counter += direction;
    if (counter == 0) {
        myScheduler.pauseJob(flashLed1); //pause the task
        direction = 1;
    }
    if (counter == 10) {
        myScheduler.restartJob(flashLed1); //restart the task
        direction = -1;
    }
    myScheduler.scheduler();
}

Significa che ogni 10 secondi svolge un funzione per volta o le due insieme?
A presto,
Ivan

if ( (time_last = millis()/1000) % interval == 0 ){

Non sono un mago della informatica ma mi sembra strano usare un assegnazione all'interno della condizione di IF.

Per pimo viene calcolato
millis()/1000
poi
time_last = risultato di (millis()/1000) che come risultato dell assegnazione da 1
poi viene fatto
1% interval
che é sempre 1 perché la variabile interval sara maggiore di 1
e poi la condizione
1 ==0 é sempe 0

Mi sbaglio in questo?

Ciao Uwe

Sintatticamente si può combinare l'uso di un'assegnazione con un'operazione di confronto. Ci sono casi in cui può servire. In questo preciso esempio però pare che la cosa sia come hai detto tu.

Buona sera a tutti, vi ringrazio per avermi aiutato :slight_smile:
Dopo parecchie prove e dopo aver rivisto il mio progetto ho pensato che la soluzione migliore per me è quella di utilizzare un altro arduino collegato tramite seriale (Software Serial) in modo da dividere i compiti, uno per il salvataggio ed uno per la visualizzazione dei dati.

Adesso nasce un altro problema (per me): dividere una stringa che invio tramite seriale in variabili.
Ad esempio, se tramite seriale invio la stringa t1=10&t2=20&t3=22, bisognerà individuare le varibili che si vogliono In seguto visualizzare su LCD.

Tramite un semplice codice sono riuscito a dividere una stringa indicando il delimitatore:

#include <string.h>

char sz[] = "t1=10&t2=20&t3=22";
void setup()
{
 char *p = sz;
 char *str;
 Serial.begin(9600);  
 while ((str = strtok_r(p, "&", &p)) != NULL) // delimiter is the semicolon
 char* t1 = str;
   Serial.println(str);
}

void loop(){}

Come posso assegnare delle variabili ad ogni valore?
Naturalmente in seguito dovrò aggiungere dei simboli per indicare l'inizio della lettura e della fine tipo $t1=10&t2=20&t3=22%, giusto?

Grazie,
Ivan

IMHO invece di semplificartelo, il compito lo hai complicato :wink:
Adesso devi scrivere e mantenere 2 sketch differenti, oltre alle problematiche della comunicazione seriale.

A parte questo, se stai lavorando con oggetti String, non con stringhe di char del C, puoi usare 2 funzioni di String:
substring, con cui "affettare" la stringa, e indexOf, con cui sapere da che punto partire ogni volta a cercare il carattere separatore.

Grazie per la dritta :wink:
Credo di aver capito come fare, ma nonostante ciò trovo un piccolo problema nel funzionamento del codice...
Praticamente i dati ricevuti nel formato #0000#, t1 53, t2 20, t3 40, t4 20, t5 53, t6 30, t7 15, coefficiente 3.149, Led On li inserisco in un array, li trasformo in una stringa e controllo il contenuto del messeggio.
In base al contenuto scelgo di eseguire certe operazioni.
Il mio problema è: se processo più di 3 dati ricevuti la stringa risulta essere incomprensibile, altrimenti tutto va a buon fine :astonished:.

Potresti per favore dare un occhiata? Grazie mille :slight_smile:

// Esempio di stringa ricevuta
char ricevo[160]="#0000#, t1 53, t2 20, t3 40, t4 20, t5 53, t6 30, t7 15, coefficiente 3.149, Led On";

int t1=0;
int t2=0;
int t3=0;
int t4=0;
int t5=0;
int t6=0;
int t7=0;

float Coefficiente=0;
bool Led=false;
void setup() 
{
  Serial.begin(9600);
  Serial.print("La stringa di partenza e': ");
  Serial.print(ricevo);
}
void loop() 
{
// 1. RICEVI L'ARRAY
// 2. TRASFORMALO IN UNA STRINGA
    String StringaTemporanea = String(ricevo);                // Trasforma la ricezione in una STRINGA
    StringaTemporanea.toLowerCase();                      // Trasforma tutto il testo contenuto nella stringa in MINUSCOLO
// 3. COMPRENDI LA STRINGA.
// 3.1 E' UNA RICHIESTA DI INFORMAZIONI? Rispondi con una stringa di caratteri
    if (StringaTemporanea.equals("help"))                 // Controlla che sia un messaggio di "HELP"
      {
      Serial.print("\nLa stringa in ingresso dovra' sempre essere cosi' composta: #0000#, t1 52, t2 20, tX xX, coefficiente 1.1, Led ON");
      }
// 3.2 E' UN COMANDO?
    else if (StringaTemporanea.startsWith("#0000#")) {    // Verifica se il messaggio contiene la PASSWORD corretta
    // #### comandi di inizializzazione
      int IndirizzoInizioComando=7;
      int IndirizzoFineComando;
      int LunghezzaTotaleStringa=StringaTemporanea.length();
  // #### INZIO CICLO DO..WHILE PER LA DECODIFICA ED IL CONTROLLO DEI SINGOLI COMANDI
      do{
    // ottieni indirizzo estremi stringa
      IndirizzoFineComando = StringaTemporanea.indexOf(",",IndirizzoInizioComando+1);
      if (IndirizzoFineComando<0){
        IndirizzoFineComando=LunghezzaTotaleStringa;
        }
    // copia la stringa in una sub temporanea
      String SubStringaTemporanea = StringaTemporanea.substring(IndirizzoInizioComando,IndirizzoFineComando);
    // trasformala in array
      SubStringaTemporanea.trim();
      char SubStringaTempChar[160];
      SubStringaTemporanea.toCharArray(SubStringaTempChar, IndirizzoFineComando-IndirizzoInizioComando);
      Serial.print("\nPezzo di stringa da analizzare:");
      Serial.print(SubStringaTempChar);
      
  // --- DA QUI PARTE LA COMPRENSIONE VERA E PROPRIA DEI SINGOLI COMANDI DELLA STRINGA IN INGRESSO ---
    // Dichiarazione delle variabili temporanee utili per la decodifica della stringa iniziale
      int valtemp; int valtemp2; String TempString; char TempChar[160];
    // #### COMPRENSIONE DI UN NUMERO "INT" ####
      // 1 -------------------------------------------
      if (sscanf (SubStringaTempChar,"t1 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t1=valtemp;
          Serial.print("\t\tTemp1 impostata a: ");
          Serial.print(t1);
          }
        else {Serial.print("\t\tIl valore di Temp1 deve essere compreso tra i valori 0 e 100");}
        }
        // 2 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t2 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t2=valtemp;
          Serial.print("\t\tTemp2 impostata a: ");
          Serial.print(t2);
          }
        else {Serial.print("\t\tIl valore di Temp2 deve essere compreso tra i valori 0 e 100");}
        }
        // 3 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t3 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t3=valtemp;
          Serial.print("\t\tTemp3 impostata a: ");
          Serial.print(t3);
          }
        else {Serial.print("\t\tIl valore di Temp3 deve essere compreso tra i valori 0 e 100");}
        }
        
        // 4 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t4 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t4=valtemp;
          Serial.print("\t\tTemp4 impostata a: ");
          Serial.print(t4);
          }
        else {Serial.print("\t\tIl valore di Temp4 deve essere compreso tra i valori 0 e 100");}
        } 
        
        // 5 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t5 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t5=valtemp;
          Serial.print("\t\tTemp5 impostata a: ");
          Serial.print(t5);
          }
        else {Serial.print("\t\tIl valore di Temp5 deve essere compreso tra i valori 0 e 100");}
        }
        /*
        // 6 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t6 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t6=valtemp;
          Serial.print("\t\tTemp6 impostata a: ");
          Serial.print(t6);
          }
        else {Serial.print("\t\tIl valore di Temp6 deve essere compreso tra i valori 0 e 100");}
        }
        // 7 ------------------------------------------
         else if (sscanf (SubStringaTempChar,"t7 %d",&valtemp)){
        if (valtemp>0 && valtemp<100){
          t7=valtemp;
          Serial.print("\t\tTemp7 impostata a: ");
          Serial.print(t7);
          }
        else {Serial.print("\t\tIl valore di Temp7 deve essere compreso tra i valori 0 e 100");}
        }
    */
    /*
    // #### COMPRENSIONE DI UN NUMERO "INT" IN NEGATIVO ####
      else if (sscanf (SubStringaTempChar,"t2 %d",&valtemp)){
        if (valtemp>-100 && valtemp<100){
          t2=valtemp;
          Serial.print("\t\tTemp2 impostata a: ");
          Serial.print(t2);
          }
        else {Serial.print("\t\tIl valore di Temp2 deve essere compreso tra i valori -100 e 100");}
        }
      */  
    // #### COMPRENSIONE DI UN NUMERO "FLOAT" A VIRGOLA MOBILE ####
      else if (sscanf (SubStringaTempChar,"coefficiente %s",TempChar)){
        float valtempf = atof(TempChar);
        if (valtempf>0 && valtempf<5){
          Coefficiente=valtempf;
          Serial.print("\tCoefficiente impostato a: ");
          Serial.print(Coefficiente);
          }
        else {Serial.print("\tIl valore del Coefficiente deve essere compreso tra i valori 0 e 5");}
        }
    // #### COMPRENSIONE DI UN COMANDO "CHAR", OSSIA CON SRTINGA DI COMANDO (es "ON" "OFF") ####
      else if (sscanf (SubStringaTempChar,"led %s",&TempChar)){
        if (!strcmp(TempChar,"on")){
          Led=true;
          Serial.print("\t\tLed impostato su 'ACCESO'");
          }
        else if (!strcmp(TempChar,"off")){
          Led=false;
          Serial.print("\t\tLed impostato su 'SPENTO'");
          }
        else {Serial.print("\t\tIl valore di 'Led' deve essere di tipo 'ON' o 'OFF'");}
        }
    // #### NEL CASO IN CUI SIA IMPOSSIBILE COMPRENDERE IL COMANDO ####
      else {
        Serial.print("Il comando: '");
        Serial.print(SubStringaTempChar);
        Serial.print("' non è comprensibile. Prova ad inviare il comando 'help' alla centralina");
        }
  // Aggiorna l'indirizzo del comando, inizializzandolo al comando successivo.
      IndirizzoInizioComando = IndirizzoFineComando+1;
  // RI-ESEGUI QUESTO CICLO DI CONTROLLO FINCHE' TUTTE LE ISTRUZIONI DELLA STRINGA INIZIALE NON SARANNO STATE CONTROLLATE E COMPRESE
      } while (IndirizzoFineComando < LunghezzaTotaleStringa);
      }
// 3.3 NON E' QUALCOSA DI COMPRENSIBILE? Reinvia l'SMS ad un numero di fiducia, comprensivo di mittente.
    else {
      Serial.print("\nLa stringa di testo in ingresso è di tipo sconosciuto e non è comprensibile");
      }
      Serial.print("\n\n");
  delay(3000);
}

Intanto inizia ad usare la funzione F() per racchiudere le stringhe di testo fisso e risparmiare RAM.
Questo:

Serial.print("\nLa stringa in ingresso dovra' sempre essere cosi' composta: #0000#, t1 52, t2 20, tX xX, coefficiente 1.1, Led ON");

diventa:

Serial.print(F("\nLa stringa in ingresso dovra' sempre essere cosi' composta: #0000#, t1 52, t2 20, tX xX, coefficiente 1.1, Led ON"));

Ciao, risolto tutto, sbagliavo a dichiarare la lunghezza del buffer :slight_smile:
Adesso ho un altra domanda...
Probabilmente il codice risulta essere un po pesante, perciò quando includo un paio di librerie per gestire lcd, l'esecuzione del programma si blocca.
Come posso risolvere?
Grazie!

Inizia col suggerimento che ti ho dato qui sopra. Risparmi molta memoria RAM.
Se poi continua a bloccarsi, vediamo di capire perché.

L'ho già fatto, che funzione svolge questa "F"?
Comunque sia, si blocca solo se dichiaro lcd tramite:
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2

Però è strano... è l'unico dispositivo i2c collegato ad arduino e il codice di esempio funziona...

Mi sbagliavo..
anche solo includendo le librerie non funziona più. ..

La funzione F() permette di leggere le stringhe dalla memoria Flash.
I microcontrollori sono ad architettura Harvard, ciò significa che la memoria che contiene il programma (la Flash su cui scrivi lo sketch) è separata dalla memoria che contiene i dati creati dal programma stesso (la RAM in cui vengono messe le variabili).
Senza precisare diversamente, la CPU preleva i dati sempre dalla RAM per cui il compilatore, quando trova una stringa, la salva sì in Flash (come parte del programma) ma durante l'esecuzione la copia in RAM. Se hai molte stringhe, i 2K di RAM dell'Atmega si saturano velocemente, essendoci in RAM anche tutte le altre variabili create dal codice nonché lo stack e l'heap.
Grazie alla funzione F() si istruisce il compilatore affinché legga le stringhe direttamente dalla Flash, saltando la loro copia in RAM. Il consumo di RAM cala quindi drasticamente.

Tornando a noi,

è l'unico dispositivo i2c collegato ad arduino e il codice di esempio funziona..

ma l'indirizzo del driver che gestisce il display è 0x27 oppure no? Se non è il suo indirizzo, la libreria non lo trova sul bus I2C.

Grazie per la spiegazione! :slight_smile:
Si, l'indirizzo è 0x27, infatti con il codice di esempio funziona tutto come dovrebbe...

Ma il display da solo, senza le altre lib nello sketch, ti funziona, quindi?
Se è così, potrebbe darsi che ci sia qualche incompatibilità fra libreria io che quelle usate saturino comunque la memoria.

Compilandolo con l'IDE 1.5.7, il compilatore alla fine riporta non solo l'uso della Flash ma anche quello (statico) della RAM. Provando lì, che numeri leggi?