Uso di un rotary encoder su Mega per selezione funzioni

Buonasera,
All'interno di un progetto più ampio voglio determinare l'azione da compiere in funzione del movimento di un encoder rotativo.
La mia intenzione è più semplice di quanto si possa pensare:
Se il valore encoder è in aumento allora esegui la funzione n+1
Se il valore encoder diminuisce allora esegui la funzione n-1
Nel mio caso le funzioni sono 5 ma potrebbero essere di più.
Ho fatto la prima esperienza con un encoder (su Arduino Mega) provando lo sketch suggerito al link qui sotto:

Per funzionare funziona ma mi da un valore dell'encoder e non una sua variazione.
Sembra banale (e forse lo è) ma la variazione altri non è che una differenza tra valore al passo n e valore al passo n-1
Quindi registro in una variabile 'stato0' lo staro attuale e, al passo successivo, la sottraggo al valore attuale ottenendo, in teoria, la differenza.
Seè positiva chiamo la funzione(n+1), se negativa la funzione(n-1)
Tutto da ABC
Peccato che tale differenza sia sempre…nulla.
Ovunque o vada a memorizzare il 'valore precedente' dell'encoder, al momento di confrontarlo con l'attuale, questi sono identici.

Perchè?

Ritengo che sia una conseguenza dell'uso degli interrupt che non hanno alcuna relazione con i passi del ciclo principale.
Degli interrupt so praticamentenulla, è la prima volta che li uso e solo perchè sto copiando un pezzo di codice di altri.

Quali altre opzioni ho?
Male che vada metto 4 pulsanti per una selezione diretta delle chiamate ma mi sembra di arrendermi!

Grazie.

Riccardo

Premesso che c'è sicuramente un errore nel tuo codice (... che purtroppo non hai messo e quindi possiamo solo immaginare), io vedo un altro problema ...

L'encoder è gestito ad interrupt, quindi piuttosto rapido e sensibile ... se tu hai chiamato la funzione 1 (quindi il valore attuale è 1) e giri per chiamare la funzione 5 ... mano mano che giri passi per la 2, la 3, la 4 ed infine la 5 ... ovvero, invece di chiamare la 5 le chiami TUTTE fino alla 5 ::slight_smile:

Ti va bene così ? ? ? Perché altrimenti la cosa si complica e occorre tenere anche conto del fattore "tempo", ovvero ... dopo quanto tempo che ti sei fermato da girare l'encoder il valore è buono e la funzione può essere chiamata ?

Guglielmo

Buona seta Gulielmo e ben ritrovato.
Il codice l'ho su un floppy da 5"1/4 e nel tablet non riuscivo a infilarlo. Hanno quelle presine così piccole e anguste!
Domani in ufficio accendo il mio M24 e ci provo.

Se c'è un errore lo troverò/troveremo.

A me non serve sapere il valore o di quanto è cambiato, mi basta vedere che è cambiato. Basta che valoreAttuale e valorePrecedente siano diversi.
Posso addirittura fare a meno del senso di variazione, devo girare 4 pagine, se andare indiwtro di una significa andare avanti di tre...poco disturba.

Riccardo

Guzzi82:
A me non serve sapere il valore o di quanto è cambiato, mi basta vedere che è cambiato. Basta che valoreAttuale e valorePrecedente siano diversi.
Posso addirittura fare a meno del senso di variazione, devo girare 4 pagine, se andare indiwtro di una significa andare avanti di tre…poco disturba.

Se è solo per scorrere, allora basta rilevare se il valore seguente è > o < del precedente e andare avanti o indietro …
… quando uno smette di girare si ferma :smiley:

Guglielmo

Mi piacerebbe sapere che versione dell'ide di arduino possa girare sopra ad un Olivetti M24.
Comunque aspettiamo il codice.

speedyant:
Mi piacerebbe sapere che versione dell'ide di arduino possa girare sopra ad un Olivetti M24.

Quella scritta per girare in RomBasic :stuck_out_tongue: :smiley:

