Buonasera e Buon Anno.
Sto cercando di utilizzare 2 encoder rotativi sullo stesso arduino.
Dopo aver provato diverse librerie che promettevano di fare ciò con facilità, le ho abbandonate, perchè non sono abbastanza veloci e perdono parecchie letture anche con un solo encoder soprattutto se utilizzate in codice corposo con una durata del loop non trasurabile.
Finora per avere letture veloci ed accurate utilizzavo questo codice:
/***********************************************************
File name: _16_RotaryEncoderModule.ino
Description: The information of rotary encoder module has been
detected by UNO R3,and displayed in the serial monitor
When the rotary encoder turns clockwise, the angular
displacement is increased;when it turns counterclockwise,
it’s decreased.If you press the switch on the rotary
encoder, related readings will return to zero
Website: www.adeept.com
E-mail: support@adeept.com
Author: Tom
Date: 2016/06/15
***********************************************************/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define APin 2 //Set the digital 2 to A pin
#define BPin 3 //Set the digital 3 to B pin
#define Prova 14
int lastEncoded = 0;
float encoderValue = 8700;
long lastencoderValue = 0;
float frequency;
int lastMSB = 0;
int lastLSB = 0;
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("hello");
pinMode(APin, INPUT_PULLUP);//initialize the A pin as input
pinMode(BPin, INPUT_PULLUP);//initialize the B pin as input
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
pinMode(Prova, INPUT_PULLUP);
Serial.begin(9600); //opens serial port, sets data rate to 9600 bps
}
void loop()
{
Serial.println(encoderValue);
frequency = encoderValue / 100;
if (frequency < 87.00) frequency = 87.00;
if (frequency > 108.00) frequency = 108.00;
Serial.println(frequency);
lcd.setCursor(0, 1);
lcd.print(encoderValue);
lcd.setCursor(0, 2);
lcd.print(frequency);
if (digitalRead (Prova) == LOW) {
lcd.setCursor(0, 3);
lcd.print("0");
}
else if (digitalRead (Prova) == HIGH)
{
lcd.setCursor(0, 3);
lcd.print("1");
}
}
void updateEncoder() {
int MSB = digitalRead(APin); //MSB = most significant bit
int LSB = digitalRead(BPin); //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
}
A questo punto ho collegato un secondo encoder ai pin 18 e 19 ed ho copiato il codice necessario modificandone le variabili per non duplicarle ed aggiungendo i necessari riferimenti per i pin e gli interrupt.
A tal proposito, consultando il pinout del MEGA, ho notato che gli interrupt sui pin 2 e 3 sono indicati come 4 e 5 e quindi, negli attachInterrupt corrispondenti, li ho sostituiti ma, così facendo, l'encoder corrispondente non funziona; viceversa rimettendo 0 e 1 il valore varia correttamente.
A ricerca di conferme, ho aperto il file pins.h del MEGA, e stranamente, nella definizione degli interrupt, sembra che effettivamente sui pin 2 e 3 vi siano gli interrupt 0 e 1: ora, visto che anche il pinout dell'AtMega 2560 li riporta come 4 e 5, mi piacerebbe capire se c'è un errore da qualche parte o, se chi ha scritto il file, li ha deliberatamente assegnati così magari per compatibilità con l'UNO.
P.S.
Nei giorni scorsi si era già parlato di encoder che perdevano passi: se l'autore del topic non ha risolto o volesse provare senza librerie, può ripulire il codice riportato, utilizzando come valore utile encoderValue (il resto sono mie aggiunte per utilizzarlo nella sintonia dei moduli radioFM)