# ESP32 and Mycropython: Programming your Hardware
# Author: Mordechai Bar Natan
#
# Lesson 9: Play a song
# https://wokwi.com/projects/394870368777379841
#
# 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
# Notes and their equivalent frequency
# Syllabic Notes DO RE MI FA SOL LA SI
# Alphabetical Notes C D E F G A B
# Octave 0 ********************
B0 = 31 # B
# Octave 1 ********************
C1 = 33 # C
CS1 = 35 # C#/Db
D1 = 37 # D
DS1 = 39 # D#/Eb
E1 = 41 # E
F1 = 44 # F
FS1 = 46 # F#/Gb
G1 = 49 # G
GS1 = 52 # G#/Ab
A1 = 55 # A
AS1 = 58 # A#/Bb
B1 = 62 # B
# Octave 2 ********************
C2 = 65 # C
CS2 = 69 # C#/Db
D2 = 73 # D
DS2 = 78 # D#/Eb
E2 = 82 # E
F2 = 87 # F
FS2 = 93 # F#/Gb
G2 = 98 # G
GS2 = 104 # G#/Ab
A2 = 110 # A
AS2 = 117 # A#/Bb
B2 = 123 # B
# Octave 3 ********************
C3 = 131 # C
CS3 = 139 # C#/Db
D3 = 147 # D
DS3 = 156 # D#/Eb
E3 = 165 # E
F3 = 175 # F
FS3 = 185 # F#/Gb
G3 = 196 # G
GS3 = 208 # G#/Ab
A3 = 220 # A
AS3 = 233 # A#/Bb
B3 = 247 # B
# Octave 4 ********************
C4 = 262 # C
CS4 = 277 # C#/Db
D4 = 294 # D
DS4 = 311 # D#/Eb
E4 = 330 # E
F4 = 349 # F
FS4 = 370 # F#/Gb
G4 = 392 # G
GS4 = 415 # G#/Ab
A4 = 440 # A
AS4 = 466 # A#/Bb
B4 = 494 # B
# Octave 5 ********************
C5 = 523 # C
CS5 = 554 # C#/Db
D5 = 587 # D
DS5 = 622 # D#/Eb
E5 = 659 # E
F5 = 698 # F
FS5 = 740 # F#/Gb
G5 = 784 # G
GS5 = 831 # G#/Ab
A5 = 880 # A
AS5 = 932 # A#/Bb
B5 = 988 # B
# Octave 6 ********************
C6 = 1047 # C
CS6 = 1109 # C#/Db
D6 = 1175 # D
DS6 = 1245 # D#/Eb
E6 = 1319 # E
F6 = 1397 # F
FS6 = 1480 # F#/Gb
G6 = 1568 # G
GS6 = 1661 # G#/Ab
A6 = 1760 # A
AS6 = 1865 # A#/Bb
B6 = 1976 # B
# Octave 7 ********************
C7 = 2093 # C
CS7 = 2217 # C#/Db
D7 = 2349 # D
DS7 = 2489 # D#/Eb
E7 = 2637 # E
F7 = 2794 # F
FS7 = 2960 # F#/Gb
G7 = 3136 # G
GS7 = 3322 # G#/Ab
A7 = 3520 # A
AS7 = 3729 # A#/Bb
B7 = 3951 # B
# Octave 8 ********************
C8 = 4186 # C
CS8 = 4435 # C#/Db
D8 = 4699 # D
DS8 = 4978 # D#/Eb
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, wait_ms=100, active_duty=50):
for note in song:
play_note(note, wait_ms, active_duty)
# This is the list of notes for mario theme
# 0 denotes rest notes
mario = [
E7, E7, 0, E7, 0, C7, E7, 0,
G7, 0, 0, 0, G6, 0, 0, 0,
C7, 0, 0, G6, 0, 0, E6, 0,
0, A6, 0, B6, 0,AS6, A6, 0,
G6, E7, 0, G7, A7, 0, F7, G7,
0, E7, 0, C7, D7, B6, 0, 0,
C7, 0, 0, G6, 0, 0, E6, 0,
0, A6, 0, B6, 0,AS6, A6, 0,
G6, E7, 0, G7, A7, 0, F7, G7,
0, E7, 0, C7, D7, B6, 0, 0,
]
# This is the list of notes for jingle bells
jingle = [
E7, E7, E7, 0,
E7, E7, E7, 0,
E7, G7, C7, D7, E7, 0,
F7, F7, F7, F7, F7, E7, E7, E7, E7, D7, D7, E7, D7, 0, G7, 0,
E7, E7, E7, 0,
E7, E7, E7, 0,
E7, G7, C7, D7, E7, 0,
F7, F7, F7, F7, F7, E7, E7, E7, G7, G7, F7, D7, C7, 0
]
# This is the list of notes for Twinkle, Twinkle Little Star
twinkle = [
C6, C6, G6, G6, A6, A6, G6, 0,
F6, F6, E6, E6, D6, D6, C6, 0,
G6, G6, F6, F6, E6, E6, D6, 0,
G6, G6, F6, F6, E6, E6, D6, 0,
C6, C6, G6, G6, A6, A6, G6, 0,
F6, F6, E6, E6, D6, D6, C6, 0,
]
# Display and play tune
oled.fill(0)
oled.text("Mario Theme", 0, 0, 1)
oled.show()
play_song(mario, 150, 50)
sleep(1)
oled.fill(0)
oled.text("Jingle Bells", 0, 0, 1)
oled.show()
play_song(jingle, 250, 50)
sleep(1)
oled.fill(0)
oled.text("Twinkle, twinkle little star", 0, 0, 1)
oled.show()
play_song(twinkle, 600, 50)
sleep(1)