I then wrote up a sketch to read the encoder. It is implemented on a UNO and uses direct access to port registers to speed up the interrupt handler. A pin change interrupt is used to trigger on each edge of both of encoder waveforms, giving a resolution of 4 x the slot count (1/1764 of a rotation). The sensor gives a nice clean wave with its inbuilt hysteresis circuit, so noise and 'bounce' are not a concern.
This sketch just sends raw position count. Shaft angle and RPM will be added later.
/* *******************************
** WOOTER'S MOTOR CONTROLLER **
** **
*******************************
*/
#include <avr/interrupt.h>
#include <Arduino.h>
#include <stdint.h>
#include <stdbool.h>
volatile uint8_t OldState = 0;
volatile int32_t Position = 0;
volatile bool InvalidInc = 0;
const int8_t IncArray[4][4]= {0,-1,1,2,1,0,2,-1,-1,2,0,1,2,1,-1,0};
void setup() {
Serial.begin(19200);
pinMode(8, INPUT);
pinMode(9, INPUT);
PCICR |= 0b00000001; // "PCIE0" PORT B pin change interrupt enabled
PCMSK0 |= 0b00000011; // Mask for "PCINT0 & PCINT1" pins set enabled -> D8-D9 will trigger interrupt
}
void loop() {
delay(100);
Serial.println(Position,DEC);
if (InvalidInc) {
Serial.println("LOST COUNT");
InvalidInc = 0;
}
}
ISR (PCINT0_vect) {
uint8_t State = PINB & 0b00000011;
int8_t Inc = IncArray[OldState][State];
OldState = State;
Position += Inc;
InvalidInc |= (Inc == 2);
}
The idea of using the lookup array is taken from here:
https://cdn.sparkfun.com/datasheets/Robotics/How%20to%20use%20a%20quadrature%20encoder.pdf
Using a pin change interrupt on both pins essentially implements the XOR shown.
Confirming my numbers where correct, I made a small mark on the disk and read the count after 1 rotation, 40 rotations and some time running on the power supply. Each time the position counter aligned very closely with the number of rotations which indicates the system maintains its position count well
I should add that I used the datasheet above to trace the function of the wires. The small PCB already has the current limiting resistor for the LED, so using the 1.6v forward voltage, 20mA drive current and a measurement of the resistor (82ohm) I determined the board was designed to take 3.3V. Which, is available on the UNO. Handy!