Problema chiamata funzioni

Ripropongo qui il mio problema perchè ritengo sia opportuno dargli un titolo adeguato e dignità di “problema primario” invece di finire in coda ad un altro post nato per tutt’altro scopo.

I dati base: Arduino Mega, display 3.2", modulo RTC.

Sto realizzando un piccolo pannellino per l’auto sul quale visualizzare alcuni dati. Ho scelto di creare 4 differenti pagine selezionabili con un piccolo encoder.
Le singole pagine saranno:
Orologio
una semplice visualizzazione di data, ora e temperatura
Cronometro
ore, minuti e secondi. Un pulsante per dare lo start, uno per lo stop, uno per azzerare.
Timer
imposto un tempo (uso i tre pulsanti di prima) e faccio partire il countdown
Dash
è il più complesso, visualizzo 8 dati relativi al funzionamento del motore. Ho quindi 8 sensori, leggo il loro valore, passo attraverso le curve di taratura e lo stampo a video.

Le 4 pagine sono state create in temi diversi, programmi separati e “stand alone” e funzionano tutte come voglio.
I programmi potevano sicuramente essere scritti meglio, usare librerie più aggiornate, sprecare meno risorse… non mi importa.

Adesso ho realizzato un “contenitore” ovvero uno sketch che richiama i 4 programmi sotto forma di funzioni, in relazone al movimento del famoso encoder.

Il contenitore funziona.
Inizialmente non ho inserito la chiamata alle funzioni ma facevo semplicemente scrivere qualcosa sul seriale. Funzionava.

Adesso che ho inserito tutto il pezzo di codice relativo alla funzione “cronometro” e non va più.
Mi da un errore in compilazione che subito si scontra con la mia ignoranza e richiede il vostro aiuto.
Avevo capito che potevo inserire il codice così com’era ma evidentemente qualcosa va fatto per “trasformarlo” da programma autonomo a funzione.
Ho eliminato il setup, ma non è cambiato nulla.
Resta l’errore:

DASH_3.ino: In function ‘void cronometro()’:
DASH_3:160: error: a function-definition is not allowed here before ‘{’ token
DASH_3:227: error: expected ‘}’ at end of input

come se la funzione loop non fosse permessa dentro la funzione cronometro. Potrebbe essere anche solo un problema di parentesi ma il conto mi torna.

Ecco il codice:

// Date and time functions using RX8025 RTC connected via I2C and Wire lib
#include <UTFT.h>
#include <Wire.h>
#include "Sodaq_DS3231.h"
char weekDay[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

// inserisco i fonts che verrano utilizzati
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

UTFT myGLCD(CTE32HR,38,39,40,41);

int pinstart = 10; // digital pin   pulsante di inizio conteggio
int pinstop = 11;  // digital pin   pulsante di fine conteggio
int pinreset = 12;  // digital pin  pulsante di azzeramento

int statostart;
int statostop;
int statoreset;

unsigned long tempo_base;
unsigned long tempo_cronometrato = 0;
unsigned long tempo_congelato;
unsigned long tempo;
unsigned long centesimi;
unsigned long secondi;
unsigned long minuti;
unsigned long ore;
int flag = 1;

int encoderPin1 = 2;
int encoderPin2 = 3;
 
 volatile int lastEncoded = 0;
 volatile int encoded = 0;
 volatile int status0 = 0;
volatile long encoderValue = 0;
 
long lastencoderValue = 0;
 

int page = 1;

int lastMSB = 0;
int lastLSB = 0;
 
void setup() 
{
  myGLCD.InitLCD();// settato in orizzontale
  Serial.begin (9600);
  Wire.begin();
  rtc.begin();
  pinMode (pinstart, INPUT_PULLUP);
  pinMode (pinstop, INPUT_PULLUP);
  pinMode (pinreset, INPUT_PULLUP);
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
}
 
void loop()
{

if (encoderValue != status0)
  { 
              if ((encoderValue-status0)>0) //se l'encoder è stato ruotato in senso antiorario
              {
                  page = page-1; // vai alla pagina precedente
                  if (page==0) page=4;   // le pagine sono 4, dopo la 4 c'è nuovamente la 1
              }
       
              else if ((encoderValue-status0)<0)  // se l'encoder è stato ruotato in senso orario
              {
                 page = page+1;   // vai alla pagina successiva
                 if (page==5) page=1;  // le pagine sono sempre 4 quindi prima della 1 c'è la 4
              }
         
              else   // si verifica solo se le due variabili hanno lo stesso identico valore
              { // continua a non fare un bel cazzo di niente
              }


              switch (page) 
              {
                   case 1:
                     orologio();
                   break;
           
                  case 2:
                     dash();
                  break;
              
                  case 3:
                     cronometro();
                  break;
           
                  case 4:
                     timer();
                  break;
           
                  default: 
                     Serial.println("QUALCOSA NON FUNZIONA");
                  break;
                }
    }
    
 else   // si verifica solo se le due variabili hanno lo stesso identico valore
    { // persevera a non fare un bel cazzo di niente
    }    
     
   
   status0 = encoderValue;
 delay(500);
  
}
 
void updateEncoder()
{
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit
  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
  
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) 
  {encoderValue ++;
  }
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) 
  {encoderValue --;
  }
  lastEncoded = encoded; //store this value for next time
}




