Skip to content

Commit 8d3f140

Browse files
committed
Add interrupt handling examples
Add three comprehensive examples demonstrating interrupt functionality: 1. InterruptBasic: - Simple single-button interrupt handling - Demonstrates FALLING (press) and RISING (release) modes - Shows proper ISR implementation with debouncing - Uses SimpleCallback for button events 2. InterruptMultipleButtons: - Handle interrupts from all D-PAD buttons simultaneously - Demonstrates CHANGE mode with level parameter - Per-button callbacks with event tracking - Press statistics for all buttons 3. InterruptWithPin: - Uses Pin-compatible API with interrupts - Demonstrates attachInterrupt/detachInterrupt - LED control triggered by button interrupts - Long press detection (>2s) for special actions All examples include: - STEAMI board I2C configuration - Proper debouncing (50ms) - Detailed comments and usage instructions - Error handling checks - Status reporting Updated README with interrupt examples section.
1 parent 4af5843 commit 8d3f140

6 files changed

Lines changed: 463 additions & 0 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,16 @@ All methods are identical to `MCP23009Pin`, but logic is automatically inverted.
232232
233233
The library includes several examples:
234234
235+
### Basic Examples
235236
- **BasicUsage** - Read D-PAD buttons and print states
236237
- **LED_ActiveLow** - Control LEDs in active-low configuration with effects
237238
- **ErrorHandling** - Demonstrates I2C error detection and handling
238239
240+
### Interrupt Examples
241+
- **InterruptBasic** - Simple interrupt handling with one button (FALLING/RISING)
242+
- **InterruptMultipleButtons** - Handle interrupts from multiple buttons (CHANGE mode)
243+
- **InterruptWithPin** - Use Pin API with interrupts and LED control
244+
239245
## Hardware Considerations
240246
241247
### I2C Address
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* Basic Interrupt Example for MCP23009E Library
3+
*
4+
* This example demonstrates how to use hardware interrupts with the MCP23009E.
5+
* When a button is pressed, an interrupt is triggered and handled automatically.
6+
*
7+
* Hardware Setup:
8+
* - MCP23009E connected via I2C
9+
* - Button on GPIO 7 (with pull-up enabled)
10+
* - MCP23009E INT pin connected to microcontroller GPIO (INT_EXPANDER)
11+
*
12+
* Interrupt modes:
13+
* - FALLING: Triggered when button is pressed (HIGH to LOW)
14+
* - RISING: Triggered when button is released (LOW to HIGH)
15+
* - CHANGE: Triggered on both press and release
16+
*
17+
* Note: The interrupt pin configuration and ISR attachment are now handled
18+
* automatically by the library when you pass the interruptPin to begin().
19+
*/
20+
21+
#include <Wire.h>
22+
#include <MCP23009E.h>
23+
24+
// Create MCP23009E instance
25+
MCP23009E mcp(Wire, MCP23009_I2C_ADDR);
26+
27+
// Reset pin (adjust for your board)
28+
const int RESET_PIN = RST_EXPANDER; // Set to your reset pin number, or -1 if none
29+
const int INTERRUPT_PIN = INT_EXPANDER; // Microcontroller pin connected to MCP23009E INT
30+
31+
// Button configuration
32+
const int BUTTON_PIN = MCP23009_BTN_UP; // Use D-PAD UP button (GPIO 7)
33+
34+
// Volatile variables for interrupt handling
35+
volatile bool buttonPressed = false;
36+
volatile bool buttonReleased = false;
37+
38+
// Callback for button press (falling edge)
39+
void onButtonPress() {
40+
buttonPressed = true;
41+
}
42+
43+
// Callback for button release (rising edge)
44+
void onButtonRelease() {
45+
buttonReleased = true;
46+
}
47+
48+
void setup() {
49+
Serial.begin(115200);
50+
while (!Serial) delay(10);
51+
52+
Serial.println("Initializing I2C...");
53+
Wire.setSDA(I2C_INT_SDA);
54+
Wire.setSCL(I2C_INT_SCL);
55+
Wire.begin();
56+
57+
Serial.println("================================");
58+
Serial.println("MCP23009E Interrupt Basic Example");
59+
Serial.println("================================\n");
60+
61+
// Initialize MCP23009E
62+
mcp.begin(RESET_PIN, INTERRUPT_PIN);
63+
64+
// Configure button as input with pull-up
65+
Serial.println("Configuring button with interrupts...");
66+
mcp.setup(BUTTON_PIN, MCP23009_DIR_INPUT, MCP23009_PULLUP);
67+
68+
// Configure interrupts on the MCP23009E
69+
// Note: The interrupt pin and ISR are automatically configured by begin()
70+
mcp.interruptOnFalling(BUTTON_PIN, onButtonPress);
71+
mcp.interruptOnRaising(BUTTON_PIN, onButtonRelease);
72+
73+
Serial.println("✓ Interrupt configuration complete");
74+
Serial.println("\nPress the UP button to trigger interrupts...\n");
75+
Serial.println("(Button should be connected with pull-up)");
76+
Serial.println("Press = FALLING interrupt");
77+
Serial.println("Release = RISING interrupt\n");
78+
}
79+
80+
uint32_t pressCount = 0;
81+
uint32_t releaseCount = 0;
82+
83+
void loop() {
84+
// Handle button press events in main loop (not in ISR)
85+
if (buttonPressed) {
86+
buttonPressed = false;
87+
pressCount++;
88+
Serial.print("✓ Button PRESSED (count: ");
89+
Serial.print(pressCount);
90+
Serial.println(")");
91+
}
92+
93+
// Handle button release events in main loop (not in ISR)
94+
if (buttonReleased) {
95+
buttonReleased = false;
96+
releaseCount++;
97+
Serial.print("✓ Button RELEASED (count: ");
98+
Serial.print(releaseCount);
99+
Serial.println(")");
100+
}
101+
102+
// Print status every 5 seconds
103+
static uint32_t lastStatusTime = 0;
104+
if (millis() - lastStatusTime > 5000) {
105+
lastStatusTime = millis();
106+
Serial.println("\n--- Status ---");
107+
Serial.print("Total presses: ");
108+
Serial.println(pressCount);
109+
Serial.print("Total releases: ");
110+
Serial.println(releaseCount);
111+
Serial.println("Waiting for interrupts...\n");
112+
}
113+
114+
// Small delay to avoid excessive CPU usage
115+
delay(10);
116+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/**
2+
* Multiple Buttons Interrupt Example for MCP23009E Library
3+
*
4+
* This example demonstrates handling interrupts from multiple buttons (D-PAD).
5+
* Each button can trigger an interrupt and the handler identifies which button
6+
* caused the interrupt and its state (pressed/released).
7+
*
8+
* Hardware Setup:
9+
* - MCP23009E connected via I2C
10+
* - D-PAD buttons on GPIO 4, 5, 6, 7 (with pull-ups enabled)
11+
* - MCP23009E INT pin connected to microcontroller GPIO (INT_EXPANDER)
12+
*
13+
* D-PAD Button Mapping:
14+
* - GPIO 7: UP
15+
* - GPIO 5: DOWN
16+
* - GPIO 6: LEFT
17+
* - GPIO 4: RIGHT
18+
*
19+
* Note: The interrupt pin configuration and ISR attachment are now handled
20+
* automatically by the library when you pass the interruptPin to begin().
21+
*/
22+
23+
#include <Wire.h>
24+
#include <MCP23009E.h>
25+
26+
// Create MCP23009E instance
27+
MCP23009E mcp(Wire, MCP23009_I2C_ADDR);
28+
29+
// Reset pin (adjust for your board)
30+
const int RESET_PIN = RST_EXPANDER;
31+
const int INTERRUPT_PIN = INT_EXPANDER;
32+
33+
// Button states
34+
struct ButtonState {
35+
bool changed;
36+
uint8_t level;
37+
uint32_t pressCount;
38+
};
39+
40+
volatile ButtonState upButton = {false, HIGH, 0};
41+
volatile ButtonState downButton = {false, HIGH, 0};
42+
volatile ButtonState leftButton = {false, HIGH, 0};
43+
volatile ButtonState rightButton = {false, HIGH, 0};
44+
45+
// Individual button callbacks using CHANGE mode
46+
void onUpButtonChange(uint8_t level) {
47+
upButton.changed = true;
48+
upButton.level = level;
49+
if (level == LOW) upButton.pressCount++;
50+
}
51+
52+
void onDownButtonChange(uint8_t level) {
53+
downButton.changed = true;
54+
downButton.level = level;
55+
if (level == LOW) downButton.pressCount++;
56+
}
57+
58+
void onLeftButtonChange(uint8_t level) {
59+
leftButton.changed = true;
60+
leftButton.level = level;
61+
if (level == LOW) leftButton.pressCount++;
62+
}
63+
64+
void onRightButtonChange(uint8_t level) {
65+
rightButton.changed = true;
66+
rightButton.level = level;
67+
if (level == LOW) rightButton.pressCount++;
68+
}
69+
70+
void setup() {
71+
Serial.begin(115200);
72+
while (!Serial) delay(10);
73+
74+
Serial.println("Initializing I2C...");
75+
Wire.setSDA(I2C_INT_SDA);
76+
Wire.setSCL(I2C_INT_SCL);
77+
Wire.begin();
78+
79+
Serial.println("========================================");
80+
Serial.println("MCP23009E Multiple Buttons Interrupt Example");
81+
Serial.println("========================================\n");
82+
83+
// Initialize MCP23009E
84+
mcp.begin(RESET_PIN, INTERRUPT_PIN);
85+
86+
// Configure all D-PAD buttons with pull-ups
87+
Serial.println("Configuring D-PAD buttons with interrupts...");
88+
mcp.setup(MCP23009_BTN_UP, MCP23009_DIR_INPUT, MCP23009_PULLUP);
89+
mcp.setup(MCP23009_BTN_DOWN, MCP23009_DIR_INPUT, MCP23009_PULLUP);
90+
mcp.setup(MCP23009_BTN_LEFT, MCP23009_DIR_INPUT, MCP23009_PULLUP);
91+
mcp.setup(MCP23009_BTN_RIGHT, MCP23009_DIR_INPUT, MCP23009_PULLUP);
92+
93+
// Configure interrupts for all buttons (CHANGE mode with level callback)
94+
// Note: The interrupt pin and ISR are automatically configured by begin()
95+
mcp.interruptOnChange(MCP23009_BTN_UP, onUpButtonChange);
96+
mcp.interruptOnChange(MCP23009_BTN_DOWN, onDownButtonChange);
97+
mcp.interruptOnChange(MCP23009_BTN_LEFT, onLeftButtonChange);
98+
mcp.interruptOnChange(MCP23009_BTN_RIGHT, onRightButtonChange);
99+
100+
Serial.println("✓ All interrupts configured");
101+
Serial.println("\nPress any D-PAD button to see interrupt handling...");
102+
Serial.println("(Buttons: UP, DOWN, LEFT, RIGHT)\n");
103+
}
104+
105+
void printButtonEvent(const char* buttonName, const ButtonState& button) {
106+
if (button.changed) {
107+
Serial.print("");
108+
Serial.print(buttonName);
109+
Serial.print(": ");
110+
Serial.print(button.level ? "RELEASED" : "PRESSED");
111+
Serial.print(" (total presses: ");
112+
Serial.print(button.pressCount);
113+
Serial.println(")");
114+
}
115+
}
116+
117+
void loop() {
118+
// Check and handle all button events
119+
bool anyChange = false;
120+
121+
if (upButton.changed) {
122+
printButtonEvent("UP ", upButton);
123+
upButton.changed = false;
124+
anyChange = true;
125+
}
126+
127+
if (downButton.changed) {
128+
printButtonEvent("DOWN ", downButton);
129+
downButton.changed = false;
130+
anyChange = true;
131+
}
132+
133+
if (leftButton.changed) {
134+
printButtonEvent("LEFT ", leftButton);
135+
leftButton.changed = false;
136+
anyChange = true;
137+
}
138+
139+
if (rightButton.changed) {
140+
printButtonEvent("RIGHT", rightButton);
141+
rightButton.changed = false;
142+
anyChange = true;
143+
}
144+
145+
// Add a blank line after processing all changes
146+
if (anyChange) {
147+
Serial.println();
148+
}
149+
150+
// Print statistics every 10 seconds
151+
static uint32_t lastStatsTime = 0;
152+
if (millis() - lastStatsTime > 10000) {
153+
lastStatsTime = millis();
154+
Serial.println("--- Button Press Statistics ---");
155+
Serial.print("UP: ");
156+
Serial.print(upButton.pressCount);
157+
Serial.print(" | DOWN: ");
158+
Serial.print(downButton.pressCount);
159+
Serial.print(" | LEFT: ");
160+
Serial.print(leftButton.pressCount);
161+
Serial.print(" | RIGHT: ");
162+
Serial.println(rightButton.pressCount);
163+
Serial.println("-------------------------------\n");
164+
}
165+
166+
// Small delay
167+
delay(10);
168+
}

0 commit comments

Comments
 (0)