All sorted now. This board is easy to use and addresses the lack of available IO and ADC pins on the PRESTO. A very useful PRESTO add-on.
Here is a demo with Potentiometers, voltages, PWM, LEDs, simple graphics and basic digital IO. All very straight forward.
# IO Expander Demo on Presto
# Tony Goodhew 16th February 2025
# Requirements: IO expander on Qw/ST port
# Button to GND on Pin 2
# 10K potentiometer wiper on 10, + 3.3v and GND
# LED with 330 ohm resistor on pin 6
import time
from pimoroni_i2c import PimoroniI2C
from breakout_ioexpander import BreakoutIOExpander
from presto import Presto
from picovector import ANTIALIAS_FAST, PicoVector, Polygon, Transform
# Setup for the Presto display
presto = Presto(full_res=True)
display = presto.display
# Pico Vector setup section
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_FAST)
t = Transform()
vector.set_font("Roboto-Medium.af", 54)
vector.set_font_letter_spacing(100)
vector.set_font_word_spacing(100)
vector.set_transform(t)
vector.set_font_size(20)
# Setup IO Expander
PINS_PRESTO = {"sda": 40, "scl": 41}
i2c = PimoroniI2C(**PINS_PRESTO)
ioe = BreakoutIOExpander(i2c, address=0x18)
def clean(): # Clear the screen to Black
display.set_pen(BLACK)
display.clear()
# Create some colours
BLUE = display.create_pen(20,0,255)
WHITE = display.create_pen(255, 255, 255)
RED = display.create_pen(255,0,0)
ORANGE = display.create_pen(245, 165, 4)
GREEN = display.create_pen(0,255,0)
PINK = display.create_pen(250, 125, 180)
CYAN = display.create_pen(0,255,255)
MAGENTA = display.create_pen(255,0,255)
BLACK = display.create_pen(0, 0, 0)
YELLOW = display.create_pen(255, 255, 0)
clean()
display.set_pen(RED)
vector.set_font_size(70)
vector.text("IO Expander",40,120)
display.set_pen(BLUE)
vector.set_font_size(20)
vector.text("Tony Goodhew, Leicester UK",120,450)
presto.update()
time.sleep(1)
# 10K Potentiometer - ADC input
ioe_adc_pin = 10
ioe.set_mode(ioe_adc_pin, BreakoutIOExpander.PIN_ADC)
for count in range(60):
clean()
display.set_pen(GREEN)
vector.set_font_size(35)
vector.text("Turn the Potentiometer",10,50)
pot = ioe.input(ioe_adc_pin) // 4 # 10 bit resolution
h = int(pot/2.5)
display.set_pen(YELLOW)
vector.set_font_size(40)
vector.text("Pot Value: " + str(int(pot)),10,150)
display.set_pen(ORANGE)
display.rectangle(350,430-h,60,h)
display.set_pen(BLUE)
display.rectangle(335,431,90,4)
voltage = round(ioe.input_as_voltage(ioe_adc_pin),2)
vector.text("Volts: " + str(voltage),10,200)
presto.update()
time.sleep(0.2)
clean()
display.set_pen(BLUE)
vector.text("PWM on LED",10,50)
display.set_pen(YELLOW)
vector.text("Press button to start",10,150)
presto.update()
ioe_button_pin = 2
ioe.set_mode(ioe_button_pin, BreakoutIOExpander.PIN_IN_PU)
ioe_pwm_pin = 6
button_state = ioe.input(ioe_button_pin)
while button_state == 1:
button_state = ioe.input(ioe_button_pin)
# Settings to produce a 50Hz output from the 24MHz clock.
# 24,000,000 Hz / 8 = 3,000,000 Hz
# 3,000,000 Hz / 60,000 Period = 50 Hz
divider = 8
period = 60000
ioe.set_pwm_period(period)
ioe.set_pwm_control(divider)
ioe.set_mode(ioe_pwm_pin, BreakoutIOExpander.PIN_PWM)
clean()
display.set_pen(BLUE)
vector.text("PWM on LED",10,50)
display.set_pen(YELLOW)
presto.update()
time.sleep(0.3)
for count in range(2):
# Brightening
for duty_cycle in range(0, 65536,2048):
clean()
display.set_pen(BLUE)
# display.text("PWM on LED",10,50,400,4)
vector.text("PWM on LED",10,50)
display.set_pen(YELLOW)
vector.text("Duty cycle: "+ str(duty_cycle),50,200)
ioe.output(ioe_pwm_pin, duty_cycle)
presto.update()
time.sleep(0.5)
# Dimming
for duty_cycle in range(65535, -1,-2048):
clean()
display.set_pen(BLUE)
vector.text("PWM on LED",10,50)
display.set_pen(YELLOW)
vector.text("Duty cycle: "+ str(duty_cycle),50,200)
ioe.output(ioe_pwm_pin, duty_cycle)
presto.update()
clean()
display.set_pen(BLUE)
vector.text("PWM on LED",10,50)
ioe.output(ioe_pwm_pin, 0) # LED off
display.set_pen(YELLOW)
vector.text("Duty cycle: "+ str(0),50,200)
presto.update()
time.sleep(0.6)
ioe_LED_pin = 6 # LED now digital on/off
ioe.set_mode(ioe_LED_pin, BreakoutIOExpander.PIN_OUT)
clean()
display.set_pen(GREEN)
vector.text("Basic LED Flashing",10,50)
presto.update()
for i in range(10):
ioe.output(ioe_LED_pin, 1)
time.sleep(0.2)
ioe.output(ioe_LED_pin, 0)
time.sleep(0.2)
clean()
display.set_pen(GREEN)
vector.text("Button Control of LED",10,50)
display.set_pen(YELLOW)
vector.text("Press button ON/OFF",10,150)
presto.update()
ioe.output(ioe_LED_pin, 0) # LED OFF
future = time.time() + 8 # 8 seconds
while time.time() < future:
button_state = not(ioe.input(ioe_button_pin)) # True if pressed
ioe.output(ioe_LED_pin, button_state)
colour = RED
if button_state == 0:
colour = BLACK
display.set_pen(colour)
display.circle(240,300,50)
presto.update()
ioe.output(ioe_LED_pin, 0) # LED OFF
clean()
presto.update()
I’ve updated the code above to use a vector font and inverted the button press action so that the LED lights up when the button is pressed - more logical?
Where do you put your sensor stick? A bit of Blu Tack holds it neatly on the front with light sensor pointing into the room.
Have fun!