MCP23017 need help with code and interrupts

hi,

you're my last chance :wink: i wrote in the german forum and i wrote on many other sites, but nobody is able to help me.

i also studied Nick Gammon's site.

this is my last code

#include <Wire.h>
#include <TimerOne.h>



#define Mcp_Reg_IODIRA			0x00  	// IO direction  (0 = output, 1 = input (Default))
#define Mcp_Reg_IODIRB			0x01
#define Mcp_Reg_IOPOLA			0x02  	// IO polarity   (0 = normal, 1 = inverse)
#define Mcp_Reg_IOPOLB   		0x03
#define Mcp_Reg_GPINTENA 		0x04  	// Interrupt on change (0 = disable, 1 = enable)
#define Mcp_Reg_GPINTENB 		0x05
#define Mcp_Reg_DEFVALA  		0x06  	// Default comparison for interrupt on change (interrupts on opposite)
#define Mcp_Reg_DEFVALB  		0x07
#define Mcp_Reg_INTCONA  		0x08  	// Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define Mcp_Reg_INTCONB  		0x09
#define Mcp_Reg_IOCON    		0x0A  	// IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define Mcp_Reg_IOCON 		0x0B 		// same as 0x0A
#define Mcp_Reg_GPPUA    		0x0C  	// Pull-up resistor (0 = disabled, 1 = enabled)
#define Mcp_Reg_GPPUB    		0x0D
#define Mcp_Reg_INFTFA   		0x0E  	// Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define Mcp_Reg_INFTFB   		0x0F
#define Mcp_Reg_INTCAPA  		0x10  	// Interrupt capture (read only) : value of GPIO at time of last interrupt
#define Mcp_Reg_INTCAPB  		0x11
#define Mcp_Reg_GPIOA    		0x12  	// Port value. Write to change, read to obtain value
#define Mcp_Reg_GPIOB    		0x13
#define Mcp_Reg_OLLATA   		0x14   	// Output latch. Write to latch output.
#define Mcp_Reg_OLLATB   		0x15

#define mcp                             0x21

#define MCPResetPin			4		// hier hängt der MCP mit seinem Reset-Pin dran
#define MCPInterruptA	                0		// hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define MCPInterruptB    	        1		// hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define LEDOnBoard			13		// pin 13, LED aufm Arduino-Board

byte WireTransmitResult = 0;
volatile boolean SwitchPressed = false;
volatile boolean PolledTimer = false;
volatile boolean isInInit = false;
byte inputStateA = 0;
byte inputStateB = 0;
byte inputLastStateA = 0;
byte inputLastStateB = 0;
int lastRead = 0;

byte OutStateA = 0;
byte OutStateB = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("Start");
  Wire.begin();
  initiic();
  pinMode (LEDOnBoard, OUTPUT);
  digitalWrite (LEDOnBoard, LOW);
  // attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING);
  // attachInterrupt(MCPInterruptB, ISRSwitchPressed, FALLING);
  Serial.println("Bereit");
  Timer1.initialize(50000); // 10 Hz
  //  Timer1.initialize(50000); // 20 Hz
  //  Timer1.initialize(25000); // 40 Hz
  Timer1.attachInterrupt( ISRTimer ); // attach the service routine here
}



void loop()
{
  // if (SwitchPressed || (millis() - lastRead >= 4000))
  if (SwitchPressed || PolledTimer)
  {
    digitalWrite (LEDOnBoard, HIGH);

    //    inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
    //    inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);
    inputStateA = readiicbyte(mcp, Mcp_Reg_GPIOA);
    inputStateB = readiicbyte(mcp, Mcp_Reg_GPIOB);
    //    inputStateA = readiicbyte(mcp, Mcp_Reg_OLLATA);
    //    inputStateB = readiicbyte(mcp, Mcp_Reg_OLLATB);

    if (inputStateA != inputLastStateA || inputStateB != inputLastStateB)
    {
      for (byte i = 0; i <= 7; i++)
      {
        if (inputStateA & (1 << i))
        {
          OutStateA ^= (1 << i);
        }
        if (inputStateB & (1 << i))
        {
          OutStateB ^= (1 << i);
        }
      }

      Serial.print(OutStateA, BIN);
      Serial.print("  ");
      Serial.print(OutStateB, BIN);
      Serial.println("\n");

      inputLastStateA = inputStateA;
      inputLastStateB = inputStateB;

      digitalWrite (LEDOnBoard, LOW);

      lastRead = millis();
      SwitchPressed = false;
      PolledTimer = false;
    }
  }
}