Scherzi a parte ... Guzzi82, come gia detto da Guglielmo, bisogna che inserisci nel tuo sketch anche un timer che esegua la funzione selezionata solo dopo un certo tempo che l'encoder si e' fermato ... oppure, piu semplicemente, usare un'encoder con pulsante ... ce ne sono diversi modelli, hanno un pulsante in asse con l'asse di rotazione, che si attiva premendolo, e si usano di solito per fare quelle selezioni, uno ruota finche' ha selezionato quello che gli interessa, poi preme per confermare ... esempio: http://www.ebay.com/itm/12mm-Rotary-Encoder-Push-Button-Switch-Keyswitch-Electronic-Components-Effective/231410073065?_trksid=p2047675.c100005.m1851&_trkparms=aid%3D222007%26algo%3DSIC.MBE%26ao%3D1%26asc%3D35624%26meid%3D6ee6712b7e37418dba5ef235850416cb%26pid%3D100005%26rk%3D2%26rkt%3D6%26sd%3D261537203134 , o un qualsiasi altro simile ...

l'encoder è già di quelli a pulsante ma il mio scopo è talmente banale che non credo sia il caso di attivarlo.
Mi basta girare delle pagine sul display, non sono 1000, sono solo 4. Se anche l'impulso non fosse preciso e se ne girassero 2 per sbaglio....faccio un altro giro.
Potrei anche usare un solo pulsante ma credo che ricadrei nello stesso problema di adesso: non riconoscere lo stato in due momenti differenti.

A breve posto lo sketch appena la carbonella sotto l'Olivetti si è accesa.
Prima devo scoprire come inserirlo nella modalità corretta senza essere preso a calci.

Ecco il codice,
qui c’è anche l’utilizzo di un led comandato dal valore dell’encoder, era giusto per farmene qualcosa di quel numerello…

la variabile “status0” assume il valore di “encoderValue” a fine ciclo e mi aspetterei che, al ciclo successivo, avesse un valore differente di quello precedente…
non è così.
Aggiornamento “istantaneo”?
Adesso provo a metterci un delay…

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 led = 4;

int lastMSB = 0;
int lastLSB = 0;
 
void setup() {
  Serial.begin (9600);
  pinMode(led, OUTPUT);
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
 
}
 
void loop(){
  
  Serial.println(encoderValue); 
   Serial.println("--------------"); 
  Serial.println(status0); 
   analogWrite(led, encoderValue/8);
  status0 = encoderValue;
}
 
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
}

Ok.
era proprio solo questione di velocità.
Basta inserire un ritardo ed ecco che magicamente i due stati sono distinti, almeno per quel tempo.
Ho fatto accendere il led quando gli stati sono differenti e spegnere quando sono uguali.
Per 200 millis il led resta acceso.
Probabilmente quando stenderò l’intero programma saranno sufficienti le operazioni in esso comprese a “generare il ritardo” necessario per “vedere” il cambiamento di stato ovvero la rotazione.
Oppure introdurrò qualche variabioe che rimane costante tra due cambiamenti di stai successivi…
Qualcosa mi invento

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 led = 4;

int lastMSB = 0;
int lastLSB = 0;
 
void setup() {
  Serial.begin (9600);
  pinMode(led, OUTPUT);
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
 
}
 
void loop(){
  
  Serial.println(encoderValue); 
   Serial.println("--------------"); 
  Serial.println(status0); 
   
   if(encoderValue != status0) 
   {analogWrite(led, 100);}
   else
    {analogWrite(led, 0);}
   
   status0 = encoderValue;
  delay(200);
  
}
 
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
}

Grazie per l’attenzione.

@formicaveloce: se vuoi ti passo l’IDE per 8086 in GW-Basic… Però contiene i “go to”…

Uhm ... forse non ho capito io, ma ... il tuo encoder e' uno di quelli con gli scatti meccanici ? (nel senso che ha delle posizioni fisse, non quelli che girano liberamente) ...

Se e' cosi, perche' non usi un solo interrupt, e non ti limiti a comparare lo stato del secondo canale all'interno dell'interrupt ?

Cerco di spiegarmi meglio, scusa se dico cose strane, ma non sono un programmatore ... pero', gli encoder a scatti, hanno una ben precisa condizione delle uscite, quando sono nelle posizioni "ferme" degli scatti, ed un ben preciso stato delle due uscite nel momento in cui cambiano mentre li ruoti ... quindi, in teoria (programmatori, correggetemi se sbaglio), poniamo che le uscite dell'encoder siano entrambe alte a "riposo" (se sono basse, basta invertire la logica) ... se attacchi un'interrupt all'uscita 1 e lo leggi quando va basso (falling), ed in quel momento la routine di interrupt compara lo stato dell'uscita 1 con quello dell'uscita 2, se entrambe sono identiche, stai girando in un senso, se sono diverse, stai girando nell'altro, quindi sempre in teoria, dovrebbe essere sufficente infilare nella routine interrupt una cosa tipo "if A = B incrementa il contatore ELSE decrementa il contatore" ...

