Rotary Encoder: come utilizzare un encoder con Arduino

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.

rotary encoder con Arduino

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:

rotary encoder led

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

Permanent link to this article: https://www.mauroalfieri.it/elettronica/arduino-rotary-encoder.html

50 pings

Skip to comment form

  1. […] « Rotary Encoder: come utilizzare un encoder con Arduino […]

  2. […] 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 […]

  3. […] utilizzare l’encoder, parte della descrizione dello sketch la trovi in un mio precedente articolo dedicato agli encoder che ti invito a […]

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.