Rotary encoder, interrupts and indivisible code

Hi all

I'm working on a project that uses a rotary encoder knob. I want to use interrupts to avoid missing any pulses from the encoder. I can see how to do this without much trouble. I'm going to use both interrupts to catch the rising and falling edges of both switches in the encoder. To keep my interrupt code as quick as possible, it's simply going to increment or decrement a counter. I will read that counter in my main loop.

My main loop will be something like this: encoderCount is incremented or decremented by the interrupt.

byte previousEncoderCount;

void loop() { byte count = encoderCount; byte distanceMoved = count - previousEncoderCount;

if (distanceMoved != 0) { // Do something previousEncoderCount = count; } }

I know I need to add some logic to cope with the counter overflowing.

Here's my question. Is it safe to do count = encoderCount without stopping interrupts? I assume that using a byte makes it a safe indivisible transfer but I'd like to confirm that. I don't think using an int would be safe because that would need to move two bytes and the interrupt might occur between them producing a wrong answer especially if the interrupt caused the LSB to roll over in that time.

I'm interested in any comments in case there is something the compiler does behind the scenes that I'm not aware of.

A note to anyone playing with encoders. I bought an expensive optical encoder ($17 from Mouser) because I wanted 64 steps per revolution. I missed the fact that if you catch all edges then you can get four times the number of steps. My next one will use a $2 mechanical encoder with 16 steps to achieve 64. I'll probably need some debounce circuitry because I can't really software debounce if it's causing interrupts.

Thanks Ross

I have the similar optical encoder and I just kept everything a int in the ISR and in the loop. I just placed a noInterrupts() before and a interrupts() after the statement where I’m copying the ISR count to the loop count variables. I didn’t notice any impact on missing counts due to these added statements, but that of course would depend on how fast one can turn the knob.

I did have occasional missing counts when turning the shaft fast at first but when I converted digitalRead statements to direct port I/O statements inside the ISR that helped eliminate them. I also played around with using all four encoder level transitions, two transitions and one transitions, it was cool seeing how the encoder resolution could be changed so easily.

Lefty

Is it safe to do count = encoderCount without stopping interrupts?

Assuming encoderCount is declared volatile, because they are both single bytes then, yes, it is safe.

I don't think using an int would be safe because that would need to move two bytes and the interrupt might occur between them producing a wrong answer

That is a potential problem and it is easily managed by following retrolefty's advice.

Thanks for the replies. I've got it working nicely with a volatile byte. It's nice not to have to turn interrupts off and potentially miss one.