Ok so I have a problem with either my hardware or software that is driving me absolutely batty.
I'm interfacing my arduino to a Microchip MCP23017 I/O expander chip via the I2C bus. There are two 8 bit ports on the 23017 and I've designated one port as rows and the other as columns so that I can create a switch matrix. Port A (rows) has the internal pullups enabled so its always pulled high and is set as an input. Port B (cols) is initialized as low output so that when a switch in the matrix is pushed, it triggers an interrupt. The Interrupt A pin on the 23017 is attached to Pin 2 on my ATMEGA2560. When the interrupt occurs it sets a flag in my ISR in my code that a key was pressed. Also, it prints to the serial monitor, "ISR" (meaning the ISR was triggered - for debugging purposes). Then a handling function is called that reads the interrupt capture on that port and prints it to the screen ("10111111", or something like that). Later i will use that information to decode the binary number and determine what switch was pressed, etc. Right now i am simulating a pressed button on the breadboard by just use a jumper wire to connect the row to col.
Here's the problem, whenever, I press a button, it prints "ISR" several times in the monitor. This tells me that it calls the ISR way too many times. Also, ISR is being called when I let go of the switch. I only want the interrupt to trigger when I press the switch. Below is what the serial monitor looks like if i press a button.
press a button on the expander's switch matrix
ISR
ISR
ISR
ISR
ISR
ISR
11111111 <-reading INTCAPA register, one of these should be zero depending on what pin is grounded
let go of button
ISR
11111111 <-reading INTCAPA register
Here is my code. Its not all the code but its the only part that pertains to the I2C expander and matrix.
ExpanderWrite is a function I wrote that takes the I2C device addr, the register, and the data as the parameters. So i am initializing the i2c device in the Setup().
void setup(){
Serial.begin(9600); //beging serial comm at 9600 bits/s
Wire.begin(); //wake up the i2c bus
Serial.println("Boot-up sequence");
expanderWriteBoth (I2C_TOGS, IOCON, 0b00000000); // mirror interrupts, disable sequential mode
expanderWrite(I2C_TOGS, IODIRB, 0x00);
expanderWrite(I2C_TOGS, GPIOB, 0x00);
expanderWrite(I2C_TOGS, IOPOLA, 0x00);
expanderWrite(I2C_TOGS, DEFVALA, 0xFF);
expanderWrite(I2C_TOGS, INTCONA, 0x00);
expanderWrite(I2C_TOGS, GPPUA, 0xFF);
expanderWrite(I2C_TOGS, GPINTENA, 0xFF);
// no interrupt yet
keyPressed = false;
// read from interrupt capture addr A to clear it (reading resets the addr interrupt)
expanderRead(I2C_TOGS, INTCAPA);
// pin 19 of MCP23017 is plugged into D2 of the Arduino which is interrupt 0
attachInterrupt(0, keypress, FALLING);
Serial.println("Initializing LCD...");
initializeDisplay(); // initialize the display
Serial.println("Initializing Cue Statuses");
// initializeCues(cue); //initialize cues
}
// ISR
void keypress(){
keyPressed = true;
Serial.println("ISR");
}
// Main Program Loop
void loop(){
unsigned long i;
// some imaddrant calculations here ...
for (i = 0; i < 0x7FFFF; i++) {
}
// was there an interrupt?
if (keyPressed){
handleKeypress();
}
//updateDisplay(); if(displayData);
// read Serial port
/*if(Serial.available() > 0){
char command = Serial.read(); //read the data
delay(100); // wait for entire message to be received
}*/
/*
/*
void fireSelectedCue(int cue){
Serial.write(cue);
}
*/
}
// Write to both addrs of the expander
void expanderWriteBoth (const byte addr, const byte reg, const byte data ) {
Wire.beginTransmission (addr);
Wire.write(reg);
Wire.write(data); // addr A
Wire.write(data); // addr B
Wire.endTransmission();
}
// called from main loop when we know we had an interrupt
void handleKeypress ()
{
unsigned int keyValue = 0;
byte readData;
int col;
boolean flag = false;
byte bitData = 0x00;
delay(100); // de-bounce before we re-enable interrupts
for(int i=0; i<8; i++){
expanderWrite(I2C_TOGS, GPIOB, bitSet(bitData,i));
readData = expanderRead(0x24, GPIOA);
if(readData != 0 && !flag){
flag=true;
col=i;
}
expanderWrite(I2C_TOGS, GPIOB, 0x00);
}
if(readData != 0x00){
readData |= col;
Serial.println(readData, BIN);
readData = 0x00;
}
//expanderWrite(I2C_TOGS, GPIOB, 0x00);
expanderRead(0x24, INTCAPA); //reset the interrupt capture on addr A
keyPressed = false; // ready for next time through the interrupt service routine
/*
// 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 ("Button ");
Serial.print (button + 1, DEC);
Serial.println (" now down");
} // end of if this bit changed
} // end of for each button
// 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*/
}
// write a byte to the expander
void expanderWrite(const byte addr, const byte reg, const byte data){
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
}
// read a byte from the expander
unsigned int expanderRead (int addr, const byte reg)
{
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(addr, 1);
return Wire.read();
}