void cronometro() // unica funzione attualmente implementata (più o meno...)
{
      Serial.println("visualizzo la schermata del cronometro:");
      Serial.println(page);
      // visualizzo un cronometro sullo schermo 00:00:00  hh:mm:ss  non mi interessano decimi e centesimi
      myGLCD.setFont(BigFont);
      myGLCD.clrScr();
      myGLCD.setColor(VGA_AQUA);// cambio colore 
      myGLCD.setFont(SevenSegNumFont);
      myGLCD.print("00",82,150);
      myGLCD.print("00",166,150);
      myGLCD.print("00",250,150);
      myGLCD.setFont(BigFont);
      myGLCD.print(":",149,170);
      myGLCD.print(":",233,170);
      
   

      uint32_t old_ts; //questo comando l'ho copiato pari pari dall'esempio da cui mi sono ispirato, non so che faccia, a che serva e se serva. 

    void loop () 
    {
    statostart = digitalRead (pinstart);
    statostop  = digitalRead (pinstop);
    statoreset = digitalRead (pinreset);

     if ((statostart == LOW)&& (flag < 2)) // premo il pulsante start e parte il cronometro
     {
      myGLCD.clrScr();
      DateTime now = rtc.now(); //get the current date-time
      uint32_t ts = now.getEpoch();
      tempo_base = ts;
      flag = 0;
     }

     if ((statostart == LOW)&& (flag == 2)) 
     {
      flag = 0;
     }

     if (flag == 0)
     {
      myGLCD.setFont(BigFont); 
      myGLCD.print("START", 100,125);
      DateTime now = rtc.now(); //get the current date-time
      uint32_t ts = now.getEpoch();
      tempo_cronometrato = ts - tempo_base;  // differenza tra conteggio attuale e conteggio di partenza
      tempo = tempo_cronometrato; 
      myGLCD.setFont(SevenSegNumFont);
      myGLCD.printNumI(tempo, 82,250);
      ore = int(tempo/3600);
      minuti = int((tempo-(ore*3600))/60);
      secondi = tempo-(ore*3600)-(minuti*60);
      //finalmente scriviamo qualcosa sullo schermo...
      myGLCD.printNumI(ore,82,150,2,'0');
      myGLCD.printNumI(minuti,166,150,2,'0');
      myGLCD.printNumI(secondi,250,150,2,'0');
      myGLCD.setFont(BigFont);
      myGLCD.print(":",149,170);
      myGLCD.print(":",233,170);
     }

     if (statostop == LOW)
     {
      myGLCD.setFont(BigFont);
      myGLCD.print("STOP ", 100,125);
      flag = 2;
     }
    }
  
}

void timer() //funzione non ancora implementata
{
    Serial.println("visualizzo la schermata del timer:");
    Serial.println(page);
}
 
void orologio() //funzione non ancora implementata
{
      Serial.println("visualizzo la schermata dell'orologio:");
      Serial.println(page);
}

void dash() //funzione non ancora implementata
{
      Serial.println("visualizzo la schermata dei dati motore:");
      Serial.println(page);
}

Se qualche anima pia avesse voglia di darci un’occhiata…

Grazie

Riccardo

ciao

da una occhiata al volo:

  • manca la '}' alla fine della funzione cronometro();
  • ho visto ben 2 volte void loop() :o :o

ciao
pippo72

… pippo72 è stato più veloce di me :smiley:

