Here's a version that uses Squential Operation Mode bit enabled. This seems to solve the problem I had in the past that simetimes the interrupt flag has not been correctly reset (read my old posts in this section).
Btw I experimented a lot with this chip and his SPI brother 23s17 and results are that interrupt section it's not working always as expected. For example, mcp23s17 configured in input for use the interrupts will always freeze down the INT port after some minute (checked with at list 10 different chips, various configuration and even different libraries), use it with no INT option will not cause any problem (looks like that only INT output pin it's affected).
In out mode it works always perfect, just find some difficulties when different chips use the HAEN option and share the same CS pin (better send HAEN to all chips before all).
The I2C version works (in input configuration) much better but find that Sequential Mode it's more reliable (at list as input with INT option). In out mode works as expect always (since no HAEN mode for this chip).
I find useful use a small button tied to ground engage hardware reset for this chips during configuration experiments since sometimes they just freeze up and works strangely, this just for experiments, not needed for applications.
Here's the code for use with Squential Operation mode bit
Thanks again for your lessons, Nick, it's always a great inspiration see your pages.
#include <Wire.h>
/*
Ths version has been modified for use with Squential Operation mode bit
This use slight less code
*/
#define I2C_SW1 0x27//USE THE CORRECT ADDRESS! this is 3 10k resistors tied to +
/* Multiple Interrupt defs and pins */
#define INT_DEBOUNCE_TIME 40
#define INT_COMMON_PIN 10
#define INT_COMMON_NUM 0
#define IODIR 0x00
#define IOPOL 0x02
#define GPINTEN 0x04
#define DEFVAL 0x06
#define INTCON 0x08
#define IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
#define GPPU 0x0C
#define INFTF 0x0E
#define INTCAP 0x10
#define GPIO 0x12
#define OLLAT 0x14
volatile byte keyPressed;
void setup(void)
{
#if defined DBG
Serial.begin(38400);
Serial.println("inited");
#endif
Wire.begin(); // start I2C
TWBR = ((F_CPU / 400000L) - 16) / 2;//I2C a 400Khz
//-------------------------> SWITCH LOGIC CONFIGURATION
//BANK,MIRROR,SEQOP,DISSLW,HAEN,ODR,INPOL,nused
switchWrite(I2C_SW1,IOCON,0b01000000,2); // mirror interrupts, enable sequential mode, open drain
// enable pull-up on switches
switchWrite(I2C_SW1,GPPU,0xFF,2); // pull-up resistor for switch - both ports
// invert polarity
switchWrite(I2C_SW1,IOPOL,0xFF,2); // invert polarity of signal - both ports
// enable all interrupts
switchWrite(I2C_SW1,GPINTEN,0xFF,2); // enable interrupts - both ports
switchWrite(I2C_SW1,IODIR,0b11111111,2); //port A = INPUT
// read from interrupt capture ports to clear them
switchRead(I2C_SW1,INTCAP);
keyPressed = 0;
// pin 19 of MCP23017 is plugged into D2 of the Arduino which is interrupt 0
pinMode(INT_COMMON_PIN,INPUT); // make sure input
digitalWrite(INT_COMMON_PIN,HIGH); // enable pull-up as we have made the interrupt pins open drain
attachInterrupt(INT_COMMON_NUM,keypress,FALLING);
}
/**************++++++++++ LOOP ++++++++++*********************
**************************************************************/
void loop(void)
{
if (keyPressed){
handleKeypress();
}
}
// interrupt service routine, called when pin D2 goes from 1 to 0
void keypress()
{
keyPressed = 1; // set flag so main loop knows
} // end of keypress
void switchWrite(const byte address,const byte reg,const byte data,const byte times)
{
Wire.beginTransmission(address);
Wire.write(reg);
for (byte i=0;i<times;i++){
Wire.write(data);
}
Wire.endTransmission();
}
// read a word from the expander
word switchRead(const byte address,const byte reg)
{
word _data = 0;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom((int)address, 2);
_data = Wire.read();
_data |= Wire.read() << 8;
return _data;
}
void handleKeypress()
{
word keyValue = 0b0000000000000000;//16 bit
delay(INT_DEBOUNCE_TIME); // de-bounce before we re-enable interrupts
keyPressed = 0;
// Read port values, as required. Note that this re-arms the interrupts.
if (switchRead(I2C_SW1,INFTF)){
keyValue = switchRead(I2C_SW1,INTCAP);
if (keyValue > 0){
for (byte key = 0; key < 16; key++)
{
if (keyValue & (1 << key))
{
Serial.print("Button ");
Serial.print(key, DEC);
Serial.println();
}
}
}
}
} // end of handleKeypress
|