In questi giorni ho ricevuto da un appassionato lettore del Blog: “Cosimo” un encoder rotativo ( Rotary encoder ) da testare e inserire in un progetto più articolato.
Prima di cimentarmi con il progetto vero e proprio ho preferito fare dei test con l’encoder e qualche sketch per Arduino. Degli encoder hai già letto nell’articolo Rover 5: usare l’encoder, in cui hai analizzato il tipo di encoder presente nel Rover5, usato in altri progetti, e la teoria dei 90° di differenza tra le onde quadre presenti sui 2 pin dell’encoder stesso.
Ho eseguito due, entrambi si basano sull’uso degli interrupt di Arduino e prendono spunto da questo esempio di codice ben fatto: Rotary Encoder + Arduino puoi tuttavia trovare validissimi esempi anche nel Playgroung ufficiale Arduino.
Il primo sketch del Rotary Encoder
fa uso del Rotary Encoder e di un solo led ( collegato al pin 5 PWM ). I pin dell’encoder sono connessi rispettivamente ai pin 2, Gnd e 3 di Arduino, questo permette all’encoder di funzionare correttamente sfruttando gli interrupt 0 ed 1 dell’Arduino Uno. Il pin centrale va connesso a massa.
int encoderPin1 = 2; int encoderPin2 = 3; int ledPin1 = 5; // PWM volatile int lastEncoded = 0; volatile long encoderValue = 0; long lastencoderValue = 0; int lastMSB = 0; int lastLSB = 0; void setup() { Serial.begin (9600); pinMode(encoderPin1, INPUT); pinMode(encoderPin2, INPUT); pinMode(ledPin1, OUTPUT); digitalWrite(encoderPin1, HIGH); //turn pullup resistor on digitalWrite(encoderPin2, HIGH); //turn pullup resistor on analogWrite (ledPin1,LOW); attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); } void loop(){ Serial.println(encoderValue); if ( encoderValue > 255 ) { encoderValue = 255; } if ( encoderValue < 0 ) { encoderValue = 0; } analogWrite(ledPin1,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 }
il punto principale dello sketch è senza dubbio la funzione updateEncoder() che si occupa di leggere i valori dell’encoder e incrementare o decrementare la variabile encoderValue in funzione del verso di rotazione del Rotary Encoder.
I pin 2 e 3 di arduino puoi utilizzarli anche come interrupt, ossia assegnare loro una funzione ogni colta che lo stato cambia, questo avviene alle linee 24-25 in cui puoi leggere il comando attachInterrupt( interrupt, funzione, metodo) dove interrupt è 0 per il pin 2 e 1 per il pin 3 di Arduino, la funzione è quella che vuoi sia invocata e il metodo indica in quale caso debba essere chiamata la funzione, nell’esempio usi CHANGE ossia quando il pin 2 o il pin 3 passa da HIGH a LOW e viceversa.
il controllo del led avviene nella funzione loop() in cui alle linee 31-32: definisci i limiti letti dall’encoder rispetto ai valori che puoi inviare al pin PWM 5 mediante il comando analogWrite() e alla linea 34: imposti il valore sul pin corrispondente.
Il secondo Sketch del Rotary Encoder
Il secondo esempio è un po’ più complesso in quanto oltre a rilevare i valori dell’encoder fa uso di quattro led che si illuminano in sequenza al crescere del valore letto dall’encoder.
In questo caso il Rotary Encoder è utilizzato quasi come un potenziomentro in cui i valori vanno da 0 a 1023, quindi potresti utilizzare un comune potenziometro per ottenere lo stesso risultato con lo svantaggio che non puoi ottenere range differenti, mantre con un Rotary Encoder puoi arrivare a valori infiniti è solo legato ai limiti che imposti nello sketch.
I led sono collegati rispettivamente ai pin 5,6,9 e 10 di Arduino:
Ecco l’esempio:
int encoderPin1 = 2; int encoderPin2 = 3; int ledPin1 = 5; // PWM int ledPin2 = 6; // PWM int ledPin3 = 9; // PWM int ledPin4 = 10; // PWM volatile int lastEncoded = 0; volatile long encoderValue = 0; long lastencoderValue = 0; int lastMSB = 0; int lastLSB = 0; int ledPin = ledPin1; int value = 0; void setup() { Serial.begin (9600); pinMode(encoderPin1, INPUT); pinMode(encoderPin2, INPUT); pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(ledPin3, OUTPUT); pinMode(ledPin4, OUTPUT); digitalWrite(encoderPin1, HIGH); //turn pullup resistor on digitalWrite(encoderPin2, HIGH); //turn pullup resistor on analogWrite (ledPin1,LOW); analogWrite (ledPin2,LOW); analogWrite (ledPin3,LOW); analogWrite (ledPin4,LOW); attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); } void loop(){ Serial.print(ledPin); Serial.print( " - " ); Serial.println(encoderValue); if ( encoderValue > 1024 ) { encoderValue = 1024; } if ( encoderValue < 0 ) { encoderValue = 0; } if ( encoderValue > 0 && encoderValue < 255) { ledPin =ledPin1; value = encoderValue; } if ( encoderValue > 256 && encoderValue < 512) { ledPin =ledPin2; value = map( encoderValue,255,512,0,255); } if ( encoderValue > 513 && encoderValue < 767) { ledPin =ledPin3; value = map( encoderValue,512,767,0,255); } if ( encoderValue > 768 ) { ledPin =ledPin4; value = map( encoderValue,767,1024,0,255); } if ( value > 250 ) { value = 255; } if ( value < 5 ) { value = 0; } analogWrite(ledPin,value); } 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 }
Ti sei accorto che sono state aggiunte delle linee:
linee 03-06: definisci i pin a cui sono collegati i 4 led;
linee 24-27: imposti i pin dei led come pin di tipo OUTPUT con il comando pinMode(pin,Mode);
linee 31-34: invia il valore LOW o 0 a ciascun pin a cui è connesso un led in modo da tenerli spenti all’avvio;
A questo punto la lettura dei valori dell’encoder rotativo ( Rotary Encoder ) la lasciamo immutata alla funzione updateEncoder() invocata dagli interrupt di Arduino, e ci concentriamo sulla funzione loop():
linee 46-47: definisci i limiti dei valori letti dall’encoder per i quali decidi di accentere il led, essendo 4 led ho deciso di usare solo i primi 1023 valori ma potresti decidere di utilizzare 4000 valori per ottenere un passaggio più lento della luminosità;
linee 49-52: sono il cuore dell’effetto ottenuto sui led, eseguendo l’operazione 1024 ( 0-1023) diviso 4 ottieni 1024/4 = 255 per cui i range saranno di 255 in 255: 0-255, 256-512, 513-767, 768-1023. Vai quindi a scrivere le 4 condizioni:
se il valore dell’encoer è compreso tra 0 e 255, accendi il led connesso al pin 5 inviando un valore pari a quello dell’encoder stesso;
se il valore dell’encoer è compreso tra 256 e 512, accendi il led connesso al pin 6 inviando un valore mappato su 0-255, ricorda che il PWM può inviare solo valori da 0 a 255;
se il valore dell’encoer è compreso tra 513 e 767, accendi il led connesso al pin 9;
se il valore dell’encoer è compreso tra 768 e 1023, accendi il led connesso al pin 10;
Nell’ultima condizione ti sarai accorto che manca il limite superiore ( 1024 ) in realtà questo limite è impostato alla linea 46;
linee 54-55: definisci i limiti da passare al pin PWM, serve come precauzione in caso di essrori presenti nei calcoli o nelle linee precedenti il valore passato al led è sempre compreso nel suo range. In particolare noti che la prima condizione non dice value > 255 ma value > 250 e la seconda non si rapporta a 0 ma a 5 serve ad introdurre una tolleranza tra i valori calcolati nelle linee 49-52 ed il valore realmente passato al’analogWrite() in corrispondenza degli esteremi 0 e 255;
linea 57: invii finalmente il valore PWM al pin corrispondente.
Per comprendere meglio quello che hai realizzato ho prodotto un breve filmato che ti aiuta a capire come funzionano i due sketch:
Buon divertimento !!!
Prima di inserire un commento, per favore, leggi il regolamento
50 pings
Skip to comment form
[…] « Rotary Encoder: come utilizzare un encoder con Arduino […]
[…] trattato in passato l’argomento encoder rotativi ( puoi leggerlo qui ) per spiegare la teoria con la quale è possibile leggere il valore di rotazione ed il […]
[…] utilizzare l’encoder, parte della descrizione dello sketch la trovi in un mio precedente articolo dedicato agli encoder che ti invito a […]