NON puoi avere due funzioni loop() … probabilmente nel copia/incolla te ne sei portata dietro una di troppo.

Usa sempre la combinazione CTRL-T (Tools → Auto Format) per rendere più “ordinato” il codice e quindi più leggibile.

Guglielmo

Grazie delle risposte, tre commenti:

  1. mi ero impegnato ad essere "ordinato"..... è come alle elementari, io mi impegnavo ma la maestra diceva che ero disordinato. Odiavo la maestra :wink:
  2. nel topic precedente (che ho chiuso per aprire questo dedicato) mi si diceva che potevo avere quante funzioni loop volevo.... ora sono un po' confuso. Se non metto un loop all'interno della mi achiamata, come faccio a fare continuare l'azione indefinitamente?
  3. le parentesi mi sembrano chiudersi correttamente: la funzione cronometro è alla riga 139, la parentesi si apre alla 140 e si chiude alla 209 appena prima della funzione timer. Sialludava a qualcosaltro? o semplicemente non ho ancora capito un beep?

Ho provato ctrl-t, mi piaceva di più prima.... naaaa, non è vero!

Rigrazie

Guzzi82:
.... ora sono un po' confuso. Se non metto un loop all'interno della mi achiamata, come faccio a fare continuare l'azione indefinitamente?...

ci deve essere un solo loop() che richiama le altre funzioni:

void funzione1
{
...
}
void funzione2
{
...
}
void funzione3
{
...
}

void loop()
{
funzione1();
funzione2();
funzione3();
}

ciao
pippo72

In 'C' puoi avere UNA sola funzione con un determinato nome ...
... loop() è appunto il nome della funzione, quindi ... ne puoi avere UNO ed UNO SOLO (così come puoi avere un solo setup()).

Puoi poi avere svariate altre funzioni, ciascuna con il suo nome (univoco), che richiami da dove vuoi ...
... ovvero una qualsiasi funzione può essere chiamata sia da dentro setup(), che da dentro loop() che da dentro un'altra funzione.

Essendo queste veramente le basi ... mi permetto di suggerirti un po' di studio del linguaggio 'C' ... ci sono un'infinità di libri in giro e moltissimo anche on-line :wink:

Guglielmo

Guzzi82:
... Se non metto un loop all'interno della mi achiamata, come faccio a fare continuare l'azione indefinitamente?...

... con dei cicli di controllo "if" oppure "while" condizionati dallo stato di uno o piu flags ? ... :wink:

Ad esempio (pseudocodice) ...

... 
programma
... 

...
parte in cui imposti il valore di un flag in base all'azione da ripetere
...

if (flag1 = 1)
{
   ...
   blocco di istruzioni da continuare ad eseguire
   finche' il valore di flag1 rimane 1
   ...
}
else if (flag1 = 2)
{
   ...
   blocco di istruzioni da continuare ad eseguire
   finche' il valore di flag1 rimane 2
   ...
}
else if (flag1 = 3)
{
   ...
   blocco di istruzioni da continuare ad eseguire
   finche' il valore di flag1 rimane 3
   ...
}
else if (flag1 = 4)
{
   ...
   blocco di istruzioni da continuare ad eseguire
   finche' il valore di flag1 rimane 4
   ...
}
... e cosi via ...

Ovviamente ci sono altri sistemi, questo e' solo uno dei possibili esempi :wink:

Ok, dal tuo messaggio di prima lo avevo capito. E' in contrasto con quanto suggeritomi da altri in precedenza (o male interpretato da me) ma non è questione di colpe....

Adsso la mia "funzione" in realtà è tutto un programma che deve girare fino a che non cambio idea e glielo comunico girando il pomello dell'encoder.
La funzione in origine era in effetti un programma che stava in piedi da solo, ora l'ho "convertito" in funzione. Ovviamente al suo interno conteneva un ciclo di loop cho ora, alla luce del tuo intervento (e dei fatti...) non posso più mantenere.