... o sto semplificando troppo e mi sfugge qualcosa ?

Probabilmente hai ragione.
sono io che sto saltando a piè pari dei passaggi importanti nell mia "preparazione" in materia.
Per raggiungere il mio scopo sto aggirando alcuni problemi sfruttando degli esempi preconfezionati senza analizzarli in profondità. Sto facendo una pista per le biglie in spiaggia con un bulldozzer? forse si.
Il mio progetto prevede la lettura di parecchi sensori, alcuni dei quali richiedono dei circuiti dedicati che devo costruire e poi tarare. Mi sto concentrando su questo.
Come funiona un encoder....passa in secondo piano. Forse sbaglio.
Devo girare tra 4 pagine diverse su un display. Ho pensato che un encoder a scatti fosse un buon sistema.
Potevano esserlo anche 4 pulsanti dedicati.
Forse un giorno le pagine saranno 5 o 6, ecco che l'encoder era più versatile.
Torno ad ammettere che non mi sono documentato più di tanto.
Ho molte risorse (uso un Mega), se ne spreco un po' mi va bene ugualmente.
So che non è bello ma preferisco raggiungere lo scopo piuttosto che perdermi nei dettagli.
Poco etico, poco elegante.... verissimo. Non è nemmeno il mio stile nelle cose ma si vive una volta sola, il tempo è poco e ho tante altre cose al fuoco.
Arduino è un mezzo per costruire un pezzo di un mio progetto in tutt'altro settore.

Un appassionato di acquari salati di barriera può usare Arduino per illuminazioni, fasi lunari, moto ondoso, controllo del pH e del reattore di calcio..... ma, quando tutto funziona, vuole godersi i suoi coralli e i suoi gamberetti, i suoi anemoni e le uova dei suoi pagliacci. Non gli importa nulla se ha usato il 90% delle risorse del suo processore quando, ottimizzando, poteva usarne il 40%.

Onore e merito a chi si specializza, senza di loro niente progresso.

Scusate il pistolotto di autogiustificazione della mia ignoranza.

Giuro che mi sto documentando!

Riccardo

Etemenanki:
ferme" degli scatti, ed un ben preciso stato delle due uscite nel momento in cui cambiano mentre li ruoti ...

Gli encoder meccanici sono dei piccoli bastardi :slight_smile:
Mettendo da parte le complicazioni date dai rimbalzi, e non sono poche, c'è il fatto che nelle posizioni di fermo i due canali possono essere entrambi a 1 oppure a 0, in pratica durante la rotazione tra due posizioni di fermo il canale A cambia stato a circa 1/3 della distanza angolare dal punto di fermo e il canale B fa la stessa cosa dopo circa 2/3 della distanza angolare.
Quanto sopra ci porta alla condizione di avere 2 cambi di stato per ogni scatto, due scatti sono un ciclo completo dei due canali, con cambio dei bit secondo il codice gray, cambia un solo bit per volta.
Solitamente gli encoder meccanici si gestiscono tramite un singolo interrupt su uno specifico cambio stato, p.e. da 0 a 1, con l'XOR sul secondo canale che fornisce la direzione, in pratica quando si avvia l'interrupt si somma 1 al contatore della posizione e a seconda del risultato del XOR si setta il segno negativo o positivo.
Esempio pratico, ipotizziamo di usare l'interrupt sul fronte positivo del canale A e la condizione di partenza per A e B è 0.

Rotazione CW
0 0 -> condizione iniziale
0 1 -> inizio rotazione e interrupt, l'XOR vale true pertanto sommo 1 al contatore della posizione.
1 1 -> secondo step della rotazione, nessun interrupt, sono arrivato al fermo successivo.

Rotazione CCW
0 0 -> condizione iniziale
1 0 -> inizio rotazione, nessun interrupt.
1 1 -> secondo step della rotazione e interrupt, l'XOR vale false pertanto sommo -1, sono arrivato al fermo successivo.

