I have code that causes significant delays to responding to an interrupt (interupts are enabled, but I dont get around to reading the register for a few hundred ms so I might miss a button press). Because of that I could not use the ReadButton () function. I wrote an update to read the capture register and it worked fine. With the 5 button keypad, I am only interested in one button press at a time and dont have any need to distinguish between multiple button presses. In the sketch, I treat multiple button presses (value different than 1,2,4,8, or 16 as 0 and do nothing.GeertVc wrote:This is not correct. The INTCAP register only "snapshots" the state of the IO pins the moment the interrupt happens. There's another register, INTF or Interrupt Flag Register, that indicates exactly which pin(s) have caused the interrupt. That register must be used to know the origin of the interrupt.adafruit_support_rick wrote:The mcp23017 helps you out with this a little bit by providing the INTCAP register, which will tell you which pin caused the interrupt.
Here is the additions to the libraries starting with the Hardware interrupt modification described in viewtopic.php?f=31&t=32813
Here are the code modifications to the library
Code: Select all
Add to AdafruitLCDShield.h
void enableButtonInterrupt(); //Added to default library
void disableButtonInterrupt(); //Added to default library
uint8_t readIntButton();
void home();
Add to Adafruit_MCP23017.h
void enableButtonInterrupt(); //Added to default library
void disableButtonInterrupt(); //Added to default library
uint8_t readINTCAPA(); //Added to default library to read button capture interrupt
Add to AdafruitLCDShield.cpp
//Added to default library
void Adafruit_RGBLCDShield::enableButtonInterrupt() {
_i2c.enableButtonInterrupt();
}
//Added to default library
void Adafruit_RGBLCDShield::disableButtonInterrupt() {
_i2c.disableButtonInterrupt();
}
//Added to default library
uint8_t Adafruit_RGBLCDShield::readIntButton() {
uint8_t reply = 0x1F;
reply &= ~(_i2c.readINTCAPA());
return reply;
}
Add to Adafruit_MCP23017.cpp
//Added to default library
//From the Adafruit_RGBLCDShield library we learn that the
//buttons are on bits 0..4, which are on GPIOA,
//so we use GPINTENA, INTCONA and IOCONA.
void Adafruit_MCP23017::enableButtonInterrupt() {
uint8_t data;
//Enable the interrupts on the button pins 0..4
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPINTENA);
Wire.endTransmission();
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
data = wirerecv();
data |= 0x1F; //Bits 0..4 high, to enable IOC
//Write the new value back
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPINTENA);
wiresend(data);
Wire.endTransmission();
//We set INTCONA bits 0..4 to 0 = State change interrupt
//(instead of compare to state)
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_INTCONA);
Wire.endTransmission();
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
data = wirerecv();
data &= ~0x1F; //Force bits 0..4 to low
//Write the new value back
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_INTCONA);
wiresend(data);
Wire.endTransmission();
//We set the INTA pin to Active-Low
//first read current register value
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_IOCONA);
Wire.endTransmission();
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
data = wirerecv();
//Bit 1 = INTPOL = Low = Active-Low
//(When disabled or no interrupt, signal is high)
data &= ~0x02;
//Bit 2 = ODR = Low = Open Drain disabled
data &= ~0x04;
//Bit 6 = MIRROR = Low = INTA/INTB seperate
data &= ~0x40;
//Write the new value back
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_IOCONA);
wiresend(data);
Wire.endTransmission();
}
//Added to default library
void Adafruit_MCP23017::disableButtonInterrupt() {
uint8_t data;
//Disable the interrupts on the button pins 0..4
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPINTENA);
Wire.endTransmission();
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
data = wirerecv();
data &= ~0x1F; //Bits 0..4 low, to disable IOC
//Write the new value back
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPINTENA);
wiresend(data);
Wire.endTransmission();
}
//Added to default library
//reads and returns the entire captur interrupt contents as full byte
//readIntButton() in the main library will mask byte and give button pressed
uint8_t Adafruit_MCP23017::readINTCAPA(){
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_INTCAPA); //request contents of INTCAPA register
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
return wirerecv();
}
Globals
Code: Select all
volatile bool isTriggered = false;
volatile uint16_t buttonEventTime;
volatile uint16_t prevButtonEventTime = 0;
Code: Select all
//Catch the external interrupt from the button input
attachInterrupt(0,ISR_Button,FALLING);
//This signal is active low, so HIGH-to-LOW when interrupt
code in loop()
Code: Select all
if (isTriggered && ((buttonEventTime - prevButtonEventTime) > 100)) {
Serial.println ("interrupt ");
isTriggered = false;
uint8_t IntButton = lcd.readIntButton();
if (IntButton) {
lcd.clear();
lcd.setCursor(0,0);
if (IntButton & BUTTON_UP) {
lcd.print("UP ");
lcd.setBacklight(RED);
}
if (IntButton & BUTTON_DOWN) {
lcd.print("DOWN ");
lcd.setBacklight(YELLOW);
}
if (IntButton & BUTTON_LEFT) {
lcd.print("LEFT ");
lcd.setBacklight(YELLOW);
}
if (IntButton & BUTTON_RIGHT) {
lcd.print("RIGHT ");
lcd.setBacklight(VIOLET);
}
if (IntButton & BUTTON_SELECT) {
lcd.print("SELECT ");
lcd.setBacklight(VIOLET);
}
}
}
}
else if ((buttonEventTime - prevButtonEventTime) <100) {
isTriggered = false;
lcd.readButtons();
}
//ISR to service the button interrupt
void ISR_Button() {
isTriggered = true; //Also flag we triggered
prevButtonEventTime = buttonEventTime;
buttonEventTime = millis();
}