I have a Teensy 3.2 connected to and MCP23017, running the Adafruit MCP23017 library. This is setup on a breadboard to simulate being connected to a home-made pinball game.

GPA0,1 and 2 connected to momentary switches (for the 3 bumpers) GPA2-7 and GPB0 are connected to on/off switches to simulate the 2 banks of 3 drop target micro-switches (switch is connected when the target is hit and drops down)

The buttons (bumpers) work perfectly and send an interrupt to the Teensy however when any of the switches are turned on (drop target hit) this locks up the code until the switch is turned off.

Is there a way around this, so that I can check which target(s) have fallen whilst still detecting hits on the bumpers?

This is my code so far, based on the Adafruit Interrupt example:

// Install the LowPower library for optional sleeping support.
// See loop() function comments for details on usage.
//#include <LowPower.h>

#include <Wire.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;

byte ledPin=13;

// Interrupts from the MCP will be handled by this PIN
byte arduinoIntPin=3; // Connect to MCP INTB with default sketch

volatile boolean awakenByInterrupt = false;

// Two pins at the MCP (Ports A/B where some buttons have been setup.)
// Buttons connect the pin to grond, and pins are pulled up.
// A0-A7 = 0 - 7
// B0-B7 = 8 -15

byte mcpBumper1 = 0;
byte mcpBumper2 = 1;
byte mcpBumper3 = 2;

byte mcpTarget1 = 3;
byte mcpTarget2 = 4;
byte mcpTarget3 = 5;
byte mcpTarget4 = 6;
byte mcpTarget5 = 7;
byte mcpTarget6 = 8;

void setup(){
  Serial.println("MCP23007 Pinball");


  mcp.begin();      // use default address 0

  // We mirror INTA and INTB, so that only one line is required between MCP and Arduino for int reporting
  // The INTA/B will not be Floating 
  // INTs will be signaled with a LOW

  // configuration for a button on port A
  // interrupt will triger when the pin is taken to ground by a pushbutton
  //mcp.pinMode(mcpPinA, INPUT);
  //mcp.pullUp(mcpPinA, HIGH);  // turn on a 100K pullup internally

  // similar, but on port B.
  //mcp.pinMode(mcpPinB, INPUT);
  //mcp.pullUp(mcpPinB, HIGH);  // turn on a 100K pullup internall

  mcp.pinMode(mcpBumper1, INPUT);
  mcp.pinMode(mcpBumper2, INPUT);
  mcp.pinMode(mcpBumper3, INPUT);
  mcp.pinMode(mcpTarget1, INPUT); 
  mcp.pinMode(mcpTarget2, INPUT);
  mcp.pinMode(mcpTarget3, INPUT);
  mcp.pinMode(mcpTarget4, INPUT);
  mcp.pinMode(mcpTarget5, INPUT);
  mcp.pinMode(mcpTarget6, INPUT);

  mcp.pullUp(mcpBumper1, HIGH);
  mcp.pullUp(mcpBumper2, HIGH);
  mcp.pullUp(mcpBumper3, HIGH);
  mcp.pullUp(mcpTarget1, HIGH);
  mcp.pullUp(mcpTarget2, HIGH);
  mcp.pullUp(mcpTarget3, HIGH);
  mcp.pullUp(mcpTarget4, HIGH);
  mcp.pullUp(mcpTarget5, HIGH);
  mcp.pullUp(mcpTarget6, HIGH);

  mcp.setupInterruptPin(mcpBumper1, FALLING);
  mcp.setupInterruptPin(mcpBumper2, FALLING);
  mcp.setupInterruptPin(mcpBumper3, FALLING);  
  mcp.setupInterruptPin(mcpTarget1, FALLING);
  mcp.setupInterruptPin(mcpTarget2, FALLING);
  mcp.setupInterruptPin(mcpTarget3, FALLING);
  mcp.setupInterruptPin(mcpTarget4, FALLING);
  mcp.setupInterruptPin(mcpTarget5, FALLING);
  mcp.setupInterruptPin(mcpTarget6, FALLING);

  // We will setup a pin for flashing from the int routine
  pinMode(ledPin, OUTPUT);  // use the p13 LED as debugging


// The int handler will just signal that the int has happen
// we will do the work from the main loop.
void intCallBack(){

void handleInterrupt(){

  // Get more information from the MCP from the INT
  uint8_t pin = mcp.getLastInterruptPin();
  uint8_t val = mcp.getLastInterruptPinValue();

  Serial.print("Last Pin: ");
  Serial.print(", value: ");

  // Flash to show an interrupt

  // we have to wait for the interrupt condition to finish
  // otherwise we might go to sleep with an ongoing condition and never wake up again.
  // as, an action is required to clear the INT flag, and allow it to trigger again.
  // see datasheet for datails.
    mcp.digitalRead(mcpBumper1) &&
    mcp.digitalRead(mcpBumper2) &&
    mcp.digitalRead(mcpBumper3) && 
    mcp.digitalRead(mcpTarget1) &&
    mcp.digitalRead(mcpTarget2) &&
    mcp.digitalRead(mcpTarget3) &&
    mcp.digitalRead(mcpTarget4) &&
    mcp.digitalRead(mcpTarget5) &&
  // and clean queued INT signal

// handy for interrupts triggered by buttons
// normally signal a few due to bouncing issues
void cleanInterrupts(){

 * main routine: sleep the arduino, and wake up on Interrups.
 * the LowPower library, or similar is required for sleeping, but sleep is simulated here.
 * It is actually posible to get the MCP to draw only 1uA while in standby as the datasheet claims,
 * however there is no stadndby mode. Its all down to seting up each pin in a way that current does not flow.
 * and you can wait for interrupts while waiting.
void loop(){

  // enable interrupts before going to sleep/wait
  // And we setup a callback for the arduino INT handler.
  attachInterrupt(digitalPinToInterrupt(arduinoIntPin), intCallBack, FALLING);

  // Simulate a deep sleep
  // Or sleep the arduino, this lib is great, if you have it.
  //LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);

  // disable interrupts while handling them.

  if(awakenByInterrupt) handleInterrupt();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.