Ive been messing around with the GPIO module and the Einhugur interrupt example (https://einhugur.com/blog/index.php/xojo-gpio/connecting-button-with-gpio-and-using-interupts/) and thought Id have a go at knocking up some rotary encoder code.
I picked up a pack of cheap rotary encoders from eBay (emphasis on the word CHEAP!). They are the passive type that produce gray code from a pair of internal switches. I hooked up one pin to the Pis GPIO pin 20 and the other to pin 21. I also connected the centre pin to a GND and not a 3.3v pin.
I tried tracking every change within the encoder, but these switches are very noisy (cheap!), so there were a lot of repeated signals due to bouncing. This made working out the direction of travel almost impossible as filtering out the signal from the noise was tricky. Ideally you should employ some hardware debouncing (a couple of capacitors etc.) but I wanted to see if I could debounce in code. I also couldnt be bothered to head into town to pick up some capacitors!
So in the end I only setup an interrupt on one pin and checked the status of the other pin during that interrupt. This allowed me to use the simple rule:
Pin A = Pin B -> CW / Right
Pin A != Pin B -> CCW / Left
This seems to work pretty well and with the addition of a check to filter out very close clicks (simple debounce) its pretty functional for my needs. I do get incorrect rotations reported now and then, and of the 5 encoders I have, some behave noticeably better than others. The interrupt fires on both the rising and falling edge, to maintain more granularity, however I found that on the worst functioning of the encoders, switching to only checking on either rising or falling led to less false readings.
With hardware debounce added things would be far better (or buying higher quality encoders!), but this code is plenty accurate enough for what I need. I dont need it to be 100% perfect.
If you want to have a play, download the code here:
There are a couple of projects in the ZIP file. One is the module based code, which works pretty well. The other is my attempt to create a self contained rotary encoder class. This however is broken.
The project I am working on will require a few rotary encoders, so I wanted to create a class so I could reuse the code easily. However, the interrupt handler crashes the app as soon as you rotate the device. I guess that its not possible to have an interrupt take place within a class? If anyone has any ideas on how to get it to work, then feel free to take a look. I have a feeling that its not possible though.
Hope someone else finds this useful!