Arduino + termocoppia + modulo 4 relè + LCD [Sketch]

Ciao a tutti,
continua la realizzazione della stufa a legna.
Se volete un resoconto, potete leggere qui:

http://forum.arduino.cc/index.php?topic=285414.msg2003192

In questo post vorrei dedicarmi allo Sketch.
Riassumendo molto velocemente, ho un Arduino connesso ad una termocoppia tramite MAX6675, un display LCD (16x2 standard Hitachi HD44780) e 4 relè.
Tutti i collegamenti sono riportati nello sketch.

In pratica vorrei che:

  • sotto una certa temperatura tutti i relè siano LOW
  • con 4 scaglioni di temperature, che si attivino i rispettivi relè (uno alla volta).
    Ecco lo Sketch:

(lo metto nel post sotto, per via del limite dei 9000 caretteri)

In pratica faccio fare un controllo ogni secondo (impostato nella costante “intervallo”).
Visto che le temperature lette dal MAX6675 sono un po’ “ballerine”, prima di far cambiare effettivamente marcia, voglio che la condizione del cambio sia valida per almeno 5 secondi (dati dalla costante iterMarcia).
Se il cambio temperatura dura più dei 5 secondi, tramite uno “switch case” si procede a mettere a LOW gli altri relè, e dopo un secondo (dato dalla costante “temporele”, ma stavolta con un delay, non con mills) viene acceso il relè corrispondente. Questa attesa avviene per un motivo preciso: avevo letto, da qualche parte, che bisognava aspettare un po’ di tempo dallo spegnimento di un relè alla reale fine del passaggio di corrente, per via delle parti meccaniche in gioco. Essendo che non voglio che ci siano più correnti in giro, è una cosa corretta da fare? Ho informazioni giuste o sono “castronerie”?
Il programma secondo voi va bene o si può ottimizzare? Spero che sia facilmente “interpretabile”, poiché presenta, per me, qualche difficoltà farlo! :slight_smile:

Grazie a tutti per il supporto!
Buon anno! :slight_smile:

Leonardo

/*  
 Pin di Arduino:
 
 14: pin collegamento al relè per la quarta marcia
 13: pin SCK del MAX6675
 12: pin RS del display
 11: pin E (Enable) del display
 10: pin CS del MAX6675
 9:  pin SO del MAX6675
 8:  Pin collegamento al relè per la terza marcia
 7:  Pin collegamento al relè per la seconda marcia
 6:  Pin collegamento al relè per la prima marcia
 5:  pin D4 del display
 4:  pin D5 del display
 3:  pin D6 del display
 2:  pin D7 del display
 

  Pin LCD: 
 * pin RS collegato al pin digitale 12 
 * pin E (Enable) collegato al pin digitale 11 
 * pin D4 collegato al pin digitale 5 
 * pin D5 collegato al pin digitale 4 
 * pin D6 collegato al pin digitale 3 
 * pin D7 collegato al pin digitale 2 
 * pin R/W collegato al GND 
 * pin 1 e pin 4 collegati a GND 
 * pin 2 collegato a +Vcc 
 * centrale del potenziometro 1 (lineare monogiro da 10 KOhm) collegato al pin 3 del'LCD (contrasto)
 * pin SX potenziometro 1 collegato a +Vcc 
 * pin DX potenziometro 1 collegato a GND 
 * centrale del potenziometro 2 (lineare monogiro da 10 KOhm) collegato al pin 15 del'LCD (retroilluminazione)
 * pin SX potenziometro 2 collegato a +Vcc 
 * pin DX potenziometro 2 collegato a GND 
*/  
  
// includere la libreria per il display:  
#include <LiquidCrystal.h>  

// includere la libreria per la sonda:  
#include <MAX6675.h>

