// Arduino **MEGA** for optical rotary encoder; plus an encoder simulator Sept 2022
// WOKWI animation : https://wokwi.com/projects/343001355413094995
/*
The first part of the program receives the quadrature signal from an optical rotary encoder
and displays its position on the serial monitor.
---------------------------------------------
If you have a 5 Volts encoder and an Arduino:
---------------------------------------------
Connect the outputs A and B of the 5 Volt encoder to the input pins 2 and 3 of the Arduino
(put resistors of 1K max in series between the pins and the wires A and B, for safety).
Do not make the connections on pins 11 and 12, nor the 2 buttons on A0 and A3.
You can delete the second part of the program, which is not used with a real encoder.
------------------------------------
If you don't have the real encoder :
------------------------------------
the second part of the program allows to simulate the quadrature function on pins 11 and 12
(these pins work like an encoder, they are controlled by the buttons).
With a real Arduino:
-------------------
Place resistors of 1K max as shown on the Wokwi diagram, to protect the pins from a programming error:
output 12 to input 2, and output 11 to input 3;
and also on the buttons, 1K max between A0 and the button, 1K max between A3 and the other button.
ATTENTION don't forget to set (prevmillis > 20) in the "additionalButtons()" function
(for Wokwi the value is 1, otherwise the reaction time of the buttons is too long).
In simulation with Wokwi:
-------------------------
The resistors are intentionally not connected, it is to indicate how to do with the real Arduino.
In case of blocking, it is sometimes necessary to stop the simulation, and restart it.
You may have noticed that English is not my usual language ;-)
*/
// ENCODER function : quadrature signal decoded with interrupt inputs 2 & 3 ----------------------------
#define INPUT_ENCOD_A 2 // *** MEGA PIN2 (***=adapt with input pin)
#define INPUT_ENCOD_B 3 // *** MEGA PIN3
#define SignalA B00010000 // *** MEGA PIN2 = PORT_E bit4 = B00010000
#define SignalB B00100000 // *** MEGA PIN3 = PORT_E bit5 = B00100000
#define SignalAB B00110000 // *** both signals
volatile int ISRencodPos; // encoder position
int encodLastPos; // previous position
byte LastPort8 = SignalA; // previous A/B state
unsigned long prevmillis; // BUTTONS debounce period
void setup(void) { //
pinMode(INPUT_ENCOD_A, INPUT_PULLUP); //
pinMode(INPUT_ENCOD_B, INPUT_PULLUP); //
attachInterrupt(digitalPinToInterrupt(INPUT_ENCOD_A), ExtInt, CHANGE);
attachInterrupt(digitalPinToInterrupt(INPUT_ENCOD_B), ExtInt, CHANGE);
Serial.begin(115200); // fast fast fast !
Serial.println(F("waiting for encoder rotation...")); //
} //
void ExtInt() { /// OPTICAL ENCODER ext interrupt pin X, Y
byte Port8 = PINE & SignalAB; // *** PINE (PORT INPUT E) ***for Mega***
LastPort8 ^= Port8; //
if (LastPort8 & SignalA) ISRencodPos++; // Rotation -> {ISRencodPos++; Sense = 1;}
if (LastPort8 & SignalB) ISRencodPos--; // Rotation <- {ISRencodPos--; Sense = 0;}
if ( Port8 && (Port8 != SignalAB)) Port8 ^= SignalAB; // (swap A-B)
LastPort8 = Port8; // mieux vaut faire court
} //
void loop(void) { /// MAIN LOOP
noInterrupts(); //
int encodPosition = ISRencodPos; //
interrupts(); //
//! ATTENTION // // Wokwi=1,real Mega=20 (ms debounce period)
//
if (encodLastPos != encodPosition && millis() - prevmillis > 5) { // when the encoder change,
encodLastPos = encodPosition; //
Serial.println(encodPosition); // print encoder position
prevmillis = millis();
} //
}