Attenzione che non tutti gli encoder meccanici funzionano in questo modo, vale per la stragrande maggioranza però ci sono encoder meccanici che cambiano stato allo stesso modo degli encoder ottici, ogni posizione di fermo cambia solo un bit, si tratta di modelli abbastanza costosi.
Poi ci sono gli encoder capacitivi con ghiera di stop che funzionano come gli encoder ottici però hanno le posizioni di fermo, dato che costano meno di quelli ottici sono utilizzati sugli apparati dove serve una buona risoluzione, p.e. 50 step rotazione, senza salire troppo con i costi.

Uffa!!
Mi costringete a pensare!!
Me l’avevano detto che la magia ha sempre un prezzo…

Ok. Studierò gli encoder e gli interrupt.
Purtroppo di quanto scritto da te ho capito la metà per mancanza di “basi”

Il problema dei rimbalzi però l’ho già verificato con il mio led che testimonia il passaggio di stato. A volte sfarfalla.

Per completezza di informazione e per ulteriore semplificazione, io posso anche rinunciare a determinare il senso di rotazione.

Ancora grazie

astrobeed:
...
Quanto sopra ci porta alla condizione di avere 2 cambi di stato per ogni scatto, ...

Si, ovvio, il mio ragionamento semplificava la cosa, presumendo che ad ogni scatto lui volesse fare +1 o -1 secondo il verso di rotazione (i problemi di rimbalzo si risolvono con due reti RC ;)) ...

