Skip to content

Commit 3d0a575

Browse files
committed
add example / readme
1 parent a7ec573 commit 3d0a575

2 files changed

Lines changed: 289 additions & 0 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
I2C Expander signal readings using KeyDetector library with SparkFun Qwiic Directional Pad.
3+
4+
Demonstrates how to use KeyDetector to trigger action based on digital signal readings from
5+
a SparkFun Qwiic Directional Pad which uses a PCA9554 8-bit I2C GPIO expander.
6+
7+
The SparkFun Qwiic Directional Pad has 5 buttons:
8+
- Up (pin 4)
9+
- Down (pin 5)
10+
- Left (pin 6)
11+
- Right (pin 7)
12+
- Center/Select (pin 3)
13+
14+
Connection:
15+
- Connect the Qwiic Directional Pad to your Arduino/ESP32/etc using a Qwiic cable
16+
or connect directly to the I2C pins (SDA/SCL)
17+
18+
Additional info about KeyDetector library available on GitHub:
19+
https://github.com/Spirik/KeyDetector
20+
21+
This example code is in the public domain.
22+
*/
23+
24+
#include <Arduino.h>
25+
#include <Wire.h>
26+
#include <KeyDetector.h>
27+
28+
// Define signal identifiers for five buttons
29+
#define KEY_UP 1
30+
#define KEY_DOWN 2
31+
#define KEY_LEFT 3
32+
#define KEY_RIGHT 4
33+
#define KEY_SELECT 5
34+
35+
// D-Pad pins on the PCA9554
36+
const byte pinSelect = 3;
37+
const byte pinUp = 4;
38+
const byte pinDown = 5;
39+
const byte pinLeft = 6;
40+
const byte pinRight = 7;
41+
42+
const int keyPressDelay = 500; // Delay after key press event triggered and before continuous press is detected, ms
43+
const int keyPressRepeatDelay = 250; // Delay between "remains pressed" message is printed, ms
44+
45+
long keyPressTime = 0; // Variable to hold time of the key press event
46+
long now; // Variable to hold current time taken with millis() function at the beginning of loop()
47+
48+
// Implementation of the I2CExpander interface for PCA9554
49+
class PCA9554Expander : public I2CExpander {
50+
private:
51+
SFE_PCA95XX io;
52+
53+
public:
54+
PCA9554Expander() : io() {}
55+
56+
bool begin() override {
57+
return io.begin();
58+
}
59+
60+
void pinMode(uint8_t pin, uint8_t mode) override {
61+
io.pinMode(pin, mode);
62+
}
63+
64+
void digitalWrite(uint8_t pin, uint8_t val) override {
65+
io.digitalWrite(pin, val);
66+
}
67+
68+
int digitalRead(uint8_t pin) override {
69+
return io.digitalRead(pin);
70+
}
71+
};
72+
73+
// Create PCA9554 expander instance
74+
PCA9554Expander dpadExpander;
75+
76+
// Create array of Key objects that will link defined key identifiers with pins on the expander
77+
// Note: We set ioType to KEY_IO_TYPE_I2C_EXPANDER and pass our expander object
78+
// Also set pullup to true since the D-Pad buttons are active LOW
79+
Key keys[] = {
80+
{KEY_UP, pinUp, -1, KEY_IO_TYPE_I2C_EXPANDER, &dpadExpander},
81+
{KEY_DOWN, pinDown, -1, KEY_IO_TYPE_I2C_EXPANDER, &dpadExpander},
82+
{KEY_LEFT, pinLeft, -1, KEY_IO_TYPE_I2C_EXPANDER, &dpadExpander},
83+
{KEY_RIGHT, pinRight, -1, KEY_IO_TYPE_I2C_EXPANDER, &dpadExpander},
84+
{KEY_SELECT, pinSelect, -1, KEY_IO_TYPE_I2C_EXPANDER, &dpadExpander}
85+
};
86+
87+
// Create KeyDetector object with 10ms debounce and pullup set to true
88+
KeyDetector dpad(keys, sizeof(keys)/sizeof(Key), 10, 16, true);
89+
90+
void setup() {
91+
// Serial communications setup
92+
Serial.begin(115200);
93+
while (!Serial) {
94+
; // Wait for serial port to connect (needed for native USB port only)
95+
}
96+
97+
Serial.println("SparkFun Qwiic Directional Pad Example with KeyDetector");
98+
99+
// Initialize the I2C expander
100+
if (!dpadExpander.begin()) {
101+
Serial.println("Failed to initialize PCA9554 expander! Check connections.");
102+
while (1); // Halt if we can't communicate with the expander
103+
}
104+
105+
Serial.println("PCA9554 expander initialized successfully.");
106+
Serial.println("Press any button on the D-Pad...");
107+
}
108+
109+
void loop() {
110+
// Get current time to use later on
111+
now = millis();
112+
113+
// Check the current state of input signal
114+
dpad.detect();
115+
116+
// When button press is detected ("triggered"), print corresponding message
117+
// and save current time as a time of the key press event
118+
switch (dpad.trigger) {
119+
case KEY_UP:
120+
Serial.println("UP pressed!");
121+
keyPressTime = now;
122+
break;
123+
case KEY_DOWN:
124+
Serial.println("DOWN pressed!");
125+
keyPressTime = now;
126+
break;
127+
case KEY_LEFT:
128+
Serial.println("LEFT pressed!");
129+
keyPressTime = now;
130+
break;
131+
case KEY_RIGHT:
132+
Serial.println("RIGHT pressed!");
133+
keyPressTime = now;
134+
break;
135+
case KEY_SELECT:
136+
Serial.println("SELECT pressed!");
137+
keyPressTime = now;
138+
break;
139+
}
140+
141+
// When button release is detected, print message
142+
switch (dpad.triggerRelease) {
143+
case KEY_UP:
144+
Serial.println("UP released.");
145+
break;
146+
case KEY_DOWN:
147+
Serial.println("DOWN released.");
148+
break;
149+
case KEY_LEFT:
150+
Serial.println("LEFT released.");
151+
break;
152+
case KEY_RIGHT:
153+
Serial.println("RIGHT released.");
154+
break;
155+
case KEY_SELECT:
156+
Serial.println("SELECT released.");
157+
break;
158+
}
159+
160+
// After keyPressDelay passed since keyPressTime, handle continuous press
161+
if (now > keyPressTime + keyPressDelay) {
162+
// Determine currently pressed button and print message with repeat delay
163+
switch (dpad.current) {
164+
case KEY_UP:
165+
Serial.println("UP held down...");
166+
delay(keyPressRepeatDelay);
167+
break;
168+
case KEY_DOWN:
169+
Serial.println("DOWN held down...");
170+
delay(keyPressRepeatDelay);
171+
break;
172+
case KEY_LEFT:
173+
Serial.println("LEFT held down...");
174+
delay(keyPressRepeatDelay);
175+
break;
176+
case KEY_RIGHT:
177+
Serial.println("RIGHT held down...");
178+
delay(keyPressRepeatDelay);
179+
break;
180+
case KEY_SELECT:
181+
Serial.println("SELECT held down...");
182+
delay(keyPressRepeatDelay);
183+
break;
184+
}
185+
}
186+
187+
// Also demonstrate detection of simultaneous key presses (if secondary key detected)
188+
if (dpad.secondary != KEY_NONE) {
189+
String primaryKey, secondaryKey;
190+
191+
// Determine name of primary key
192+
switch (dpad.current) {
193+
case KEY_UP: primaryKey = "UP"; break;
194+
case KEY_DOWN: primaryKey = "DOWN"; break;
195+
case KEY_LEFT: primaryKey = "LEFT"; break;
196+
case KEY_RIGHT: primaryKey = "RIGHT"; break;
197+
case KEY_SELECT: primaryKey = "SELECT"; break;
198+
}
199+
200+
// Determine name of secondary key
201+
switch (dpad.secondary) {
202+
case KEY_UP: secondaryKey = "UP"; break;
203+
case KEY_DOWN: secondaryKey = "DOWN"; break;
204+
case KEY_LEFT: secondaryKey = "LEFT"; break;
205+
case KEY_RIGHT: secondaryKey = "RIGHT"; break;
206+
case KEY_SELECT: secondaryKey = "SELECT"; break;
207+
}
208+
209+
if (dpad.previousSecondary != dpad.secondary) {
210+
Serial.print("Multiple buttons pressed: ");
211+
Serial.print(primaryKey);
212+
Serial.print(" + ");
213+
Serial.println(secondaryKey);
214+
}
215+
}
216+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Example-05: I2C Expander with SparkFun Qwiic Directional Pad
2+
3+
This example demonstrates how to use the KeyDetector library with the SparkFun Qwiic Directional Pad, which uses a PCA9554 8-bit I2C GPIO expander chip.
4+
5+
## Hardware Requirements
6+
7+
- Arduino board (or any other compatible board like ESP32, ESP8266, etc.)
8+
- [SparkFun Qwiic Directional Pad](https://www.sparkfun.com/products/15316)
9+
- Qwiic cable or I2C connection wires
10+
11+
## Wiring
12+
13+
The SparkFun Qwiic Directional Pad can be connected to your Arduino/board in one of two ways:
14+
15+
### Option 1: Using Qwiic Connector (Recommended)
16+
If your board has a Qwiic connector or you have a Qwiic shield, simply connect the D-Pad to your board using a Qwiic cable.
17+
18+
### Option 2: Manual I2C Connection
19+
If your board doesn't have a Qwiic connector, connect the D-Pad to your board using the following connections:
20+
21+
- D-Pad GND → Arduino GND
22+
- D-Pad 3.3V → Arduino 3.3V
23+
- D-Pad SDA → Arduino SDA (A4 on most Arduinos)
24+
- D-Pad SCL → Arduino SCL (A5 on most Arduinos)
25+
26+
## Button Mapping
27+
28+
The SparkFun Qwiic Directional Pad has 5 buttons mapped to the following pins on the PCA9554 chip:
29+
30+
- Up: Pin 4
31+
- Down: Pin 5
32+
- Left: Pin 6
33+
- Right: Pin 7
34+
- Center/Select: Pin 3
35+
36+
## Active Low Logic
37+
38+
The buttons on the D-Pad are active LOW, meaning they are pulled up by default and pressing them connects the pin to ground. This example takes care of this by setting the `pullup` parameter to `true` in the KeyDetector constructor.
39+
40+
## Features Demonstrated
41+
42+
This example demonstrates:
43+
44+
1. Implementation of the `I2CExpander` interface for the PCA9554 chip
45+
2. Reading button states from the I2C expander
46+
3. Detecting button press, release, and held states
47+
4. Handling simultaneous button presses
48+
5. Sending button events to the Serial monitor
49+
50+
## Serial Output
51+
52+
Open the Serial Monitor at 115200 baud to see the button press, release, and held events. The example will print:
53+
- When a button is pressed
54+
- When a button is released
55+
- When a button is held down
56+
- When multiple buttons are pressed simultaneously
57+
58+
## Troubleshooting
59+
60+
If the example doesn't work:
61+
62+
1. Check your I2C connections
63+
2. Verify that the I2C address is correct (0x27 by default)
64+
3. Make sure the D-Pad is properly powered (3.3V)
65+
4. Check if your Arduino can communicate with the D-Pad using an I2C scanner sketch
66+
67+
## Further Customization
68+
69+
You can modify the example to:
70+
- Change the debounce delay (currently 10ms)
71+
- Adjust the key press and repeat delays
72+
- Add custom actions for different button combinations
73+
- Integrate with other I2C devices using the same Wire interface

0 commit comments

Comments
 (0)