# ESP32 and Mycropython: Programming your Hardware
# Author: Mordechai Bar Natan
#
# Lesson 8: Play C5 scale and short melody
# https://wokwi.com/projects/395336039274989569
#
# 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
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
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, wait_ms=100, duty=200):
for note in song:
play_note(note, wait_ms, duty)
# C5 scale up
scale_up = [ C5, D5, E5, F5, G5, A5, B5, C6, ]
# Display and play tune
oled.fill(0)
oled.text("C5 scale up", 0, 0, 1)
oled.show()
play_song(scale_up, 400, 50)
sleep(1)
# C5 scale down
scale_down = [ C6, B5, A5, G5, F5, E5, D5, C5, ]
oled.text("C5 scale down", 0, 10, 1)
oled.show()
# play_song(scale_down, 400, 50) # same method as scale up
# another method to play the scale
for k in range(len(scale_down)): # 8 notes, loop from 0 to 7
play_note(scale_down[k], 400, 50)
sleep(1)
# short melody, will play notes with different durations (times)
melody = [ C4, G3, G3, A3, G3, 0, B3, C4, ]
# note durations, 4=quarter note / 8=eighth note
melody_timing = [ 4, 8, 8, 4, 4, 4, 4, 4, ]
oled.text("short melody", 0, 20, 1)
oled.show()
for j in range(len(melody)): # 8 notes, loop from 0 to 7
play_note(melody[j], int(1000/melody_timing[j]), 50)
sleep(1)