Mi sembra di intuire che, avendo messo la chiamat alla funzione in un loop, questa verrà eseguita all'infinito.
Dovrei quindi tirare fuori dalla funzione le operazioni che non vanno continuamente ripetute.
Lo avevo già fatto per la dichiarazione delle variabili o l'inizializzazione del display.
Adesso mi trovo invece azioni che non posso nè tirare fuori nè lasciare dentro.
Mi spiego: prima del secondo loop (quello all'interno della funzione stessa) faccio scrivere sul monitor una schermata iniziale (00:00:00) poi, al premere di un pulsante, parte il conteggio.
Se lascio dentro questa schermata iniziale, ad ogni coclo del loop principale mi riscriverà 00:00:00 invece di proseguire col conteggio. Se la metto fuori invece andrà in controsta con le altre funzioni che non lo richiedono.

Tutto questo è assurdo e mi porta a pensare che mi stia sfuggendo qualcosa di essenziale e basilare su come si scrivono le funzioni, sui loro limiti e applicazioni.

Purtroppo nei testi consultati questa parte è fumosa e da troppo per scontato quindi ho deciso di provare a sono approdato su questi scogli.

Devo capire se riesco a tirare insieme una zattera galleggiante oppure se devo rassegnarmi al naufragio.

Scusa è ... il loop() gira sempre e siamo d'accordo, nel loop leggi l'encoder e SAI con esattezza cosa devi fare ... a quel punto, in funzione del valore del encoder e quindi di quello che sai di dover fare ... richiami la giusta funzione ...

Per il tuo contatore ...
... lo inizializzerai a 00:00:00 in un certo punto e all'avvenire di una certa condizione e poi, normalmente lo incrementerai senza riinizializzarlo.

Non mi sembra molto difficile ::slight_smile:

Guglielmo

P.S.: Rinnovo l'invito a fermarti un'attimo, studiarti i fondamenti della programmazione in 'C' e poi a riprendere in mano il tuo programma ... perché senza i concetti di base, che ti mancano completamente, NON vai molto lontano ... ::slight_smile:

Guzzi82:
Se lascio dentro questa schermata iniziale, ad ogni coclo del loop principale mi riscriverà 00:00:00 invece di proseguire col conteggio. Se la metto fuori invece andrà in controsta con le altre funzioni che non lo richiedono.

No, basta mettere quel pezzo in un if() che controlla una variabile vero/falso.

Come accennato da ete, puoi usare dei flag booleani, ovvero che possono assumere come valori solo vero e falso. Ad esempio supponiamo di averne uno globale:

boolean inizializzato;

Questo serve a tenere traccia di se la funzionalità attualmente in esecuzione è già stata inizializzata. Quando rilevi che l'encoder ha cambiato valore lo imposti a falso. Per ogni funzionalità fai quindi due funzioni, una che fa tutto quel che serve fare una sola volta, e una che viene chiamata di continuo. Esattamente come setup() e loop() in sostanza. Quindi nel loop puoi fare qualcosa tipo:

if (inizializzato == false) {
  setup_contatore ();
  inizializzato = true;
}

loop_contatore ();

Chiaro?

Il messaggio precedente era in risposta a pippo prima delle due precedenti.

Veniamo a questi.
Sui testi da leggere e le cose da imparare sono in pieno accordo. Da bravo ing mi piacerebbe conoscere tutto e tutto bene per fare le scelte giuste ma ogni ing ha due metà: quella chiara e quella oscura.
Quella chiara ci spinge a sapere e prepararci, quella oscura ad agire e basta.
Questo per me è un problema collaterale nel risolvere un problema marginale su un progetto che nulla ha a che fare con la programmazione ma solo con motori e meccanica.
Di vita ne ho una sola e tutto al 100% non si può fare.
Ovviamente le possibilità di Arduino mi appassionano altrimenti avrei già mollato tutto e speso 100€ per qualcosa di già fatto, funzionante e affidabile.
Sono già certo che qualsiasi cosa imparerò da questa esperienza servirà ad altro (un paio di cose in mente le ho già....) ciò non toglie che tutto non posso imparare e qualcosa lo devo "tentare"....
Qualche testo già l'ho messo a "scaffale" ma sull'argomento mi ha lasciato insoddisfatto. Per altri mi sto organizzando. Qualcuno mi diede tempo fa dei buoni consigli su dove cercare.

Per il ciclo "condizionato" ci avevo pensato ma devo schiarirmi le idee.

Qualcuno di voi ha visto "Terminetor genisys" ?
A furia di viaggiare nel tempo non si capisce più dove e quando stia avendo luogo l'azione.
Qui è uguale: ogni volta che "entro" nel ciclo mi perdo.

Ci va una pausa di riflessione, un caffè e anche una cucchiaiata di Nutella.

Visto il tuo codice, quello con la doppia loop().
Allora... la loop() giusta gira di continuo e in base all'encoder e a switch chiama le funzioni giuste.
Se valore==3 allora chiami cronometro() e il tuo problema è qui.
La cronometro ha una parte iniziale che vuoi eseguita solo la prima volta che con encoder vuoi il cronometro(), mentre la parte che è dentro questa seconda loop() deve essere eseguita di continuo.

Ora, la parte della loop() dentro la cronometro, togli la loop e la lasci come codice dentro la cronometro.
Visto che cronometro viene chiamata di continuo e finchè encoder è 3, quel pezzo va bene.
Quello che non va bene cosè? La prima parte, quella che da inizio cronometro() andava a loop().
Quel pezzo deve essere eseguito solo 1 volta. Quindi quel pezzo DEVE stare dentro un if() { ... }
Ma... che test facciamo nel if ?? Qui sotto la tua cronometro() che ho però tagliato ... solo come scheletro !!

void cronometro() // unica funzione attualmente implementata (più o meno...)
{
  Serial.println("visualizzo la schermata del cronometro:");
  Serial.println(page);
  if( boh )    // che test ???
  { 
    // visualizzo un cronometro sullo schermo 00:00:00  hh:mm:ss  non mi interessano decimi e centesimi
    myGLCD.setFont(BigFont);
    myGLCD.clrScr();
    myGLCD.setColor(VGA_AQUA);// cambio colore 
    ...
    myGLCD.print(":",233,170);
    //uint32_t old_ts; //questo comando l'ho copiato pari pari dall'esempio da cui mi sono ispirato, non so che faccia, a che serva e se serva. 
  }
  // ex loop
  statostart = digitalRead (pinstart);
  statostop  = digitalRead (pinstop);
  ...
  if (statostop == LOW)
  { myGLCD.setFont(BigFont);
    myGLCD.print("STOP ", 100,125);
    flag = 2;
  }
  // ex loop
}

Sono in perenne ritardo sulle risposte. Ne ho perse altre due.

Cercherò di capire anche questa sulle variabili booleane e di vedere come fare un if che skippi quello che non serve.

Due cucchiai di Nutella

grazie nid69

OT: ma non si può levare sto cavolo di limite ad 1 post ogni 5 minuti? sono in continuo ritardo! Qui siete rapidi come iltopolino messicano (ma lui mi stava sul c...)

nid69 (o devo chiamarti Aigor?) hai centrato il punto.
Quale if ci mettiamo?

Qui ci viene in aiuto il booleano: qualcosa che cambia valore solo se l'encoder si è mosso.

Caxxo! Mi tocca studiare e pensare!

Il test deve essere fatto su una variabile che vale 0 o 1 (tipo la tua flag, forse quella può valere anche 2 ?! )
Metti in cima al programma insieme alle altre variabili qualcosa del tipo

byte CronoFirst=0;

quindi nella cronometro() al posto del boh

if( CronoFirst==0 )    // che test ???
{ CronoFirst=1;

Quando entri la priva volta in quel pezzo, la prima cosa che farai è dichiarare... ueh sono entrato, CronoFirst=1 quindi non entrare più !!

Piccolo problemino. Fatto così NON farà mai più quel pezzo (finchè non spegni Arduino). Anche se porti encoder a 2 e poi ritorni a 3. Quindi per forza nei vari switch() case... che non sono 3 devi ... mettere CronoFirst=0;
Oppure semplicemente prima di switch()

if(page!=3) CronoFirst=0;   
switch (page) ...
{

P.S. buona Nutella. Passane un pò và. :grin:

ciao

Guzzi82:
... e anche una cucchiaiata di Nutella.

Guzzi82:
Due cucchiai di Nutella

Occhio che da dipendenza :wink:

ciao
pippo72

Ciao

Io uso una routine che legge l’encoder: encoder();
In essa la variabile E viene inizialmente posta a zero per azzerare il rilevamento precedente, dopodiché, se l’encoder viene ruotato, viene assegnato a E un valore che può essere 1 o -1
A ogni giro del loop() viene chiamata la routine e poi letto il valore di E: se è 0 procede; se è 1 o -1 vuol dire che l’encoder è stato ruotato in senso orario o antiorario, perciò fa quello che deve fare o salta a un’altra routine.

Per muovermi nei menu uso il pulsante incorporato nell’encoder: se viene premuto per un attimo, conferma la scelta e procede; se, invece, viene tenuto premuto per più di 1 secondo, fa altro (va a un altro menu, oppure esce).

Come si mette il codice? Dovrebbe esserci un pulsante apposito, ma non lo vedo…

Mi associo per la richiesta di rimozione del limite di un post ogni 5 minuti: non potendo modificare il mio post né rispondere a un altro, me ne vado altrove e poi (forse) tornerò… :frowning:

il pulsante apposito è il primo </>
ben venga.

Per ora ho fatto come suggerito da Aigor e rimaneggiato così il mio sketch:

// Date and time functions using RX8025 RTC connected via I2C and Wire lib
#include <UTFT.h>
#include <Wire.h>
#include "Sodaq_DS3231.h"
char weekDay[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

// inserisco i fonts che verrano utilizzati
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

UTFT myGLCD(CTE32HR, 38, 39, 40, 41);

int pinstart = 10; // digital pin   pulsante di inizio conteggio
int pinstop = 11;  // digital pin   pulsante di fine conteggio
int pinreset = 12;  // digital pin  pulsante di azzeramento

int statostart;
int statostop;
int statoreset;

unsigned long tempo_base;
unsigned long tempo_cronometrato = 0;
unsigned long tempo_congelato;
unsigned long tempo;
unsigned long centesimi;
unsigned long secondi;
unsigned long minuti;
unsigned long ore;
int flag = 1;
byte DashFirst = 0;
byte TimerFirst = 0;
byte OrologioFirst = 0;
byte CronometroFirst = 0;

int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile int encoded = 0;
volatile int status0 = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;


int page = 1;

int lastMSB = 0;
int lastLSB = 0;

void setup()
{
  myGLCD.InitLCD();// settato in orizzontale
  Serial.begin (9600);
  Wire.begin();
  rtc.begin();
  pinMode (pinstart, INPUT_PULLUP);
  pinMode (pinstop, INPUT_PULLUP);
  pinMode (pinreset, INPUT_PULLUP);
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);

  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
}

void loop()
{

  if (encoderValue != status0)
  {
    if ((encoderValue - status0) > 0) //se l'encoder è stato ruotato in senso antiorario
    {
      page = page - 1; // vai alla pagina precedente
      if (page == 0) page = 4; // le pagine sono 4, dopo la 4 c'è nuovamente la 1
    }

    else if ((encoderValue - status0) < 0) // se l'encoder è stato ruotato in senso orario
    {
      page = page + 1; // vai alla pagina successiva
      if (page == 5) page = 1; // le pagine sono sempre 4 quindi prima della 1 c'è la 4
    }

    else   // si verifica solo se le due variabili hanno lo stesso identico valore
    { // continua a non fare un bel cazzo di niente
    }


    switch (page)
    {
      case 1:
        DashFirst = 0;
        TimerFirst = 0;
        CronometroFirst = 0;
        orologio();
        break;

      case 2:
        TimerFirst = 0;
        OrologioFirst = 0;
        CronometroFirst = 0;
        dash();
        break;

      case 3:
        DashFirst = 0;
        TimerFirst = 0;
        OrologioFirst = 0;
        cronometro();
        break;

      case 4:
        DashFirst = 0;
        OrologioFirst = 0;
        CronometroFirst = 0;
        timer();
        break;

      default:
        Serial.println("QUALCOSA NON FUNZIONA");
        break;
    }
  }

  else   // si verifica solo se le due variabili hanno lo stesso identico valore
  { // persevera a non fare un bel cazzo di niente
  }


  status0 = encoderValue;
  delay(500);

}

void updateEncoder()
{
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit
  int encoded = (MSB << 1) | LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
  { encoderValue ++;
  }
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
  { encoderValue --;
  }
  lastEncoded = encoded; //store this value for next time
}




void cronometro() // unica funzione attualmente implementata (più o meno...)
{
  if (CronometroFirst == 0)
  {
    CronometroFirst = 1;
    Serial.println("visualizzo la schermata del cronometro:");
    Serial.println(page);
    // visualizzo un cronometro sullo schermo 00:00:00  hh:mm:ss  non mi interessano decimi e centesimi
    myGLCD.setFont(BigFont);
    myGLCD.clrScr();
    myGLCD.setColor(VGA_AQUA);// cambio colore
    myGLCD.setFont(SevenSegNumFont);
    myGLCD.print("00", 82, 150);
    myGLCD.print("00", 166, 150);
    myGLCD.print("00", 250, 150);
    myGLCD.setFont(BigFont);
    myGLCD.print(":", 149, 170);
    myGLCD.print(":", 233, 170);
  }


  uint32_t old_ts; //questo comando l'ho copiato pari pari dall'esempio da cui mi sono ispirato, non so che faccia, a che serva e se serva.


  statostart = digitalRead (pinstart);
  statostop  = digitalRead (pinstop);
  statoreset = digitalRead (pinreset);

  if ((statostart == LOW) && (flag < 2)) // premo il pulsante start e parte il cronometro
  {
    myGLCD.clrScr();
    DateTime now = rtc.now(); //get the current date-time
    uint32_t ts = now.getEpoch();
    tempo_base = ts;
    flag = 0;
  }

  if ((statostart == LOW) && (flag == 2))
  {
    flag = 0;
  }

  if (flag == 0)
  {
    myGLCD.setFont(BigFont);
    myGLCD.print("START", 100, 125);
    DateTime now = rtc.now(); //get the current date-time
    uint32_t ts = now.getEpoch();
    tempo_cronometrato = ts - tempo_base;  // differenza tra conteggio attuale e conteggio di partenza
    tempo = tempo_cronometrato;
    myGLCD.setFont(SevenSegNumFont);
    myGLCD.printNumI(tempo, 82, 250);
    ore = int(tempo / 3600);
    minuti = int((tempo - (ore * 3600)) / 60);
    secondi = tempo - (ore * 3600) - (minuti * 60);
    //finalmente scriviamo qualcosa sullo schermo...
    myGLCD.printNumI(ore, 82, 150, 2, '0');
    myGLCD.printNumI(minuti, 166, 150, 2, '0');
    myGLCD.printNumI(secondi, 250, 150, 2, '0');
    myGLCD.setFont(BigFont);
    myGLCD.print(":", 149, 170);
    myGLCD.print(":", 233, 170);
  }

  if (statostop == LOW)
  {
    myGLCD.setFont(BigFont);
    myGLCD.print("STOP ", 100, 125);
    flag = 2;
  }
}



void timer() //funzione non ancora implementata
{
  Serial.println("visualizzo la schermata del timer:");
  Serial.println(page);
}

void orologio() //funzione non ancora implementata
{
  Serial.println("visualizzo la schermata dell'orologio:");
  Serial.println(page);
}

void dash() //funzione non ancora implementata
{
  Serial.println("visualizzo la schermata dei dati motore:");
  Serial.println(page);
}

Adesso devo però verificarlo e non posso farlo oggi perchè non ho con me l’hardware.

Rientro a casa nel fine settimana e ci lavoro.

Grazie a tutti.

PS:
La Whinehouse quanda cantava “Rehab” si riferiva proprio alla Nutella…

Ah! Ecco! non mi appariva la barra degli strumenti!
Beh... Sapendolo, avrei anche potuto scrivere a mano 'code' fra parentesi quadre! :slight_smile:

Questa è la mia routine di lettura dell'encoder:

void encoder()
{
S=3-PINB&B00000011; // Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa,
                    // quindi faccio complemento a 3 (11)  
S^=S>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
         // ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if (S!=So && S==0) X=0;
if (X==0)
  {
  if (So==1&&S==2)
    {E=1; X=1; if(B==3)Bip();}
  if (So==3&&S==2)
    {E=-1; X=1; if(B==3)Bip();}
  if (S==0)
    {E=0; X=0;}
  So=S;  
  }
}

Non uso gli interrupt perché non mi funzionò, perciò decisi di andare avanti senza, ripromettendomi di fare ricerche successivamente. Se il loop gira velocemente, comunque, funziona.

P.s.: Ho trovato MOLTO comodo usare le schede nell'IDE (nel mio ultimo progetto ne ho 16), perché permettono di saltare in un attimo da una parte all'altra dello sketch senza dover scorrere tutto.

Qui leggo la pressione del pulsante (chiude a massa). Se è più lunga di 1 secondo:

  • Cancella il display
  • Se il Bip è attivato (B>0) fa Bip saltando all'apposita routine
  • Esce dal menu in cui si trova riavviando il loop
t1=millis();
while(digitalRead(10)==LOW) 
  {
  if(millis()-t1>1000) {lcd.clear(); if(B>0) Bip(); /*loop();*/}
  }