JOURNAL2010-04-13

MCP23S08: 8 Bit I/O Expander: Part Two: <br/>Extra Switch Inputs

In Part One about the MCP23S08, I discussed how to set up one of these i/o expanders as a bank of outputs to drive LEDs.  They can also be used as digital inputs.  They don't do any good as analog inputs for things like pots.  You can use analog multiplexers for that.  As digital input expanders though, they make an excellent way to expand your systems switch capabilities.  I am using them for banks of tactile switches to step through options to control my synthesizer.  Follow the jump to see how I configure them...

To configure the MCP23S08, we set the i/o expanders registers in the same way described in Part One, except that we place different values in the configuration registers.  I configure the i/o expander in two stages.  I do this because I want to have all the value set in the registers before I turn on the interrupts.  This way I avoid triggering an unwanted interrupt.  So, the first set of transmission configure all the registers and the second turns on the interrupts.  I'm not 100% that this is necessary.  I might experiment with doing it all in one because the values probably aren't activated until the chip select line goes high.



For this i/o expander, I have eight buttons.  Each button is connected to a pin on the i/o expander on one side and to ground on the other.  The i/o expander ports are configured with their pull-up pins active, so they will have 5 Volts on them when a button is not pressed, and 0 Volts when a button is pressed.  The i/o expander is monitoring for anything other than 5 Volts being on any pin.  When that happens, it locks in the state of its pins in a special register called the "interrupt capture register."  Then, it activates its interrupt pin. This pin is connected to a microcontroller pin which is similarly configured to trigger an interrupt when it senses a change in voltage.  On the AVR, this is pin D2.



I set pin 2 to be an pull-up input.  The interrupt is activated when the pin goes from high to low.  I don't want it to be level triggered because if I don't process the interrupt right away, it will continue to trigger repeatedly.

When the interrupt is triggered, two things happen.  I set a flag so that the main part of the code knows that an interrupt happened and I set a timer to debounce the switch press.  If we respond to the switch press immediately, the switch will be bouncing between high and low and another interrupt will be triggered.  I set a timer for 200ms in this case.  I've been able to get away with less than that in the past without penalty, but these devices appear to be sensitive and 200 ms appears to be a good length of time for a switch press.  The interrupt service routine is below:



I haven't shown the timer routine here.  I'll assume if you've made it this far, you can handle that.

In the main code, I check for this flag to be set and manage all my synthesizer settings and LEDs and anything you imagine I could do based on a switch press.  You can't process anything in the interrupt routine because of the debouncing unless you had the time to wait.  If you do decide to wait, make sure to clear the watchdog timer.  Anyways, have fun expanding your i/o!