I'm trying to write an interrupt service routine for an Arduino Mega 2560 to decode a quadrature rotary encoder. I've got an ISR (Interrupt Service Routine) that responds to the falling edge of digital pin 2.
I then need to look at the value of pin 3 and see if it is high or low to tell which direction the encoder is being turned. I've built a simple debouncing circuit using a couple of resistors and a .01 μF capacitor per line from the encoder, so those signals are clean now.
Based on the reading I've done, it's best to read the pin states directly rather than using digitalRead in an ISR since the
digitalRead() function is rather slow.
I am finding it hard to find and figure out the port mappings for the port registers to read the pins.
I believe that I should use
(PIND & (1 << 3) != 0 to read digital pin 3, since I think pins 2-9 are on register PIND?
I found this chart https://www.arduino.cc/en/Hacking/PinMapping2560 that lists the pin mappings for the Mega 2560, but I'm not sure how to read it.
If I use
bool pinBState = digitalRead(rotaryPinB) == LOW in my ISR it works, but it seems to miss state changes sometimes.
If instead I use the code `bool pinBState = (PIND & (1 << 3)) == 0;
The value of
pinBState never changes.
Can somebody tell me what I'm doing wrong?
See the self-answer below. It seems that digital pins 0-7 are read from PINE, not PIND.
However, now I have a new problem:
With the code shown in my answer I am getting readings that increase for clockwise rotation, and decrease for counterclockwise rotation, as expected:
If I rotate it very slowly through a full revolution, I can usually get exactly 12 steps in a rotation. If I rotate my encoder rapidly, or through several full turns, it gives me values that aren't exact multiples of 12, and rotating it several turns clockwise, and then the same number of turns counterclockwise does not return the value to 0 like it should.
I'm using a simple debouncing circuit as recommended from the spec sheet for the encoder:
The circuit looks like this:
Shouldn't that circuit work? I wired it up on a breadboard, and have pretty long leads, and didn't cut the wires on the resistors or capacitors since this is still a test circuit. I wouldn't think this would be sensitive to RF noise though. The only other thing I've got on the project is an I2C LCD display. I've triple-checked my wiring and don't think I've made any mistakes.
I'm stumped as to why an interrupt-driven rotary encoder, with the recommended debouncing circuit, that reads port registers to read the data from it's PIN B doesn't give reliable results for normal rates of turning on the control.