int SO = 9;                // pin SO del MAX6675 (modificato in 9, era 11)
int CS = 10;               // pin CS del MAX6675
int SCIK = 13;             // pin SCK del MAX6675 
int units = 1;             // Unità di misura temp (0 = raw, 1 = ˚C, 2 = ˚F)
float temperatura = 0.0;   // Variabile della temperatura

// Inizializza la libreria del MAX6675
MAX6675 temp(CS,SO,SCIK,units);

/* 
   Viene creata l'istanza dell'oggetto LiquidCrystal chiamata lcd in cui 
   sono indicati i pin dell'LCD collegati alle uscite digitali di Arduino 
*/  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  

uint8_t degree[8]  = {140,146,146,140,128,128,128,128}; // Crea il simbolo dei gradi

#define intervallo 1000  // Intervallo di tempo tra una lettura e l'altra della sonda


long previousMills = 0;  // Memorizza l'ultima volta che la temperatura è stata visualizzata

#define Temp1 45 // Temperatura limite per la marcia 0 (tutto spento)
#define Temp2 55 // Temperatura limite per la marcia 1 (acceso il relè1)
#define Temp3 60 // Temperatura limite per la marcia 2 (acceso il relè2)
#define Temp4 62 // Temperatura limite per la marcia 3 (acceso il relè3)

#define marcia1 6 // Pin collegamento al relè per la prima marcia
#define marcia2 7 // Pin collegamento al relè per la seconda marcia
#define marcia3 8 // Pin collegamento al relè per la terza marcia
#define marcia4 14 // Pin collegamento al relè per la terza marcia

int marcia = 0;              // definisce la marcia da mettere
int prevmarcia = 0;          // definisce la marcia che è impostata
int cambiamarcia = 0;        // definisce se bisogna o meno cambiare marcia
long prevmillsmarcia = 0;    // memorizza il tempo trascorso dall'ultimo cambio della variabile marcia
#define iterMarcia 5000  // Intervallo di tempo che deve durare il cambio marcia

#define temporele 1000      // definisce il tempo che il relè deve aspettare prima di commutare
  
void setup() {  
  // mette ad OUTPUT i pin dei 3 relè
   pinMode(marcia1, OUTPUT);
   pinMode(marcia2, OUTPUT);  
   pinMode(marcia3, OUTPUT); 
   pinMode(marcia4, OUTPUT);    
   // impostare il numero di colonne ed il numero di righe di lcd  
  lcd.begin(16, 2);  
  lcd.createChar(0, degree); // Crea il simbolo dei gradi
  // Visualizzo sul display la parte fissa del messaggio
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  temperatura = temp.read_temp();
  lcd.print(temperatura);
  lcd.setCursor(11, 0);
  lcd.write((byte)0); // Scrive il simbolo dei gradi
  lcd.print("C");

  lcd.setCursor(0, 1);  // Cambia colonna
  lcd.print("Marcia: ");
  lcd.setCursor(8, 1);  
  lcd.print(marcia);
}  
  