void ISRSwitchPressed()
{
  if (!SwitchPressed && !isInInit)
  {
    SwitchPressed = true;
  }
}



void ISRTimer()
{
  if (!SwitchPressed && !isInInit && !PolledTimer)
  {
    PolledTimer = true;
  }
}


void writeiic(uint8_t adr, uint8_t port, byte value)
{
  Wire.beginTransmission( adr );
  Wire.write( port );
  Wire.write( value );
  WireTransmitResult = Wire.endTransmission();

  //  String t = "writeiic: ";
  //  t += " Adr: " + String(adr) + " Port: " + String(port) + " Value: " + String(value);
  //  Serial.println(t);
}



byte readiicbyte(uint8_t adr, uint8_t port)
{
  //Serial.println("IIC Lesen");
  byte returnword = 0x00;

  Wire.beginTransmission(adr);
  Wire.write(port);
  Wire.endTransmission();
  Wire.requestFrom((int)adr, 1);

  int c = 0;

  if (Wire.available())
  {
    returnword = Wire.read();
  }
  return returnword;
}



void initiic()
{
  Serial.println("Init Wire");
  isInInit = true;
  SwitchPressed = false;
  PolledTimer = false;

  pinMode(MCPResetPin, OUTPUT);
  digitalWrite(MCPResetPin, LOW);
  delay(5);
  digitalWrite(MCPResetPin, HIGH);

  writeiic(mcp, Mcp_Reg_IODIRA,	0x00);				// Alles auf Output setzen
  writeiic(mcp, Mcp_Reg_GPIOA,	0x00);				// Alle Pins auf 0 setzen
  writeiic(mcp, Mcp_Reg_IODIRB,	0x00);				// Alles auf Output setzen
  writeiic(mcp, Mcp_Reg_GPIOB,	0x00);				// alle Pins auf 0 setzen

  byte inputMaskA = 0xFF;
  byte inputMaskB = 0xFF;
  byte polA = 0xFF;
  byte polB = 0xFF;

  writeiic(mcp, Mcp_Reg_IODIRA, inputMaskA);		// Richtung (Ein-/Ausgang) einstellen
  writeiic(mcp, Mcp_Reg_IODIRB, inputMaskB);		// Richtung (Ein-/Ausgang) einstellen

  writeiic(mcp, Mcp_Reg_GPPUA, inputMaskA);		// Pull-Up Widerstände einrichten
  writeiic(mcp, Mcp_Reg_GPPUB, inputMaskB);		// Pull-Up Widerstände einrichten

  writeiic(mcp, Mcp_Reg_IOPOLA, polA);			// Polarität einstellen (für Eingänge 0 oder 1)
  writeiic(mcp, Mcp_Reg_IOPOLB, polB);			// Polarität einstellen (für Eingänge 0 oder 1)

  writeiic(mcp, Mcp_Reg_GPINTENA, inputMaskA);	        // Interrupt aktivieren
  writeiic(mcp, Mcp_Reg_GPINTENB, inputMaskB);	        // Interrupt aktivieren

  writeiic(mcp, Mcp_Reg_DEFVALA, inputMaskA);		// Interrupt Default-Wert festlegen
  writeiic(mcp, Mcp_Reg_DEFVALB, inputMaskB);		// Interrupt Default-Wert festlegen

  writeiic(mcp, Mcp_Reg_INTCONA, inputMaskA);		// Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert
  writeiic(mcp, Mcp_Reg_INTCONB, inputMaskB);		// Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert

  //  readiicbyte(mcp, Mcp_Reg_INTCAPA);			// Interrupts lesen und dadurch löschen
  //  readiicbyte(mcp, Mcp_Reg_INTCAPB);			// Interrupts lesen und dadurch löschen
  inputStateA = readiicbyte(mcp, Mcp_Reg_INTCAPA);
  inputStateB = readiicbyte(mcp, Mcp_Reg_INTCAPB);
  inputStateA = readiicbyte(mcp, Mcp_Reg_GPIOA);
  inputStateB = readiicbyte(mcp, Mcp_Reg_GPIOB);
  inputStateA = readiicbyte(mcp, Mcp_Reg_OLLATA);
  inputStateB = readiicbyte(mcp, Mcp_Reg_OLLATB);

  Serial.println("Init Fertig");
  isInInit = false;
}

i used a timer isr to "simulate" interrupts from the mcp. so i got a little trick to read.
but i do not want to poll!

no interrupt appears, the pins are connected to arduino-pin 2 and 3 = interrupt 0 and 1.

sometimes the interrupt appears one time, but not anymore, i know that i have to read the registers to clear the interrupts. i tried different ways.
sometimes, respectly, the interrupt is fired two or three times and than stops.

