# ESP32 and Mycropython: Programming your Hardware
# Author: Mordechai Bar Natan
#
# Lesson 9: Song menu
# https://wokwi.com/projects/395400553837319169
#
# 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
from machine import Pin, SoftI2C, ADC, PWM
from time import sleep, sleep_ms
from ssd1306 import SSD1306_I2C
from music_notes import * # my music notes library
from games_themes import * # my games themes library
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=50): # use my default values
buzzer = PWM(Pin(buzzer_pin, Pin.OUT)) # need PWM to generate (modulate) tones
if note != 0: # 0 denotes rest notes
buzzer.freq(note) # tune
buzzer.duty(active_duty) # duty of 50 is ok, more than 300 is distorted, just try
else:
buzzer.duty(0) # Turn off the buzzer
sleep_ms(duration_ms) # tone duration
buzzer.duty(0) # Turn off the buzzer
buzzer.deinit() # deinitialize the object
def play_song(song, timing, tempo_adjustment=1, duty=50): # function version 3
for i in range(len(song)): # for each note
play_note(song[i], int(1000*tempo_adjustment/timing[i]), duty)
def display_menu(selected_index): # Function to display the menu (songs)
oled.fill(0) # Clear display
for i, item in enumerate(menu_list):
if i == selected_index:
oled.fill_rect(0, i * 12, oled_w, 12, 1) # Inverse background
oled.text(item, 0, i * 12, 0)
else:
oled.text(item, 0, i * 12, 1)
oled.show()
# Display and play tune
# oled.fill(0)
# oled.text("short melody", 0, 20, 1)
# oled.show()
play_song(tetris, tetris_timing, 1.8) # need lenght adjustment
sleep(1)
play_song(mario, mario_timing, 1.3) # need lenght adjustment
sleep(1)
play_song(pacman, pacman_timing, 2.8) # need lenght adjustment
sleep(1)
play_song(doom, doom_timing, 1.1) # need lenght adjustment
sleep(1)
# Define menu (song) list
menu_list = ["song1", " song2", " song3", " song4"]
current_menu_index = 0
# here we start main program
# 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_menu(current_menu_index)
# Menu cycle
while True:
# Check if left button is pressed
if not left_button.value():
# Cycle to next menu item
current_menu_index = (current_menu_index + 1) % len(menu_list)
# Update display
display_menu(current_menu_index)
# Debounce delay
while not left_button.value():
pass
# Check if right button is pressed
if not right_button.value():
# Selected country
selected_menu_item = menu_list[current_menu_index]
# Display selected country
oled.fill(0)
oled.text("Selected:", 0, 0, 1)
oled.text(selected_menu_item, 0, 10, 1)
oled.show()
# Debounce delay
while not right_button.value():
pass
# Display and play tune
# oled.fill(0)
# oled.text("short melody", 0, 20, 1)
# oled.show()
# play_song(melody, melody_timing)
# sleep(1)