void loop() { 
 


   if (millis() -  previousMills > intervallo ) // controlla la temperatura dopo il tempo dichiarato in "intervallo"
   {
         previousMills = millis();  // Memorizza il valore di mills
         
      	 // Legge la temperatura dal MAX6675
	 temperatura = temp.read_temp();

         // queste due non so se vanno qui
         lcd.setCursor(6, 0);          
         lcd.print(temperatura);
         
         
         if (temperatura < Temp1)
         {
           marcia = 0;
           if (marcia != cambiamarcia)
           {
           prevmillsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp1 and temperatura < Temp2)
         {
           marcia = 1;
           if (marcia != cambiamarcia)
           {
           prevmillsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp2 and temperatura < Temp3)
         {
           marcia = 2;
           if (marcia != cambiamarcia)
           {
           prevmillsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp3 and temperatura < Temp4)
         {
           marcia = 3;
           if (marcia != cambiamarcia)
           {
           prevmillsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else 
         {
           marcia = 4;
           if (marcia != cambiamarcia)
           {
           prevmillsmarcia = millis();
           cambiamarcia = marcia;
           }
         }

    // questa è da togliere, vale solo di prova
    lcd.setCursor(10, 1);  
    // visualizza sul display la marcia da mettere (DM)
    lcd.print("DM ");
    lcd.print(marcia);
    // se è cambiata marcia, e la durata del cambio è maggiore della variabile iterMarcia
     if (prevmarcia != marcia and millis() -  prevmillsmarcia > iterMarcia)
     {

switch (marcia) {
  case 0:    // Mette tutto a zero
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    break;
  case 1:    // Accende il relè 01 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia1, HIGH);
    break;
  case 2:    // Accende il relè 02 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia2, HIGH);
    break;
  case 3:    // Accende il relè 03 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia3, HIGH);
    break;
  case 4:    // Accende il relè 04 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    delay (temporele);
    digitalWrite(marcia4, HIGH);
    break;
  }
  lcd.setCursor(8, 1);  
    // visualizza sull'lcd la marcia corrente
    lcd.print(marcia);
    // assegna la marcia corrente a quella precedente
    prevmarcia = marcia;
     }
 }
   

   
}

Questa attesa avviene per un motivo preciso: avevo letto, da qualche parte, che bisognava aspettare un po' di tempo dallo spegnimento di un relè alla reale fine del passaggio di corrente, per via delle parti meccaniche in gioco. Essendo che non voglio che ci siano più correnti in giro, è una cosa corretta da fare? Ho informazioni giuste o sono "castronerie"?

Parli di relè o scheda relè, nel primo caso devi usare un transistor più diodo per ogni relè.
Comunque in generale il relè ha un suo tempo di intervento, capisci si tratta di un componente elettromeccanico. Nel tuo caso un solo relè all'istante T deve essere eccitato, diseccitarlo comporta del tempo (che non puoi controllare) quindi prima di eccitare l'altro relè attenti almeno 1 secondo.

Occhio che i contatti di un relè possono rimanere incollati.

Il programma secondo voi va bene o si può ottimizzare? Spero che sia facilmente "interpretabile", poiché presenta, per me, qualche difficoltà farlo! :slight_smile:

Se ti funziona allora è corretto pensare all'ottimizzazione (non ho analizzato il codice).

Ci sono errori di programmazione da principiante che tuttavia non pregiudicano il funzionamento
del programma, quindi non è urgente porvi rimedio.

Il tipo "int" è grande 16bit e non ha senso se il valore che deve salvare con supererà mai 255, per cui si usa il tipo "byte" (uint8_t, unsigned char) , così risparmiamo un byte.
Le variabili che non cambieranno mai il loro valore durante il corso del programma (runtime) dovrebbero essere dichiarate "const" in questo modo se per errore modifichi il valore il compilatore emette errore abortendo la compilazione.

#long previousMills

Deve essere unsigned long (uint32_t). Poi il nome non è indicativo e se ti servono più variabili timer come la chiami previousMillis1, no meglio legare il nome alla funzione es. timerPwrOn.

Ciao.

Ciao!
Il relè è in realtà una scheda con due relè. Questa, per la precisione:

http://www.ebay.it/itm/111519865048?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

quindi, per quanto ho capito, basta collegarla al 5+ e gnd, dargli due pin dall'arduino.
Devo fare delle prove col tester e capire se un secondo è sufficiente, ma credo proprio di si! :slight_smile:

Per quanto riguarda lo Sketch, c'ho rimesso un po' mano seguendo i tuoi ottimi consigli!
(dal codice ho tolto i primi commenti sui pin, altrimenti superavo i 9000 caratteri.Tanto rimangono come prima)

// includere la libreria per il display:  
#include <LiquidCrystal.h>  

// includere la libreria per la sonda:  
#include <MAX6675.h>

#define SO 9                // pin SO del MAX6675 (modificato in 9, era 11)
#define CS 10               // pin CS del MAX6675
#define SCIK 13             // pin SCK del MAX6675 
#define units 1             // Unità di misura temp (0 = raw, 1 = ˚C, 2 = ˚F)
int temperatura = 0;        // Variabile della temperatura

// Inizializza la libreria del MAX6675
MAX6675 temp(CS,SO,SCIK,units);

/* 
   Viene creata l'istanza dell'oggetto LiquidCrystal chiamata lcd in cui 
   sono indicati i pin dell'LCD collegati alle uscite digitali di Arduino 
*/  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  

uint8_t degree[8]  = {140,146,146,140,128,128,128,128}; // Crea il simbolo dei gradi

#define intervallo 1000  // Intervallo di tempo tra una lettura e l'altra della sonda


unsigned long Millsintervallo = 0;  // Memorizza il tempo trascorso dall'ultima volta che la temperatura è stata visualizzata

#define Temp1 45 // Temperatura limite per la marcia 0 (tutto spento)
#define Temp2 55 // Temperatura limite per la marcia 1 (acceso il relè1)
#define Temp3 60 // Temperatura limite per la marcia 2 (acceso il relè2)
#define Temp4 62 // Temperatura limite per la marcia 3 (acceso il relè3)

#define marcia1 6  // Pin collegamento al relè per la 1° marcia
#define marcia2 7  // Pin collegamento al relè per la 2° marcia
#define marcia3 8  // Pin collegamento al relè per la 3° marcia
#define marcia4 14 // Pin collegamento al relè per la 4° marcia

byte marcia = 0;              // definisce la marcia da mettere
byte prevmarcia = 0;          // definisce la marcia che è impostata
byte cambiamarcia = 0;        // definisce se bisogna o meno cambiare marcia
unsigned long millsmarcia = 0;    // memorizza il tempo trascorso dall'ultimo cambio della variabile marcia
#define iterMarcia 5000  // Intervallo di tempo che deve durare il cambio marcia

#define temporele 1000      // definisce il tempo che il relè deve aspettare prima di commutare
  
void setup() {  
  // mette ad OUTPUT i pin dei 4 relè
   pinMode(marcia1, OUTPUT);
   pinMode(marcia2, OUTPUT);  
   pinMode(marcia3, OUTPUT); 
   pinMode(marcia4, OUTPUT);    
   // impostare il numero di colonne ed il numero di righe di lcd  
  lcd.begin(16, 2);  
  lcd.createChar(0, degree); // Crea il simbolo dei gradi
  // Visualizzo sul display la parte fissa del messaggio
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  temperatura = temp.read_temp();
  if (temperatura < 10)
  {
   lcd.print("0");
  }
  lcd.print(temperatura);
  lcd.setCursor(7, 0);
  lcd.write((byte)0); // Scrive il simbolo dei gradi
  lcd.print("C");

  lcd.setCursor(0, 1);  // Cambia colonna
  lcd.print("Marcia: ");
  lcd.setCursor(8, 1);  
  lcd.print(marcia);
}  
  
void loop() { 
 


   if (millis() -  Millsintervallo > intervallo ) // controlla la temperatura dopo il tempo dichiarato in "intervallo"
   {
         Millsintervallo = millis();  // Memorizza il valore di mills
         
       // Legge la temperatura dal MAX6675
 temperatura = temp.read_temp();

         // ***** queste righe non so se vanno qui ***** 
         lcd.setCursor(5, 0);          
         if (temperatura < 10)
          {
           lcd.print("0");
          }
         lcd.print(temperatura);
         // ***** fino a qui ***** 
         
         if (temperatura < Temp1)
         {
           marcia = 0;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp1 and temperatura < Temp2)
         {
           marcia = 1;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp2 and temperatura < Temp3)
         {
           marcia = 2;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp3 and temperatura < Temp4)
         {
           marcia = 3;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else 
         {
           marcia = 4;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }

    // ***** queste righe sono da togliere, valgono solo come prova *****
    // visualizza sul display il tempo dall'ultimo cambio marcia 
    lcd.setCursor(10, 0);
    lcd.print("T    ");
    // le due sopra servono solo per un fattore estetico: 
    // se il tempo è maggiore a 10, all'azzeramento della variabile
    // millsmarcia, viene comunque visualizzata la seconda cifra del numero precedente
    lcd.setCursor(10, 0);
    lcd.print("T ");
    lcd.print((millis() -  millsmarcia)/1000);
    lcd.setCursor(10, 1);  
    // visualizza sul display la marcia da mettere (DM)
    lcd.print("DM ");
    lcd.print(marcia);
    // ***** fino a qui *****
    
    // se è cambiata marcia, e la durata del cambio è maggiore della variabile iterMarcia
     if (prevmarcia != marcia and millis() -  millsmarcia > iterMarcia)
     {

switch (marcia) {
  case 0:    // Mette tutto a zero
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    break;
  case 1:    // Accende il relè 01 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia1, HIGH);
    break;
  case 2:    // Accende il relè 02 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia2, HIGH);
    break;
  case 3:    // Accende il relè 03 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia3, HIGH);
    break;
  case 4:    // Accende il relè 04 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    delay (temporele);
    digitalWrite(marcia4, HIGH);
    break;
  }
  // fine dello switch case
    lcd.setCursor(8, 1);  
    // visualizza sull'lcd la marcia corrente
    lcd.print(marcia);
    // assegna la marcia corrente a quella precedente
    prevmarcia = marcia;
     }
   
 }
// fine dell'if principale

   
}

Per quanto riguarda la dichiarazione dei pin e delle costanti, ho preso spunto da questa discussione:

http://forum.arduino.cc/index.php?topic=35477.0

Mi sono risparmiato un "long", poiché della temperatura, adesso, prendo solo l'intero, e le due variabile per gestire i mills (a cui ho cambiato nome) le ho messe giustamente come "unsigned".
Il programma, comunque, funziona.
Se ci fosse altro da ottimizzare, sono ben contento di farlo!
Grazie davvero a tutti!
Ciao

Per quanto riguarda la dichiarazione dei pin e delle costanti, ho preso spunto da questa discussione:

Inizializzazione pin arduino - Italiano - Arduino Forum

La discussione in quel topic non è aderente ad arduino e sopratutto alla toolchain avr-gcc.
Ciò che si sostiene riguardo a const è applicabile su un altra famiglia di microcontroller AVR 51/52.
Cioè è falso che "const" scriva i dati in flash (rom) in quanto sono sempre in ram.

Per portare un dato nella memoria di programma flash si usa dichiarare il dato nel modo classico ma aggiungendo l'attributo PROGMEM, oppure si usa la macro F("string") oppure la macro PSTR("string"). La lettura di questi dati è leggermente differente dai dati direttamente conservati in ram.

Il programma, comunque, funziona.

Se il tuo obbiettivo imminente è questo allora puoi lasciare tutto come sta, sapendo tuttavia che si può ottimizzare ancora e/o comunque si può riscrivere in modo molto differente.
Se il tuo obbiettivo è scrivere altri programmi e anche molto lunghi le cattive abitudini prese adesso
ti saranno di intralcio dopo per cui ti consiglio di dedicare tempo al fine di prendere quelle buone abitudini che ti semplificheranno il lavoro.

Ciao.

Ciao,
grazie per la risposta!
Hai mica qualche link per potermi studiare qualcosa in merito?
Il programma mi interessa che funzioni. Però sono un perfezionista, quindi man mano che aumentano le mie conoscenze vorrei che anche i lavori che faccio andassero di pari passo (quindi potrei, in futuro, riscrivere completamente il programma senza nessun problema).
Grazie davvero di tutto!
Alla fine toccherà di fare una stufa solo per te! :wink:

Un link che condensa il tutto non c'è, quindi ti devi destreggiare tra le mezze verità e lo stato di fatto che trovi in rete.

Sul forum si è parlato altre volte, ma non ho i link, quello che posso dirti e che alcuni utenti sono
più attivi di altri e il 90 % dei loro post corrisponde a realtà inconfutabili, tuttavia come ho già detto, le mezze verità derivano spesso da ignoranza che si vuole colmare. Detta papale papale in passato ne ho scritte cazzate.

Alcuni di questi utenti sono: (non se ne abbiano a male quelli che ho dimenticato)
leo72, astrobeed, lesto, Etemenanki, cybers, gpb01, Menniti, nid, cece, ecc.

Quindi puoi fare una ricerca dei topic di questi utenti.

Per il resto:
La bibbia sul microprocessore è mamma Atmel.
La bibbia sul compilatore è gcc e:Redirect Notice
La bibbia su Arduino è il codice sorgente di Arduino core.
Per il C/C++ c'è l'imbarazzo della scelta, ma C/C++ legato allo sviluppo su microcontroller con risorse limitate praticamente non c'è nulla. Quindi si parte dalla conoscenza del linguaggio e dalla conoscenza intima della toolchain e con la consapevolezza che non c'è un sistema operativo che ci vieta di fare danno, per cui controllo totale (mmm... stati pilotando un aereo da combattimento del 1945).

Alla fine toccherà di fare una stufa solo per te! :wink:

Esagerato, mmm... ok mi raccomando le decorazioni in maiolica. :smiley:

Ciao.

Ciao,
vada per la maiolica! :slight_smile:
Ho guardato un po' di cosette, ma per ora mi sembra tutto molto "arabico" :slight_smile: .
Seguendo i tuoi consigli iniziali, ho modificato nuovamente la dichiarazione di variabili e costanti...pensi ci si possa essere?

// includere la libreria per il display:  
#include <LiquidCrystal.h>  

// includere la libreria per la sonda:  
#include <MAX6675.h>

const byte SO = 9;                // pin SO del MAX6675 (modificato in 9, era 11)
const byte CS = 10;               // pin CS del MAX6675
const byte SCIK = 13;             // pin SCK del MAX6675 
const byte units = 1;             // Unità di misura temp (0 = raw, 1 = ˚C, 2 = ˚F)
int temperatura = 0;              // Variabile della temperatura

// Inizializza la libreria del MAX6675
MAX6675 temp(CS,SO,SCIK,units);

// Inizialiazza la libreria dell'LCD 
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  

uint8_t degree[8]  = {140,146,146,140,128,128,128,128}; // Crea il simbolo dei gradi

const unsigned int intervallo = 1000;  // Intervallo di tempo tra una lettura e l'altra della sonda


unsigned long Millsintervallo = 0;  // Memorizza il tempo trascorso dall'ultima volta che la temperatura è stata visualizzata

const byte Temp1 = 45;    // Temperatura limite per la marcia 0 (tutto spento)
const byte Temp2 = 55;    // Temperatura limite per la marcia 1 (acceso il relè1)
const byte Temp3 = 60;    // Temperatura limite per la marcia 2 (acceso il relè2)
const byte Temp4 = 62;    // Temperatura limite per la marcia 3 (acceso il relè3)

const byte marcia1 = 6;   // Pin collegamento al relè per la 1° marcia
const byte marcia2 = 7;   // Pin collegamento al relè per la 2° marcia
const byte marcia3 = 8;   // Pin collegamento al relè per la 3° marcia
const byte marcia4 = 14;  // Pin collegamento al relè per la 4° marcia

byte marcia = 0;                        // definisce la marcia da mettere
byte prevmarcia = 0;                    // definisce la marcia che è impostata
byte cambiamarcia = 0;                  // definisce se bisogna o meno cambiare marcia
unsigned long millsmarcia = 0;          // memorizza il tempo trascorso dall'ultimo cambio della variabile marcia
const unsigned int iterMarcia = 5000;   // Intervallo di tempo che deve durare il cambio marcia

const unsigned int temporele = 1000;    // definisce il tempo che il relè deve aspettare prima di commutare
  
void setup() {  
  // mette ad OUTPUT i pin dei 4 relè
   pinMode(marcia1, OUTPUT);
   pinMode(marcia2, OUTPUT);  
   pinMode(marcia3, OUTPUT); 
   pinMode(marcia4, OUTPUT);    
   // impostare il numero di colonne ed il numero di righe di lcd  
  lcd.begin(16, 2);  
  lcd.createChar(0, degree); // Crea il simbolo dei gradi
  // Visualizzo sul display la parte fissa del messaggio
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  temperatura = temp.read_temp();
  if (temperatura < 10)
  {
   lcd.print("0");
  }
  lcd.print(temperatura);
  lcd.setCursor(7, 0);
  lcd.write((byte)0); // Scrive il simbolo dei gradi
  lcd.print("C");

  lcd.setCursor(0, 1);  // Cambia colonna
  lcd.print("Marcia: ");
  lcd.setCursor(8, 1);  
  lcd.print(marcia);
}  
  
void loop() { 
 


   if (millis() -  Millsintervallo > intervallo ) // controlla la temperatura dopo il tempo dichiarato in "intervallo"
   {
         Millsintervallo = millis();  // Memorizza il valore di mills
         
       // Legge la temperatura dal MAX6675
 temperatura = temp.read_temp();

         // ***** queste righe non so se vanno qui ***** 
         lcd.setCursor(5, 0);          
         if (temperatura < 10)
          {
           lcd.print("0");
          }
         lcd.print(temperatura);
         // ***** fino a qui ***** 
         
         if (temperatura < Temp1)
         {
           marcia = 0;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp1 and temperatura < Temp2)
         {
           marcia = 1;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp2 and temperatura < Temp3)
         {
           marcia = 2;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else if (temperatura >= Temp3 and temperatura < Temp4)
         {
           marcia = 3;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }
         else 
         {
           marcia = 4;
           if (marcia != cambiamarcia)
           {
           millsmarcia = millis();
           cambiamarcia = marcia;
           }
         }

    // ***** queste righe sono da togliere, valgono solo come prova *****
    // visualizza sul display il tempo dall'ultimo cambio marcia 
    lcd.setCursor(10, 0);
    lcd.print("T    ");
    // le due sopra servono solo per un fattore estetico: 
    // se il tempo è maggiore a 10, all'azzeramento della variabile
    // millsmarcia, viene comunque visualizzata la seconda cifra del numero precedente
    lcd.setCursor(10, 0);
    lcd.print("T ");
    lcd.print((millis() -  millsmarcia)/1000);
    lcd.setCursor(10, 1);  
    // visualizza sul display la marcia da mettere (DM)
    lcd.print("DM ");
    lcd.print(marcia);
    // ***** fino a qui *****
    
    // se è cambiata marcia, e la durata del cambio è maggiore della variabile iterMarcia
     if (prevmarcia != marcia and millis() -  millsmarcia > iterMarcia)
     {

switch (marcia) {
  case 0:    // Mette tutto a zero
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    break;
  case 1:    // Accende il relè 01 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia1, HIGH);
    break;
  case 2:    // Accende il relè 02 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia2, HIGH);
    break;
  case 3:    // Accende il relè 03 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia4, LOW);
    delay (temporele);
    digitalWrite(marcia3, HIGH);
    break;
  case 4:    // Accende il relè 04 (e fa una pausa, onde evitare corrente su du relè)
    digitalWrite(marcia1, LOW);
    digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    delay (temporele);
    digitalWrite(marcia4, HIGH);
    break;
  }
  // fine dello switch case
    lcd.setCursor(8, 1);  
    // visualizza sull'lcd la marcia corrente
    lcd.print(marcia);
    // assegna la marcia corrente a quella precedente
    prevmarcia = marcia;
     }
   
 }
// fine dell'if principale

   
}

Condivido, comunque, le tue riflessioni presenti nell'ultimo post.
Grazie di tutto!
Leonardo

Ho guardato un po' di cosette, ma per ora mi sembra tutto molto "arabico" :slight_smile: .

Non mi aspettavo diversamente, arduino style semplifica molto, comunque alla fine arduino core lib chiama le funzioni della avrlibc le quali sono un ostiche da digerire.

Si preferisce una variabile alla #define perché se fossi dotato di un debug hardware con il supporto software puoi vedere il contenuto delle variabili, mentre una #define del pin number è appunto un numero come tanti. C'è anche una questione di stile e conformità con arduino che usa il C++. Per adesso continua così ma non prendere come dogma che le #define non si usano, si usano è sono utili e più in là ti verrà quasi spontaneo scegliere tra una #define o variabile, specie se dedichi tempo nell'apprendimento del funzionamento del preprocessore C/C++.

delay (temporele);
digitalWrite(marcia2, HIGH);

Codice intuitivo, che però in certi (molti) casi impedisce al programma di lavorare correttamente.
La funzione delay ferma tutto per T tempo, durante questo fermo le uniche cose che funzionano sono gli interrupt, quando il micro riceve una IRQ (Interrupt Request) salta ad un indirizzo specifico ad eseguire codice e al termine ritorna al punto precedente.

Senza menarla troppo il delay mortifica le prestazioni del microcontroller e pertanto ne andrebbe fatto un uso limitato assicurandosi che non comporti malfunzionamenti al resto del codice.

L'alternativa a delay(1000) è millis() tuttavia deve essere integrata nel codice e nel tuo caso
non è semplice e non è detto che ci sia motivo per farlo. Se vuoi che dopo un secondo si accenda il pin ma in questo secondo ti serve anche fare altre cose devi rivedere il codice.
Nel mio codice di delay non c'è ne ombra alcuna, solo in una lib c'è qualche delay di pochi microsecondi.

PS: quando introduci modifiche pesanti al codice funzionante congela questo con un numero di versione e lavora ad una copia del codice incrementando il numero di versione e/o aggiungendo un tag, es a (alfa), b(beta) o anche per esteso, il codice testato e funzionante ha solo il numero di versione. Potresti ritrovarti con 3 o più versioni funzionanti e ognuna introduce o meno una caratteristica, questo sarebbe utile saperlo e si usa solitamente un file chiamato changelog dove scrivi tutti i cambiamenti con data etc. Ci sono dei software che sono stati creati per mantenere tutte le versioni del codice, uno tra questi e git usato anche da Arduino team.
Troppe cose in troppo poco tempo portano confusione alla mente, per cui sai che c'è git e fra un paio di mesi vai a vedere come funziona.

digitalWrite(marcia2, LOW);
    digitalWrite(marcia3, LOW);
    digitalWrite(marcia4, LOW);

Non è per cattiveria, anche io scrivo codice di questo tipo, che è si leggibile ma comporta troppe
repliche come il codice sopra che è in ogni case. Allora si potrebbe scrivere in un array (0,0,1,0) la marcia che si vuole inserire, poi un ciclo for legge ogni elemento e se 0 scrive digitalWrite(pin, 0).
Il codice sembra complicarsi, ma si semplifica ed molto simile a quello che farebbe un essere umano, cioè si appunta dei dati e poi in base a questi si comporta.

byte pin[] = { 6, 7, 8, 14 };
byte marcia[] = { 0, 0, 0, 0 };

void changeGear() {
     // usa millis qui o prima della chiamata 
     digitalWrite(pin[i], marcia[i]);
}

/*  Esempio di chiamata changeGear()
     if (timerOneSecond == 0)
            timerOneSecond = millis();
     if ( (millis() - timerOneSecond) > 1000 ) {
        chageGear();
        timerOneSecond = 0;   
     }
 
*/

Ciao.