diff --git a/examples/ADC.py b/examples/ADC.py new file mode 100644 index 0000000..0fac936 --- /dev/null +++ b/examples/ADC.py @@ -0,0 +1,32 @@ +""" +Reads an analog input connected to ADC0. + +Connect the middle pin of your potentiometer to ADC0, and the other two pins to 3.3V and GND. +""" + +from explorer import Explorer2350 +from machine import ADC +import time + +board = Explorer2350() + +display = board.display + +# lets set up some pen colours to make drawing easier +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) + +pot = ADC(0) + +# alternatively, you could specify the pin number like this: +# pot = ADC(40) + +while True: + display.set_pen(BLACK) + display.clear() + display.set_pen(WHITE) + # read the potentiometer value, it's a number between 0 and 65535 which represents a voltage between 0v and 3.3v + pot_value = pot.read_u16() + display.text(f"{pot_value}", 0, 0, 320, 4) + display.update() + time.sleep(0.1) diff --git a/examples/LTR559_demo.py b/examples/LTR559_demo.py deleted file mode 100644 index 6de8a8b..0000000 --- a/examples/LTR559_demo.py +++ /dev/null @@ -1,28 +0,0 @@ -import time -from breakout_ltr559 import BreakoutLTR559 -from machine import Pin, I2C -from picographics import PicoGraphics, DISPLAY_EXPLORER - -i2c = I2C(0, sda=Pin(20), scl=Pin(21)) -ltr = BreakoutLTR559(i2c) -display = PicoGraphics(display=DISPLAY_EXPLORER) - -part_id = ltr.part_id() -print("Found LTR559. Part ID: 0x", '{:02x}'.format(part_id), sep="") - -# lets set up some pen colours to make drawing easier -WHITE = display.create_pen(255, 255, 255) -BLACK = display.create_pen(0, 0, 0) -RED = display.create_pen(255, 0, 0) -GREY = display.create_pen(125, 125, 125) - -while True: - reading = ltr.get_reading() - if reading is not None: - display.set_pen(BLACK) - display.clear() - display.set_pen(WHITE) - display.text(f"Lux: {reading[BreakoutLTR559.LUX]:.0f} Prox: {reading[BreakoutLTR559.PROXIMITY]}", 0, 0, 320, 7) - display.update() - - time.sleep(0.1) diff --git a/examples/button_test.py b/examples/button_test.py index 76d5940..bf73b47 100644 --- a/examples/button_test.py +++ b/examples/button_test.py @@ -1,4 +1,6 @@ -# This example shows you a simple, non-interrupt way of reading Pico Explorer's buttons with a loop that checks to see if buttons are pressed. +""" +This example shows you a simple, non-interrupt way of reading Pico Explorer's buttons with a loop that checks to see if buttons are pressed. +""" import time from picographics import PicoGraphics, DISPLAY_EXPLORER, PEN_P4 @@ -34,7 +36,7 @@ def clear(): display.set_font("bitmap8") while True: - if button_a.value() == 0: # if a button press is detected then... + if button_a.value() == 0: # if a button press is detected then... clear() # clear to black display.set_pen(WHITE) # change the pen colour display.text("Button A pressed", 10, 10, 240, 4) # display some text on the screen diff --git a/examples/explorer-sensor-stick-demo.py b/examples/explorer_sensor_stick_demo.py similarity index 98% rename from examples/explorer-sensor-stick-demo.py rename to examples/explorer_sensor_stick_demo.py index b457e78..a21a45b 100644 --- a/examples/explorer-sensor-stick-demo.py +++ b/examples/explorer_sensor_stick_demo.py @@ -33,4 +33,4 @@ if temperature is not None: display.text(f"Temperature: {temperature:.2f}°C,\nHumidity: {humidity:.0f}%,\nPressure: {pressure/100:.0f}hPa", 0, 180, 320, 3) display.update() - time.sleep(0.1) \ No newline at end of file + time.sleep(0.1) diff --git a/examples/external_buttons.py b/examples/external_buttons.py new file mode 100644 index 0000000..1abd751 --- /dev/null +++ b/examples/external_buttons.py @@ -0,0 +1,51 @@ +""" +Connect (up to) 3 external buttons to Explorer. + +We're connecting our yellow button to GPIO 0, a red button to GPIO 1 and a blue button to GPIO 3. The other side of each button should be wired to ground. + +Note that if you're using our square buttons, you should connect wires to two pins that are diagonally opposite each other. +""" + +from machine import Pin +import time +from explorer import Explorer2350 + +board = Explorer2350() + +display = board.display + +yellow_button = Pin(0, Pin.IN, Pin.PULL_UP) +blue_button = Pin(1, Pin.IN, Pin.PULL_UP) +red_button = Pin(2, Pin.IN, Pin.PULL_UP) + +# lets set up some pen colours to make drawing easier +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +YELLOW = display.create_pen(0, 255, 255) +BLUE = display.create_pen(0, 0, 255) +RED = display.create_pen(255, 0, 0) + + +while True: + display.set_pen(BLACK) + display.clear() + display.set_pen(WHITE) + display.text("Wire up some buttons to GP0, GP1 and GP2, and push 'em!", 0, 0, 320, 4) + # because we're using Pin.PULL_UP the logic is reversed - '0' is pushed and '1' is unpushed + if yellow_button.value() == 0: + display.set_pen(BLACK) + display.clear() + display.set_pen(YELLOW) + display.text("Yellow button pushed", 0, 0, 320, 4) + if blue_button.value() == 0: + display.set_pen(BLACK) + display.clear() + display.set_pen(BLUE) + display.text("Blue button pushed", 0, 0, 320, 4) + if red_button.value() == 0: + display.set_pen(BLACK) + display.clear() + display.set_pen(RED) + display.text("Red button pushed", 0, 0, 320, 4) + display.update() + time.sleep(0.01) diff --git a/examples/explorer.py b/examples/lib/explorer.py similarity index 91% rename from examples/explorer.py rename to examples/lib/explorer.py index 4d18a61..1c4e9b9 100644 --- a/examples/explorer.py +++ b/examples/lib/explorer.py @@ -50,7 +50,7 @@ class Explorer2350(): SWITCH_X_PIN = 17 SWITCH_Y_PIN = 18 SWITCH_Z_PIN = 19 - + I2C_SDA_PIN = 20 I2C_SCL_PIN = 21 @@ -61,6 +61,20 @@ class Explorer2350(): SERVO_3_PIN = 7 SERVO_4_PIN = 6 + ADC_0_PIN = 40 + ADC_1_PIN = 41 + ADC_2_PIN = 42 + ADC_3_PIN = 43 + ADC_4_PIN = 44 + ADC_5_PIN = 45 + + GPIO_0_PIN = 0 + GPIO_1_PIN = 1 + GPIO_2_PIN = 2 + GPIO_3_PIN = 3 + GPIO_4_PIN = 4 + GPIO_5_PIN = 5 + PWM_AUDIO_PIN = 12 AMP_EN_PIN = 13 @@ -70,7 +84,7 @@ class Explorer2350(): def __init__(self, init_servos=True): # Free up hardware resources gc.collect() - + self.display = PicoGraphics(display=DISPLAY_EXPLORER) # Set up the servos, if the user wants them @@ -88,12 +102,6 @@ def __init__(self, init_servos=True): self.audio_pwm = PWM(Pin(self.PWM_AUDIO_PIN)) self.__volume = self.DEFAULT_VOLUME - # Set up the user switch - self.__switch = Pin(self.USER_SW_PIN, Pin.IN, Pin.PULL_DOWN) - - def switch_pressed(self): - return self.__switch.value() - def play_tone(self, frequency): try: self.audio_pwm.freq(frequency) @@ -129,4 +137,4 @@ def mute_audio(self): self.__amp_en.off() def unmute_audio(self): - self.__amp_en.on() \ No newline at end of file + self.__amp_en.on() diff --git a/examples/main.py b/examples/main.py new file mode 100644 index 0000000..52056b3 --- /dev/null +++ b/examples/main.py @@ -0,0 +1,155 @@ +# Explorer boot menu/loader. + +import gc +import time +from os import listdir +from picographics import PicoGraphics, DISPLAY_EXPLORER, PEN_RGB332 +from machine import Pin + + +def hsv_to_rgb(h: float, s: float, v: float) -> tuple[float, float, float]: + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + v = int(v * 255) + t = int(t * 255) + p = int(p * 255) + q = int(q * 255) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +def get_applications() -> list[dict[str, str]]: + # fetch a list of the applications that are stored in the filesystem + applications = [] + for file in listdir(): + if file.endswith(".py") and file != "main.py": + # convert the filename from "something_or_other.py" to "Something Or Other" + # via weird incantations and a sprinkling of voodoo + title = " ".join([v[:1].upper() + v[1:] for v in file[:-3].split("_")]) + + applications.append( + { + "file": file, + "title": title + } + ) + + # sort the application list alphabetically by title and return the list + return sorted(applications, key=lambda x: x["title"]) + + +def prepare_for_launch() -> None: + for k in locals().keys(): + if k not in ("__name__", + "application_file_to_launch", + "gc"): + del locals()[k] + gc.collect() + + +def menu() -> str: + applications = get_applications() + + button_x = Pin(17, Pin.IN, Pin.PULL_UP) + button_y = Pin(18, Pin.IN, Pin.PULL_UP) + button_a = Pin(16, Pin.IN, Pin.PULL_UP) + + display = PicoGraphics(display=DISPLAY_EXPLORER, pen_type=PEN_RGB332) + display.set_backlight(1.0) + + selected_item = 2 + scroll_position = 2 + target_scroll_position = 2 + + selected_pen = display.create_pen(255, 255, 255) + unselected_pen = display.create_pen(80, 80, 100) + background_pen = display.create_pen(50, 50, 70) + shadow_pen = display.create_pen(0, 0, 0) + + while True: + t = time.ticks_ms() / 1000.0 + + if button_x.value() == 0: + target_scroll_position -= 1 + target_scroll_position = target_scroll_position if target_scroll_position >= 0 else len(applications) - 1 + time.sleep(0.05) + + if button_y.value() == 0: + target_scroll_position += 1 + target_scroll_position = target_scroll_position if target_scroll_position < len(applications) else 0 + time.sleep(0.05) + + if button_a.value() == 0: + time.sleep(0.05) + + return applications[selected_item]["file"] + + display.set_pen(background_pen) + display.clear() + + scroll_position += (target_scroll_position - scroll_position) / 5 + + grid_size = 40 + for y in range(0, 240 // grid_size): + for x in range(0, 320 // grid_size): + h = x + y + int(t * 5) + h = h / 50.0 + r, g, b = hsv_to_rgb(h, 0.5, 1) + + display.set_pen(display.create_pen(r, g, b)) + display.rectangle(x * grid_size, y * grid_size, grid_size, grid_size) + + # work out which item is selected (closest to the current scroll position) + selected_item = round(target_scroll_position) + + for list_index, application in enumerate(applications): + distance = list_index - scroll_position + + text_size = 4 if selected_item == list_index else 3 + + # center text horixontally + title_width = display.measure_text(application["title"], text_size) + text_x = int(160 - title_width / 2) + + row_height = text_size * 5 + 20 + + # center list items vertically + text_y = int(120 + distance * row_height - (row_height / 2)) + + # draw the text, selected item brightest and with shadow + if selected_item == list_index: + display.set_pen(shadow_pen) + display.text(application["title"], text_x + 1, text_y + 1, -1, text_size) + + text_pen = selected_pen if selected_item == list_index else unselected_pen + display.set_pen(text_pen) + display.text(application["title"], text_x, text_y, -1, text_size) + + display.update() + + +# The application we will be launching. This should be ouronly global, so we can +# drop everything else. +application_file_to_launch = menu() + +# Run whatever we've set up to. +# If this fails, we'll exit the script and drop to the REPL, which is +# fairly reasonable. +prepare_for_launch() +__import__(application_file_to_launch) diff --git a/examples/multiple_servos.py b/examples/multiple_servos.py index 74a6b22..2c34d6f 100644 --- a/examples/multiple_servos.py +++ b/examples/multiple_servos.py @@ -55,4 +55,4 @@ # Disable the servos for s in board.servos: - s.disable() \ No newline at end of file + s.disable() diff --git a/examples/simple_menu.py b/examples/simple_menu.py new file mode 100644 index 0000000..5219f2f --- /dev/null +++ b/examples/simple_menu.py @@ -0,0 +1,100 @@ +import time +from picographics import PicoGraphics, DISPLAY_EXPLORER, PEN_RGB565 +from pimoroni import RGBLED +from machine import Pin + +button_a = Pin(16, Pin.IN, Pin.PULL_UP) +button_x = Pin(17, Pin.IN, Pin.PULL_UP) +button_y = Pin(18, Pin.IN, Pin.PULL_UP) + +display = PicoGraphics(display=DISPLAY_EXPLORER, pen_type=PEN_RGB565, rotate=0) +display.set_backlight(0.8) + +# set up constants for drawing +WIDTH, HEIGHT = display.get_bounds() +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(255, 0, 0) +GREEN = display.create_pen(0, 255, 0) +BLUE = display.create_pen(0, 0, 255) +WHITE = display.create_pen(255, 255, 255) +PURPLE = display.create_pen(255, 0, 255) + + +class Menu(object): + def __init__(self): + self.items = ["Red", "Green", "Blue", "Purple"] + self.selected = 0 + self.shadow_offset = 2 + self.cursor = "<-" + self.colour = BLACK + self.title = "Simple Menu" + + # A function to draw only the menu elements. + def draw_menu(self): + display.set_pen(WHITE) + display.clear() + display.set_pen(BLACK) + length = display.measure_text(self.title, 4) + display.text(self.title, WIDTH // 2 - length // 2 + self.shadow_offset, 10 + self.shadow_offset, WIDTH, 4) + display.set_pen(self.colour) + display.text(self.title, WIDTH // 2 - length // 2, 10, WIDTH, 4) + + display.set_pen(BLACK) + for item in range(len(self.items)): + length = display.measure_text(self.items[item], 3) + if self.selected == item: + display.set_pen(self.colour) + display.text(self.cursor, length + 40, HEIGHT // 2 + item * 20, WIDTH, 3) + + display.text(self.items[item], 30, HEIGHT // 2 + item * 20, WIDTH, 3) + + display.set_pen(self.colour) + display.rectangle(0, HEIGHT - 10, WIDTH, 10) + display.set_pen(BLACK) + + # Do a thing based on the currently selected menu item + # For our example we'll be changing the text + def process_selected(self): + if self.selected == 0: + self.colour = RED + + if self.selected == 1: + self.colour = GREEN + + if self.selected == 2: + self.colour = BLUE + + if self.selected == 3: + self.colour = PURPLE + + def user_input(self): + # Process the user input and update the currently selected item + if button_y.value() == 0: + if self.selected + 1 < len(self.items): + self.selected += 1 + else: + self.selected = 0 + time.sleep(0.2) # debounce + + if button_x.value() == 0: + if self.selected > 0: + self.selected -= 1 + else: + self.selected = len(self.items) - 1 + time.sleep(0.2) # debounce + + if button_a.value() == 0: + self.process_selected() + time.sleep(0.2) # debounce + + +menu = Menu() + +while True: + + menu.draw_menu() + menu.user_input() + + display.update() + + time.sleep(1.0 / 20) diff --git a/examples/single_servo.py b/examples/single_servo.py index 035080a..1fa2f3e 100644 --- a/examples/single_servo.py +++ b/examples/single_servo.py @@ -9,22 +9,44 @@ # Create a new Explorer2350 board = Explorer2350() +display = board.display + +# lets set up some pen colours to make drawing easier +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) + +display.set_pen(BLACK) +display.clear() +display.set_pen(WHITE) +display.update() + +display.text("Attach a servo to slot 1!", 0, 0, 320, 3) +display.update() +time.sleep(2) + # Access the servo from Explorer and enable it (this puts it at the middle) s = board.servos[SERVO_1] -print(board.servos) +display.text("Enable servo", 0, 50, 320, 3) +display.update() s.enable() time.sleep(2) # Go to min +display.text("Go to min", 0, 70, 320, 3) +display.update() s.to_min() time.sleep(2) # Go to max +display.text("Go to max", 0, 90, 320, 3) +display.update() s.to_max() time.sleep(2) # Go back to mid +display.text("Back to middle", 0, 110, 320, 3) +display.update() s.to_mid() time.sleep(2) @@ -36,12 +58,16 @@ # Do a sine sweep +display.text(f"Do {SWEEPS} sine sweeps", 0, 130, 320, 3) +display.update() for j in range(SWEEPS): for i in range(360): s.value(math.sin(math.radians(i)) * SWEEP_EXTENT) time.sleep(0.02) # Do a stepped sweep +display.text(f"Do {SWEEPS} stepped sweeps", 0, 150, 320, 3) +display.update() for j in range(SWEEPS): for i in range(0, STEPS): s.to_percent(i, 0, STEPS, 0.0 - SWEEP_EXTENT, SWEEP_EXTENT) @@ -51,4 +77,6 @@ time.sleep(STEPS_INTERVAL) # Disable the servo -s.disable() \ No newline at end of file +display.text("Disable servo", 0, 170, 320, 3) +display.update() +s.disable() diff --git a/examples/weather_station_bme280.py b/examples/weather_station_bme280.py index b45cc8c..8b567ff 100644 --- a/examples/weather_station_bme280.py +++ b/examples/weather_station_bme280.py @@ -95,15 +95,22 @@ def describe_humidity(humidity): return description -while True: - # Create a new JPEG decoder for our PicoGraphics - j = jpegdec.JPEG(display) +# Create a new JPEG decoder for our PicoGraphics +j = jpegdec.JPEG(display) + +background_jpg = False + +try: + j.open_file("backgroundforscreen.jpg") + background_jpg = True +except OSError: + print("Background not found - copy backgroundforscreen.jpg to your Explorer") - # Attempt to display a fancy background, if the file is present - try: - j.open_file("backgroundforscreen.jpg") +while True: + # attempt to display a fancy background, if the file is present + if background_jpg is True: j.decode(0, 0, jpegdec.JPEG_SCALE_FULL, dither=True) - except: + else: display.set_pen(BLACK) display.clear() @@ -149,4 +156,4 @@ def describe_humidity(humidity): display.update() # wait for a short time to stop Thonny from freaking out - time.sleep(0.1) \ No newline at end of file + time.sleep(0.1)