Pensavo, dato che il cambio di stato fra condizione di "riposo" (fermo sullo scatto) e rotazione di, ad esempio, canale A, c'e' sempre ad ogni scatto, e che quando giri in un senso nel momento in cui A diventa 0 B e' sempre a 0, mentre quando giri nell'altro nel momento in cui A diventa 0 B e' sempre 1, (ovviamente, se invece di essere entrambi alti a riposo sono entrambi bassi, si inverte la logica, ma la sequenza c'e' comunque), fosse possibile semplificare in quel modo all'interno del ciclo di interrupt, contando ovviamente solo uno dei due passaggi di stato (perche' tanto ti serve un solo incremento o decremento per ogni scatto), quello che cambia rispetto allo stato di riposo, controllandolo con un solo interrupt ed un semplice if - else ... In fondo, avere una digitalread ed un'if soltanto nel ciclo interrupt dovrebbe portare via pochissimo tempo al resto dello sketch ...

Dici che non funzionerebbe ?

per il problema dei rimbalzi ti prego di fornirmi uno schemino, su carta del formaggio scannerizzata, di come risolveresti.
So di chiedere molto e sono consapevole di quanto mi stia abbassando a fare questa richiesta!

Per il codice con singolo interrupt.... ragioniamoci

nel "mio" (grazie Mr Alfieri) codice la parte di lettura dei due canali è:

int MSB = digitalRead(encoderPin1); //MSB = most significant bit
int LSB = digitalRead(encoderPin2); //LSB = least significant bit

non ho idea di quale sa la logica dietro ai nomi usati per le variabili, sono colpevole di avere copiato.

diciamo che prendo solo la prima riga e lo stato del canale A lo leggo sul encoderPin1 (che è il pin 2 del Mega)

all'interno del main lo confronto con quello che fino ad adesso ho chiamato "stato0" e verifico se sono = oppure !=.

se sono = non faccio nulla
se sono != faccio qualcosa

proviamo così.

Non ho carta da formaggio, mi spiace ma dovrai accontentarti di uno schemino disegnato con Eagle :stuck_out_tongue: :smiley:

Per i rimbalzi, e’ lo stesso principio dei debounce dei pulsanti … puoi usare uno dei sistemi in allegato, secondo se usi contatti verso massa con resistenze di pullup, oppure contatti verso il positivo con pulldown (quelo dipende da come hai cablato tu l’encoder)

Per la routine, devo improvvisare … come ho detto, non sono un programmatore, e poi al momento non ho nulla con cui testare alcuno sketch (ho un paio di schede, ma sono impegnate su un paio di prototipi che sto collaudando per lunghi periodi, e nessuna libera) … cosi ad occhio, pensavo di fare una cosa del genere … prima ovviamente assegnare due pin di ingresso digitale ai due canali dell’encoder, chiamiamoli “pinA” e “pinB”, usando per pinA uno dei pin di interrupt, diciamo il 2 per avere l’interrupt0 se stai usando una uno, ed anche una variabile da incrementare e decrementare, chiamiamola “valore” … ed agganciare appunto un’interrupt al pinA, una cosa tipo “attachInterrupt(0, contatore, FALLING);” o qualsiasi sia la sintassi corretta (questo ovviamente supponendo che i tuoi due pin dell’encoder siano alti quando e’ fermo sulle tacche, se invece l’hai connesso in modo opposto, dovra’ essere “RISING” … “contatore” e’ un nome qualsiasi della routine da richiamare) … poi nella routine contatore ci metti qualcosa di simile:

void contatore()
{
   if (digitalRead(pinA) == digitalRead(pinB))
   {
      if (valore < 3)
      {
         valore++;
      }
      else
      {
         valore=0;
      }
   }
   if (digitalRead(pinA) != digitalRead(pinB))
   {
      if (valore > 0)
      {
         valore--;
      }
      else
      {
         valore = 3;
      }
   }
}

Poi in base a quanto vale la variabile “valore”, fai quello che ti serve con il resto dello sketch … Ho messo due cicli if-else di controllo separati nella routine dell’interrupt, perche’ hai detto che deve andare da 0 a 3, cioe’ 4 stati, corrispondenti a 4 azioni, o pagine, o quello che vuoi … in questo modo il valore dovrebbe essere sempre compreso fra 0 e 3, e ripartire dall’estremo opposto quando viene superato in un senso o nell’altro … se servisse solo un’incremento o decremento libero, senza controllo del minimo e massimo, basterebbe un solo ciclo if - else, ad esempio … pero’ devi provarlo tu se vuoi, adattandolo ai nomi delle tue variabili ed al resto del tuo sketch, come ho detto, non lo posso provare, e l’ho scritto al volo … ed inoltre puo essere probabilmente migliorato, ma semmai qui lascio parlare i programmatori veri :wink:

Grazie per quanto sopra.
Non l'ho ancora analizzato.
Nel frattempo avevo provato nel seguente modo:

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

int lastMSB = 0;
int lastLSB = 0;
 
void setup() {
  Serial.begin (9600);
  pinMode(led, OUTPUT);
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
 
}
 
void loop(){
  
  Serial.println(status1); 
   Serial.println("----"); 
  Serial.println(status0); 
   
   if(status1 != status0) 
   {analogWrite(led, 100);}
   else
    {analogWrite(led, 0);}
   
   status0 = status1;
  delay(1000);
  
}
 
void updateEncoder()
{
  int MSB = digitalRead(encoderPin1);
  if (MSB = HIGH) {status1=1;}
  else {status1=0;}

   
}

ma non funziona.

evidentemente la "updateEncoder" non può essere usata mutilata.

Adesso analizzo quello che mi hai scritto e guardo l'allegato.

Io ho sempre della carta del formaggio o delle tovagliette da bar di carta sulle quali fare schemi al volo....

Ho guardato l'allegato.
Avendo settato i pin dell'encoder a pullup, usiamo il primo schema.
una resistenza in serie al contatto con un condensatore in parallelo tra pin e gnd.
Come diceva quello: "Si può fare!"

Dovrò fare lo stesso sui pulsanti del cronometro e del timer che sto realizzando.
Sono 2 delle famose 4 pagine di questo progetto:
Visualizzatore di ora e data
Cronometro
Timer
Pagina con i dati vitali del motore (temperatura aria, olio, acqua, gas di scarico, pressione olio, carburante, turbina e, in fine, AFR )

Ebbene si, è un pannellino per un auto. Display da 3.2"....

Eccomi sono ritornato sul mio progetto.
L’ho trascurato qualche settimana ma adesso andiamo avanti un pezzetto.
Ho “accettato” di usare il codice che avevo copito anche se ridondante. Capito che bastava introdurre un ritardo (la funzione loop era praticamente vuota) per leggere e confrontare le variazioni di posizione dell’encoder, adesso voglio usarle come discriminante per scegliere la azione da compiere.
Le azioni saranno essenzialmente 4 ovvero andare, a rotazione, su una delle 4 pagine del mio display. Ad ogni pagina corrisponde un pezzo di codice per fare comparire dati diversi.
In questa fase poco conta che cosa si farà nelle varie pagine, voglio solo usare l’encoder per selezionarle.

Se sono qui a scriverne ovviamnte non è per tediarvi ma perchè mi sono intoppato nuovamente.

Io ho il valore dell’encoder al passo attuale e quello al passo precedente.
Se la loro differenza è negativa (rotazione oraria dell’encoder) incremento il contatore delle pagine di 1
se la differenza è positiva (rotazione antioraria dell’encoder) il contatore delle pagine scnde di 1
Poichè le pagine sono solo 4, quando il contatore raggiunge il valore 5 gli viene assegnato d’ufficio nuovamente il valore 1, se scende a 0 invece torna a valere 4. Totale rotazione.

Bene, fatto lo spiego, arriaviamo all’intoppo.
Nello sketch che allego hoo voluto stampare a monitor seriale i 4 dati base: valore encoder attuale, precedente, loro differenza, contatore delle pagine.
Ho poi messo altri 2 campi per capire, come debug, in quale ramo del ciclo “if else” mi stavo infilando.
Cosa succede?
I valori dell’encoder variano in modo coerente, la loro diffrenza pure (pare ovvio), il valore della pagina (la variabile si chiama “page”) invece non varia come deve:
Al primo ciclo ha il valore 1 che gli assegno quando la dichiaro cone int.
Se non tocco l’encoder resta tutto immutato.
se ruoto l’encoder…idem
Sembrerebbe non accadere alcuna delle condizioni del ciclo if
invece non è così: le altre due cose che faccio scrivere a monitor sono proprio all’interno del ciclo e vengono stampate al momento giusto.
Sia che ruoti in un senso che nell’altro, il ciclo viene rispettato e la variabile “page”, variata proprio all’interno del ciclo, assume il giusto valore.
Purtroppo al ciclo successivo tornaad assumere il vlore iniziale.
Io non riesco a trovare alcun punto in cui la variabile debba essere resettata al valore iniziale. Il codice è di poche righe ed è quasi possibile fare un debug manuale!
Mi chiedo se sia veramente tonto o se non sia ncora “colpa” dell’uso degli interrupt che mi frega. Come se facessero uscire dal ciclo resettando i valori.
So che l’ho detta male, non vogliatemene…

Questo il codice

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() {
  Serial.begin (9600);
 
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
 
}
 
void loop(){


   Serial.println("--------------");
    Serial.println(encoderValue); 
    Serial.println(status0); 
    Serial.println(encoderValue-status0);
    Serial.println(page); 
   Serial.println("+++++++++++++");
  
   if ((encoderValue-status0)>0) //se l'encoder è stato ruotato in senso antiorario
    {
      page = page-1; // vai alla pagina precedente
    Serial.println("antiorario!!!"); // serve a verificare se questa evenienza è accaduta
    Serial.println(page);  // vediamo subito il valore che assume la variabile
    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
    Serial.println("orario!!!"); // serve a verificare se questa evenienza è accaduta
    Serial.println(page);  // vediamo subito il valore che assume la variabile
    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
      Serial.println("nessuna rotazione!!!"); // serve a verificare se questa evenienza è accaduta
      Serial.println(page);  // vediamo subito il valore che assume la variabile
      }
   status0 = encoderValue;
 delay(1500);
  
}
 
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
}

