I'm working on a project that consists of a number of switches that interact with the Arduino via I2C IO Expander (MCP23017). The microcontroller pipes the status of the switches from the MCP23017 to its SPI bus (slave). I now need to add six rotary encoders to the project but I'm having problems decoding their output.
The SPI bus section is purely interrupt driven as the microcontroller is acting as a slave. I'm therefore able to use the clock and data lines of the master (which is a totally black-box device) to shift data over the MISO line. The section works as expected.
To capture the switches I'm using the MCP23017's interrupt interface (mirrored) to provide an interrupt to the microcontroller. I've tried using the resulting event to read the ports of the MCP23017, however this appears to stall the device. I've therefore had to use the interrupt event to set a flag that is then used by the main loop to read the ports (after checking which port caused the interrupt).
This post should give you some idea of the code I'm using.
I've then attached the rotary encoder's two output pins to two pins on the MCP23017 and I'm attempting to us the interrupt to find out which pin changes state first to determine the direction the encoder is turning. The problem is that the data captured at the time of the interrupt often has the same state for both pins. This is where I am at a loss, I assume there is some small delay between the MCP23017's interrupt and when it captures the data. By turning the encoder it appears that both pins are at the same state by the time it tries to capture this data. If I turn the encoder really really slowly it appears to work but this is not practical and I get a lot of noise from bounces.
I assume there is a better approach to interacting with these components and I'm quite happy to look into different IO expander options if the MCP23017 can't cut it.
Rotary encoders are surprisingly difficult devices to work with (at least the cheap ones that I've dealt with thus far). The principal is simple, but the reality is far from pretty.
I've used a couple of discrete quadrature decoders in projects to deal with these; take a look at the avago HCTL-2032-SC (Motion Control Encoders) and the Maxim MAX7360 (http://pdfserv.maxim-ic.com/en/ds/MAX7360.pdf). Both of these provide lots of integration options without having to compensate for jitter, bounce, etc.
The 7360 is an i2c device; I'm tempted to start selling a breakout board for it because it's such a handy chip. The 2032 is also very nice, though a bit pricey; it's available as a through-hole part.
Thanks for the tip. I've certainly discovered that it's not a simple as it first appeared.
Do you have any information/examples on how I would work with the MAX7360. I'll obviously have a dig through the forums but thought you might have something at hand that would be helpful.
The biggest issue with the 7360 is that it's an SMT only component. I ordered one mounted on a pdip breakout board by proto-advantage.com; they handle ordering the part through digi-key, mount the component, and ship it directly to you. I think it was under $20 USD when all was said and done. The Avago part may be easier to integrate with if you're just needing to handle rotary encoders.
I haven't found a lot of examples online for the chip; suggestion at Sparkfun to carry a breakout was not exactly responded to with exhuberance. Not sure exactly why, I think the chip would make for an excellent breakout board, as it handles a lot of tricky issues - matrix keypad integration, debounce, dual rotary encoder support, a bunch of GPIOs plus 8x8 LED matrix driver in a single package? What's not to like? (if you'd like to see them carry a breakout for this guy, PLEASE post a "me too" response to this post: http://forum.sparkfun.com/viewtopic.php?f=5&t=29065)
I'll try to post some code examples for both parts this weekend.