i tried 4 MCPs and 2 arduinos, so i'm nearly sure that there is no hardware problem by a broken electronics.

who can help me?

How is this wired up?
The interrupts for that chip are open collector so they have to be connected to an arduino input with the pull up resistors enabled.
Most of the time I have found it sufficient just to pole the interrupt pin because you have to poll a flag set in the ISR anyway to read the values.

they're connected directly to Pin 2 and 3

#define MCPInterruptA	                0		// hier hängt der MCP mit seinem Interrupt-Pin 19 dran
#define MCPInterruptB    	        1		// hier hängt der MCP mit seinem Interrupt-Pin 19 dran

... later on in setup ...

attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING);
attachInterrupt(MCPInterruptB, ISRSwitchPressed, FALLING);

may be the parameters for intializing the pins on the mcp are wrong in initiic()?!

do i have to switch the pullups manualy on?

i switched the pullups on, but it still wont work :sob: :sob: :sob:

Then just pole those two pins and see if they change. Keep the pull up enabled.

may be the parameters for intializing the pins on the mcp are wrong in initiic()?!

Can't see you writing anything to Mcp_Reg_IOCON, that should be the first thing you write to when you are setting it up.

afaik, i do not have to write to iocon, because - afaik - i do not want to use the sequential mode.

but i have to say, i do not know exactly what's this mode is for ...

seen on gammon.com.au

// expander configuration register
expanderWriteBoth (IOCON, 0b01100000); // mirror interrupts, use sequential mode

i connected both interrupt-pins from the mcp to the both interrupt-in pins 2,3 = 0,1 on arduino.

but i have to say, i do not know exactly what's this mode is for

It changes the address mapping of the internal registers.

  writeiic(mcp, Mcp_Reg_IODIRA,	0x00);				// Alles auf Output setzen
  writeiic(mcp, Mcp_Reg_GPIOA,	0x00);				// Alle Pins auf 0 setzen
  writeiic(mcp, Mcp_Reg_IODIRB,	0x00);				// Alles auf Output setzen
  writeiic(mcp, Mcp_Reg_GPIOB,	0x00);				// alle Pins auf 0 setzen

This sets all the pins to outputs.

Only pins set to be inputs can generate an interrupt.

ok, you're right, BUT later in the code i set all to input :wink:

yes, i know, it looks crazy, but my intention was to set first all to a known state, after this i set the right directions.

in my original code i want to set the pins individualy by a bit mask ... therefore is the variable: inputMaskA.

now for testing all pins are inputs.

i hope i did in my code as i descripted before :stuck_out_tongue:

Have you got 4K7 pull up resistors on your I2C lines?

Did you try the code on my page and confirms that it works / doesn't work?

@Grumpy_Mike: no, the lines are very short :wink:

@Nick: thanks for your answer!

i rebuild my circuit on another breadboard, as far as i can see, i build the same circuit, but now with your code (after i changed some things in your code to work for 1.6.0) it works.

but now i have some questions:

A) if i connect maybe pin 8 constantly (interrupt fired!) - i got "button 8 now down", and with another cable i connect pin 2, the interrupt is fired well again, and on serial monitor i see "button 8 now down" and "button 2 now down", but if i use pin 13 instead of pin 2, i only see "button 13 now down" - pin 8 is still connected - the same on the other port.

B) the main question, what's wrong with my code?

C) "in my original code i want to set the pins individualy by a bit mask ... therefore is the variable: inputMaskA." my idea is to have an array where i store all the information how i want to set a pin (input or output). i now make a bit mask to set the correspondendig pins at the mcp.
i wrote this peace of code here.
but it want work right now for "input recognition" by interrupt. everything seemed to work fine as long as i poll the inputs. the interrupts are not fired.

did you find my mistakes?

regards

@Grumpy_Mike: no, the lines are very short

The length of the line is irrelevant. You need pull up resistors.

See

It's been a while since I wrote that code, but as I recall you have to clear the "interrupt" flag on the chip before you get a second one.

which code did you mean?
yours or mine?

i read your code again, i think question A is answered in this lines.

  // Read port values, as required. Note that this re-arms the interrupts.
  if (expanderRead (INFTFA))
    keyValue |= expanderRead (INTCAPA) << 8;    // read value at time of interrupt
  if (expanderRead (INFTFB))
    keyValue |= expanderRead (INTCAPB);        // port B is in low-order byte

but the opposite site is not fired/read correctly ... but i thought the interrupts are mirrored ... so both have the same value ... hmmm.