ho messo un sacco di commenti, spero che qualcuno abbia il coraggio di entrarci.

qui copioincollo quanto appare sul seriale (i commenti in rosso ovviamente li ho aggiunti qui!):

--------------
0 valore dell’encoder attuale
0 valore dell’encoder precedente
0 differenza tra i due valori
1 valore della variabile page
+++++++++++++
nessuna rotazione!!! l’encoder non è stato toccato
1 il valore di page non viene variato
--------------
-4 ho girato un passo quindi l’encoder cambia valore
0 il valore precedente non cambia
-4 ha loro differenza è negativa
1
+++++++++++++
orario!!! questa scritta testimonia che siamo entrati nel ramo giusto del ciclo if
2 coerentemente page si incrementa di 1
--------------
-4 non ho più mosso nulla quindi questo valore resta invariato rispetto al passo precedente
-4 ecco che il passo precedente si è aggiornato alla variazione
0 coerentemente la differenza dei valori è nulla
1 la variabile page però non ha assunto il valore 2 che avrebbe dovuto
+++++++++++++
nessuna rotazione!!!
1

forse che la variazione di “page” nel ciclo if else venga vista come variabile locale e non venga riconosciuta fuori dal ciclo? Se si, che fare?

Grazie.

:o :o :o ... guarda che le comparazioni per uguaglianza, in 'C' si fanno con == NON con = che è una assegnazione !!!

Correggi gli IF ...

Guglielmo