# ESP32 and Mycropython: Programming your Hardware
# Author: Mordechai Bar Natan
#
# Lesson 9: Create a menu
# https://wokwi.com/projects/394786889909321729
#
# Remember:
# On a LED, the long leg is the anode (+). Connect it to pin #2.
# The short leg is the cathode (-). Connect it to GND.
# On a momentary switch (button), connect one side to pin #4 and the other side to GND.
# The display has 4 connections: GND, VCC (to 3.3V), SCL (pin #22) & SDA (pin #21).
# The + on the buzzer connects to pin #23 on the ESP32.
#
# References
# https://docs.micropython.org/en/latest/library/machine.Pin.html
# https://docs.micropython.org/en/latest/esp8266/tutorial/ssd1306.html#ssd1306
# https://docs.micropython.org/en/latest/esp32/quickref.html#pwm-pulse-width-modulation
# https://micropython-on-wemos-d1-mini.readthedocs.io/en/latest/basics.html#beepers
#
# As the components do not change, all components are part of the program, even if not in use
# future work
from machine import Pin, SoftI2C, ADC, PWM
from time import sleep, sleep_ms
from ssd1306 import SSD1306_I2C
oled_scl_pin = 22 # Orange cable
oled_sda_pin = 21 # Blue cable
red_led_pin = 2
blue_led_pin = 15
left_button_pin = 4
right_button_pin = 17
buzzer_pin = 23 # Purple cable
i2c = SoftI2C(scl=Pin(oled_scl_pin), sda=Pin(oled_sda_pin), freq=4000000)
oled_w = 128 # display width (0..127)
oled_h = 64 # display hight (0..63)
oled = SSD1306_I2C(oled_w, oled_h, i2c) # oled will be the display bject
red_led = PWM(Pin(red_led_pin, Pin.OUT)) # need PWM to "fade" the LED
blue_led = PWM(Pin(blue_led_pin, Pin.OUT)) # need PWM to "fade" the LED
left_button = Pin(left_button_pin, Pin.IN, Pin.PULL_UP)
right_button = Pin(right_button_pin, Pin.IN, Pin.PULL_UP)
red_led_state = 0
blue_led_state = 0
left_button_state = 0
right_button_state = 0
red_led.freq(1000) # Set PWM frequency
blue_led.freq(1000) # Set PWM frequency
red_led.duty(0) # turn off LED
blue_led.duty(0) # turn off LED
def play_note(note=1047, duration_ms=100, active_duty=200): # use my default values
buzzer = PWM(Pin(buzzer_pin, Pin.OUT)) # need PWM to generate (modulate) tones
buzzer.freq(note) # tune
buzzer.duty(active_duty) # 50% duty cycle for half volume, # Max volume is a duty value of 512
sleep_ms(duration_ms) # tone duration
buzzer.duty(0) # Turn off the buzzer
buzzer.deinit() # deinitialize the object
# Define countries
countries = ["Argentina", "Brazil", "Canada", "Denmark"]
current_country_index = 0
# Function to display countries
def display_countries(selected_index):
oled.fill(0) # Clear display
for i, country in enumerate(countries):
if i == selected_index:
oled.fill_rect(0, i * 12, oled_w, 12, 1) # Inverse background
oled.text(country, 0, i * 12, 0)
else:
oled.text(country, 0, i * 12, 1)
oled.show()
# Display instructions
oled.fill(0)
oled.text("Use Left button", 0, 0, 1)
oled.text(" to cycle", 0, 10, 1)
oled.text("Use Right button", 0, 20, 1)
oled.text(" to select", 0, 30, 1)
oled.show()
sleep(5)
# Initial display
display_countries(current_country_index)
# Menu cycle
while True:
# Check if left button is pressed
if not left_button.value():
# Cycle to next country
current_country_index = (current_country_index + 1) % len(countries)
# Update display
display_countries(current_country_index)
# Debounce delay
while not left_button.value():
pass
# Check if right button is pressed
if not right_button.value():
# Selected country
selected_country = countries[current_country_index]
# Display selected country
oled.fill(0)
oled.text("Selected:", 0, 0, 1)
oled.text(selected_country, 0, 10, 1)
oled.show()
# Debounce delay
while not right_button.value():
pass