i did some tests, but now i'm confused ... i tested with your code!
i connect pin 8 and 16 constantly to gnd. if i connect pin 1 or 14 (or some else, it doen't matter which one) the interrupt is fired, but it shows me pin 8 now down and pin x (x < 8 ) now down, the same respective on the other site with pin 16 and pin y (y>15 && y<16).
i didn't change your code ...

Grumpy_Mike:
The interrupts for that chip are open collector so they have to be connected to an arduino input with the pull up resistors enabled.

My example code disabled the open-drain feature so that should assert high or low as required. IOCON register, ODR bit as zero.

I modified my code to show all of the pin states (and changed the baud rate to 115200):

/// Author: Nick Gammon
// Date: 19 February 2011

// Demonstration of an interrupt service routine connected to the MCP23017

#include <Wire.h>

// MCP23017 registers (everything except direction defaults to 0)

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IOPOLA   0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IOPOLB   0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCON    0x0A   // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B  // same as 0x0A
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INFTFA   0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB   0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15


#define port 0x20  // MCP23017 is on I2C port 0x20

#define ISR_INDICATOR 12  // pin 12
#define ONBOARD_LED 13    // pin 13

volatile bool keyPressed;

// set register "reg" on expander to "data"
// for example, IO direction
void expanderWriteBoth (const byte reg, const byte data ) 
{
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.write (data);  // port A
  Wire.write (data);  // port B
  Wire.endTransmission ();
} // end of expanderWrite

// read a byte from the expander
unsigned int expanderRead (const byte reg) 
{
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.endTransmission ();
  Wire.requestFrom (port, 1);
  return Wire.read();
} // end of expanderRead

// interrupt service routine, called when pin D2 goes from 1 to 0
void keypress ()
{
  digitalWrite (ISR_INDICATOR, HIGH);  // debugging
  keyPressed = true;   // set flag so main loop knows
}  // end of keypress

void setup ()
{
  pinMode (ISR_INDICATOR, OUTPUT);  // for testing (ISR indicator)
  pinMode (ONBOARD_LED, OUTPUT);  // for onboard LED

  Wire.begin ();  
  Serial.begin (115200); 
  Serial.println ("Starting ..."); 

  // expander configuration register
  expanderWriteBoth (IOCON, 0b01100000); // mirror interrupts, disable sequential mode
 
  // enable pull-up on switches
  expanderWriteBoth (GPPUA, 0xFF);   // pull-up resistor for switch - both ports

  // invert polarity
  expanderWriteBoth (IOPOLA, 0xFF);  // invert polarity of signal - both ports
  
  // enable all interrupts
  expanderWriteBoth (GPINTENA, 0xFF); // enable interrupts - both ports
  
  // no interrupt yet
  keyPressed = false;

  // read from interrupt capture ports to clear them
  expanderRead (INTCAPA);
  expanderRead (INTCAPB);
  
  // pin 19 of MCP23017 is plugged into D2 of the Arduino which is interrupt 0
  attachInterrupt(0, keypress, FALLING);
  
}  // end of setup

// time we turned LED on
unsigned long time = 0;

// called from main loop when we know we had an interrupt
void handleKeypress ()
{
  unsigned int keyValue = 0;
  
  delay (100);  // de-bounce before we re-enable interrupts
  
  keyPressed = false;  // ready for next time through the interrupt service routine
  digitalWrite (ISR_INDICATOR, LOW);  // debugging
  
  // Read port values, as required. Note that this re-arms the interrupts.
  if (expanderRead (INFTFA))
    keyValue |= expanderRead (INTCAPA) << 8;    // read value at time of interrupt
  if (expanderRead (INFTFB))
    keyValue |= expanderRead (INTCAPB);        // port B is in low-order byte
  
  Serial.println ("Button states");
  Serial.println ("0                   1");
  Serial.println ("0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5");
  
  // display which buttons were down at the time of the interrupt
  for (byte button = 0; button < 16; button++)
    {
    // this key down?
    if (keyValue & (1 << button))
      Serial.print ("1 ");
    else
      Serial.print ("0 ");
    
    } // end of for each button

  Serial.println ();
  
  // if a switch is now pressed, turn LED on  (key down event)
  if (keyValue)
    {
    time = millis ();  // remember when
    digitalWrite (ONBOARD_LED, HIGH);  // on-board LED
    }  // end if
  
}  // end of handleKeypress

void loop ()
{
  // was there an interrupt?
  if (keyPressed)
    handleKeypress ();

  // turn LED off after 500 ms 
 if (millis () > (time + 500) && time != 0)
   {
    digitalWrite (ONBOARD_LED, LOW);
    time = 0;
   }  // end if time up
 
}  // end of loop

These are my results as I ground pins 1 to 8 followed by 21 to 28:

Starting ...
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   <---- first button down
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   <---- first button up again
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0   <---- second button down
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
... (omitted due to post size) ...
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Exactly as expected.

Then I grounded pin 1, and leaving it grounded, grounded pin 2 temporarily:

Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    <---- pin 1 grounded
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0    <---- also pin 2 grounded
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    <---- pin 2 not grounded

Perhaps if you test what I did above.

hey nick, first i want to thank you for your attention!

i did Micks tip with the Pull-ups, my code works good so far. but also without the pull-ups

i tried your code 1:1, but it fired only one interrupt, i didn't changed anything in the circuit.

i tried a little bit around with your former code.

...
 expanderRead (INFTFA);
 expanderRead (INFTFB);

 keyValue |= expanderRead (INTCAPA) << 8;
 keyValue |= expanderRead (INTCAPB);

 expanderRead (INTCAPA);
 expanderRead (INTCAPB);
...

i removed the IF before and read INTCAPA/B twice. with or without reading twice, the problem that the last temporarly grounded pins are reported furthermore stays on.

i temp. grounded pin 1 (8/16 is constant), but not pin 1


Button 1 now down
Button 8 now down
Button 12 now down
Button 16 now down


i temp. grounded pin 9 (8/16 is constant), but not pin 1


Button 1 now down
Button 8 now down
Button 9 now down
Button 16 now down


i tried also reading this registers, but no one cleaned the intcap

	expanderRead (GPIOA);
	expanderRead (GPIOB);
	expanderRead (OLLATA);
	expanderRead (OLLATB);

edit: i tried it now with other switches, i think they were nearly debounced in hardware, and what should i say, your former code works. i get all the right states. also from the opposite banks, too.

one more question:

D) did i have to set this registers, if i set IOCON?

	byte inputMaskA = 0xFF;
	byte inputMaskB = 0xFF;
	byte polA = 0xFF;
	byte polB = 0xFF;

	writeiic(mcp, Mcp_Reg_IODIRA, inputMaskA);							// Richtung (Ein-/Ausgang) einstellen
	writeiic(mcp, Mcp_Reg_IODIRB, inputMaskB);							// Richtung (Ein-/Ausgang) einstellen

	writeiic(mcp, Mcp_Reg_GPPUA, inputMaskA);							// Pull-Up Widerstände einrichten
	writeiic(mcp, Mcp_Reg_GPPUB, inputMaskB);							// Pull-Up Widerstände einrichten

	writeiic(mcp, Mcp_Reg_IOPOLA, polA);								// Polarität einstellen (für Eingänge 0 oder 1)
	writeiic(mcp, Mcp_Reg_IOPOLB, polB);								// Polarität einstellen (für Eingänge 0 oder 1)

	writeiic(mcp, Mcp_Reg_GPINTENA, inputMaskA);						// Interrupt aktivieren
	writeiic(mcp, Mcp_Reg_GPINTENB, inputMaskB);						// Interrupt aktivieren

	writeiic(mcp, Mcp_Reg_DEFVALA, inputMaskA);							// Interrupt Default-Wert festlegen
	writeiic(mcp, Mcp_Reg_DEFVALB, inputMaskB);							// Interrupt Default-Wert festlegen

	writeiic(mcp, Mcp_Reg_INTCONA, inputMaskA);							// Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert
	writeiic(mcp, Mcp_Reg_INTCONB, inputMaskB);							// Interrupt Vergleich einstellen, 0 = Änderung zum Vorgänger, 1 = Änderung zum DEFVAL-Wert

	//writeiic(mcp, Mcp_Reg_IOCON, 0b01100010);							// IOCON setzen
	writeiic(mcp, Mcp_Reg_IOCON, 0b01000010);							// IOCON setzen

i went crazy with this chip, i thought it would be easier to use it :frowning:

Can you try the sketch I posted above? And post your output?

FlyingEagle:
i went crazy with this chip, i thought it would be easier to use it :frowning:

You seem to be making a meal of it. When I tested it today it worked as I expected. The code I posted above did what I thought it would do.

The code you posted in your original post had the interrupts commented out:

  // attachInterrupt(MCPInterruptA, ISRSwitchPressed, FALLING);
  // attachInterrupt(MCPInterruptB, ISRSwitchPressed, FALLING);

yes, i commented it out ... after testings and testings and testing ... this code now polls via timer-isr ...

i tested your code as you wished ...

my ouput:

Starting ...
Button states
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

only one time ...