Skip to content

Commit 1ac4b85

Browse files
examples: Add practical examples for mcp23009e driver. (#247)
* fix(mcp23009e): Remove test script from example * feat(mcp23009e): add reaction time example * feat(mcp23009e): add simon game example * feat(mcp23009e): add combination lock example * feat(mcp23009e): add dpad counter example * feat(mcp23009e): add morse code example * feat(mcp23009e): add binary counter example * feat(mcp23009e): add navigation menu example * feat(mcp23009e): add dpad piano example * docs(mcp23009e): add example to readme * feat(mcp23009e): add sleep on button example * docs(mcp23009e): add sleep on example to readme * docs(mcp23009e): fix examples errors. - Binary counter -> (GPIO1–GPIO4 / pins 0–3) - Example command with a existing file * fix(mcp23009e): More reliable interrupt in sleep_on_button interrupt capture registers to reliably detect wake button * fix(mcp23009e): replace wrong pin in dpad piano example * docs(mcp23009e): clarify GPIO naming for binary counter output pins In binary_counter example docstring * fix(lis2mdl): added menu btn to exit dpad piano example
1 parent f98b225 commit 1ac4b85

17 files changed

Lines changed: 964 additions & 1001 deletions

lib/mcp23009e/README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -194,21 +194,24 @@ Toggles the reset pin to perform a hardware reset.
194194

195195
## Examples
196196

197-
The library includes several examples:
198-
199-
* `buttons.py` - Simple button reading with polling
200-
* `i2c_scan.py` - Scan I2C buses for connected devices
201-
* `test_basic.py` - Basic driver functionality tests
202-
* `test_interrupts.py` - Interrupt system demonstration
203-
* `test_led_simple.py` - Basic active-low LED control example
204-
* `test_output_active_low.py` - Active-low output tests with inverted logic
205-
* `test_output.py` - GPIO output tests using low-level and Pin APIs
206-
* `test_pin.py` - MCP23009Pin class usage examples
207-
* `test_pin_irq.py` - Pin-compatible interrupt examples
208-
197+
The library includes several practical examples:
198+
199+
| Example | Description |
200+
|-----------------------|------------|
201+
| `buttons.py` | Simple D-PAD button reading using polling (no interrupts) |
202+
| `i2c_scan.py` | Scan the I2C bus to detect connected devices |
203+
| `reaction_timer.py` | Reaction time game using D-PAD buttons and interrupts (best of 5 rounds) |
204+
| `simon.py` | Simon Says memory game using the D-PAD |
205+
| `combination_lock.py` | Digital lock using a secret D-PAD sequence |
206+
| `dpad_counter.py` | Simple state machine: increment/decrement/reset/print using D-PAD |
207+
| `morse_code.py` | Morse code input using button press duration (dot/dash detection) |
208+
| `binary_counter.py` | 4-bit binary counter displayed on GPIO outputs (GPIO1–GPIO4 / pins 0–3) |
209+
| `dpad_piano.py` | Play musical notes with the D-PAD and buzzer (multi-press = higher octave) |
210+
| `menu_navigation.py` | Minimal centered UI for navigating a menu on the SSD1327 OLED display |
211+
| `sleep_on_button.py` | Low-power example: wake the board from sleep using MCP23009E interrupts |
209212

210213
### How to run
211214

212215
```python
213-
mpremote mount lib/mcp23009e run lib/mcp23009e/examples/test_basic.py
216+
mpremote mount lib/mcp23009e run lib/mcp23009e/examples/buttons.py
214217
```
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
Binary counter using D-PAD inputs and MCP23009E GPIO outputs.
3+
4+
UP -> increment
5+
DOWN -> decrement
6+
LEFT -> reset
7+
RIGHT -> print current value
8+
9+
The value is displayed on GPIO1..GPIO4 (expander pins 0..3)
10+
as a 4-bit binary number.
11+
"""
12+
13+
from time import sleep_ms
14+
15+
from machine import I2C, Pin
16+
from mcp23009e import MCP23009E
17+
from mcp23009e.const import *
18+
19+
bus = I2C(1)
20+
reset = Pin("RST_EXPANDER", Pin.OUT)
21+
22+
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)
23+
24+
BUTTONS = {
25+
MCP23009_BTN_UP: "UP",
26+
MCP23009_BTN_DOWN: "DOWN",
27+
MCP23009_BTN_LEFT: "LEFT",
28+
MCP23009_BTN_RIGHT: "RIGHT",
29+
}
30+
31+
OUTPUT_PINS = [MCP23009_GPIO1, MCP23009_GPIO2, MCP23009_GPIO3, MCP23009_GPIO4]
32+
33+
34+
def wait_all_released():
35+
while True:
36+
if all(mcp.get_level(pin_number) == MCP23009_LOGIC_HIGH for pin_number in BUTTONS):
37+
return
38+
sleep_ms(20)
39+
40+
41+
def wait_for_button():
42+
wait_all_released()
43+
while True:
44+
for pin_number, name in BUTTONS.items():
45+
if mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
46+
while mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
47+
sleep_ms(20)
48+
return name
49+
sleep_ms(20)
50+
51+
52+
def update_outputs(value):
53+
for bit_index, pin_number in enumerate(OUTPUT_PINS):
54+
bit_value = (value >> bit_index) & 0x01
55+
mcp.set_level(pin_number, bit_value)
56+
57+
58+
for pin_number in BUTTONS:
59+
mcp.setup(pin_number, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP)
60+
61+
for pin_number in OUTPUT_PINS:
62+
mcp.setup(pin_number, MCP23009_DIR_OUTPUT)
63+
mcp.set_level(pin_number, MCP23009_LOGIC_LOW)
64+
65+
counter = 0
66+
update_outputs(counter)
67+
68+
print("=================================")
69+
print("Binary Counter")
70+
print("=================================\n")
71+
print("Displaying the 4-bit value on GP0..GP3")
72+
print("UP=+1 DOWN=-1 LEFT=reset RIGHT=print\n")
73+
74+
while True:
75+
button = wait_for_button()
76+
77+
if button == "UP":
78+
counter = (counter + 1) & 0x0F
79+
elif button == "DOWN":
80+
counter = (counter - 1) & 0x0F
81+
elif button == "LEFT":
82+
counter = 0
83+
elif button == "RIGHT":
84+
pass
85+
86+
update_outputs(counter)
87+
print("Value:", counter, " Binary:", "{:04b}".format(counter))
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
Digital combination lock using the MCP23009E D-PAD.
3+
4+
Enter the secret button sequence to unlock.
5+
A wrong input resets the attempt.
6+
"""
7+
8+
from time import sleep_ms
9+
10+
from machine import I2C, Pin
11+
from mcp23009e import MCP23009E
12+
from mcp23009e.const import *
13+
14+
bus = I2C(1)
15+
reset = Pin("RST_EXPANDER", Pin.OUT)
16+
17+
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)
18+
19+
BUTTONS = {
20+
MCP23009_BTN_UP: "UP",
21+
MCP23009_BTN_DOWN: "DOWN",
22+
MCP23009_BTN_LEFT: "LEFT",
23+
MCP23009_BTN_RIGHT: "RIGHT",
24+
}
25+
26+
SECRET = ["UP", "UP", "DOWN", "LEFT", "RIGHT"]
27+
28+
29+
def wait_all_released():
30+
while True:
31+
if all(mcp.get_level(pin_number) == MCP23009_LOGIC_HIGH for pin_number in BUTTONS):
32+
return
33+
sleep_ms(20)
34+
35+
36+
def wait_for_button():
37+
wait_all_released()
38+
while True:
39+
for pin_number, name in BUTTONS.items():
40+
if mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
41+
while mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
42+
sleep_ms(20)
43+
return name
44+
sleep_ms(20)
45+
46+
47+
for pin_number in BUTTONS:
48+
mcp.setup(pin_number, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP)
49+
50+
print("=================================")
51+
print("Combination Lock")
52+
print("=================================\n")
53+
print("Enter the secret D-PAD sequence.\n")
54+
55+
entered = []
56+
57+
while True:
58+
button = wait_for_button()
59+
entered.append(button)
60+
61+
print("Input:", "-".join(entered))
62+
63+
expected_prefix = SECRET[: len(entered)]
64+
if entered != expected_prefix:
65+
print("WRONG")
66+
entered = []
67+
print()
68+
continue
69+
70+
if len(entered) == len(SECRET):
71+
print("UNLOCKED")
72+
entered = []
73+
print()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
Simple D-PAD counter.
3+
4+
UP -> increment
5+
DOWN -> decrement
6+
LEFT -> reset
7+
RIGHT -> print current value
8+
"""
9+
10+
from time import sleep_ms
11+
12+
from machine import I2C, Pin
13+
from mcp23009e import MCP23009E
14+
from mcp23009e.const import *
15+
16+
bus = I2C(1)
17+
reset = Pin("RST_EXPANDER", Pin.OUT)
18+
19+
mcp = MCP23009E(bus, address=MCP23009_I2C_ADDR, reset_pin=reset)
20+
21+
BUTTONS = {
22+
MCP23009_BTN_UP: "UP",
23+
MCP23009_BTN_DOWN: "DOWN",
24+
MCP23009_BTN_LEFT: "LEFT",
25+
MCP23009_BTN_RIGHT: "RIGHT",
26+
}
27+
28+
29+
def wait_all_released():
30+
while True:
31+
if all(mcp.get_level(pin_number) == MCP23009_LOGIC_HIGH for pin_number in BUTTONS):
32+
return
33+
sleep_ms(20)
34+
35+
36+
def wait_for_button():
37+
wait_all_released()
38+
while True:
39+
for pin_number, name in BUTTONS.items():
40+
if mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
41+
while mcp.get_level(pin_number) == MCP23009_LOGIC_LOW:
42+
sleep_ms(20)
43+
return name
44+
sleep_ms(20)
45+
46+
47+
for pin_number in BUTTONS:
48+
mcp.setup(pin_number, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP)
49+
50+
value = 0
51+
52+
print("=================================")
53+
print("D-PAD Counter")
54+
print("=================================\n")
55+
print("UP=+1 DOWN=-1 LEFT=reset RIGHT=print\n")
56+
57+
while True:
58+
button = wait_for_button()
59+
60+
if button == "UP":
61+
value += 1
62+
print("Increment ->", value)
63+
elif button == "DOWN":
64+
value -= 1
65+
print("Decrement ->", value)
66+
elif button == "LEFT":
67+
value = 0
68+
print("Reset ->", value)
69+
elif button == "RIGHT":
70+
print("Current value ->", value)

0 commit comments

Comments
 (0)