CircuitPython Setup
We’ll use CircuitPython to code the Annoy-O-Matic.
First, follow this guide https://learn.adafruit.com/adafruit-gemma-m0/circuitpython to get started with coding the Gemma M0 in CircuitPython. Install the latest release version of CircuitPython on the board. You may also want to install the Mu editor https://learn.adafruit.com/adafruit-gemma-m0/installing-mu-editor for your coding needs.
Once you can successfully upload code from Mu to your Gemma M0, return here.
Annoy-O-Matic Code
We will only need to do a few simple things in the code, and then repeat them over and over.
Pulsio
First, we'll need to be able to create sequences of sounds of various pre-defined frequencies and durations, such as three quick, high pitched tones for a cricket sound, or the thirteen notes of the famous Nokia phone ringtone.
These tones can be played using the CircuitPython pulsio library, which can send PWM (pulse width modulation) signals of specific frequencies to the piezo buzzer.
Here's a great primer on using PWM with pulsio in CircuitPython to create tones. This is what the code looks like to play a series of notes:
# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import pwmio piezo = pwmio.PWMOut(board.D2, duty_cycle=0, frequency=440, variable_frequency=True) while True: for f in (262, 294, 330, 349, 392, 440, 494, 523): piezo.frequency = f piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(0.25) # on for 1/4 second piezo.duty_cycle = 0 # off time.sleep(0.05) # pause between notes time.sleep(0.5)
Functions
We'll create a number of functions in the code so that we can easily choose between different operational modes. So, beep, doorbell, ringtone, crickets, and teen tone will all be different pre-defined functions that can then be selected at the top of the code.
Below is the full code we'll use. You can read in the comments how the different variables at the top work. For example, by changing annoy_mode = 3
to annoy_mode = 2
, you'll get a doorbell sound instead of a ringtone.
The way this works, is that at the very bottom of the code the while True:
loop runs and checks the value of annoy_mode
. Depending on that value, one of the different functions, such as def annoy_doorbell()
is called.
You can look at the different functions to see how they work, and play around with the values to change pitch frequencies and delay timings.
# SPDX-FileCopyrightText: 2018 John Edgar Park for Adafruit Industries # # SPDX-License-Identifier: MIT # Annoy-O-Matic Sound Prank Device # choose from a variety of sounds and timings to drive your victim bonkers import time import board import pwmio # pylint: disable=unused-variable,consider-using-enumerate,redefined-outer-name,too-many-locals piezo = pwmio.PWMOut(board.D0, duty_cycle=0, frequency=440, variable_frequency=True) # pick the mode here: # 1 = beep # 2 = doorbell # 3 = ringtone # 4 = crickets # 5 = teen tone # 6 = demo mode annoy_mode = 3 # set general parameters here interval = 300 # seconds before next annoyance. Default 300 (5 minutes) # set beep details here frequency = 5000 # pitch of the beep in Hz. Default 5000 length = 0.2 # length (duration) of the beep in seconds. Default 0.2 rest = 0.05 # seconds between beep repeats. Default 0.05 # set beep/cricket details here repeat = 3 # number of times to repeat the beep/cricket. Default 3 # set ringtone details here ringtone = 3 # song choices: 1 = Nokia, 2 = iPhone, 3 = Rickroll ringtone_tempo = 1.6 # suggested Nokia 0.9 , iPhone 1.3 , Rickroll 2.0 def annoy_beep(frequency, length, repeat, rest, interval): for _ in range(repeat): piezo.frequency = frequency # 2600 is a nice choice piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(length) # sound on piezo.duty_cycle = 0 # off time.sleep(rest) time.sleep(interval) # wait time until next beep def annoy_doorbell(interval): piezo.frequency = 740 piezo.duty_cycle = 65536 // 2 time.sleep(0.85) piezo.duty_cycle = 0 time.sleep(0.05) piezo.frequency = 588 piezo.duty_cycle = 65536 // 2 time.sleep(1.25) piezo.duty_cycle = 0 time.sleep(interval) # pylint: disable=too-many-statements def annoy_ringtone(ringtone, tempo, interval): # ringtone 1: Nokia # ringtone 2: Apple iPhone # ringtone 3: Rick Astley Never Gonna Give You Up # tempo is length of whole note in seconds, e.g. 1.5 # set up time signature whole_note = tempo # adjust this to change tempo of everything dotted_whole_note = whole_note * 1.5 # these notes are fractions of the whole note half_note = whole_note / 2 dotted_half_note = half_note * 1.5 quarter_note = whole_note / 4 dotted_quarter_note = quarter_note * 1.5 eighth_note = whole_note / 8 dotted_eighth_note = eighth_note * 1.5 sixteenth_note = whole_note / 16 # set up note values A2 = 110 As2 = 117 # 's' stands for sharp: A#2 Bb2 = 117 B2 = 123 C3 = 131 Cs3 = 139 Db3 = 139 D3 = 147 Ds3 = 156 Eb3 = 156 E3 = 165 F3 = 175 Fs3 = 185 Gb3 = 185 G3 = 196 Gs3 = 208 Ab3 = 208 A3 = 220 As3 = 233 Bb3 = 233 B3 = 247 # C4 = 262 Cs4 = 277 # Db4 = 277 D4 = 294 # Ds4 = 311 # Eb4 = 311 E4 = 330 # F4 = 349 Fs4 = 370 # Gb4 = 370 G4 = 392 # Gs4 = 415 # Ab4 = 415 # A4 = 440 # As4 = 466 # Bb4 = 466 B4 = 494 C5 = 523 Cs5 = 554 Db5 = 554 D5 = 587 Ds5 = 622 Eb5 = 622 E5 = 659 F5 = 698 Fs5 = 740 Gb5 = 740 G5 = 784 Gs5 = 831 Ab5 = 831 A5 = 880 As5 = 932 Bb5 = 932 B5 = 987 # here's another way to express the note pitch, double the previous octave C6 = C5 * 2 Cs6 = Cs5 * 2 Db6 = Db5 * 2 D6 = D5 * 2 Ds6 = Ds5 * 2 Eb6 = Eb5 * 2 E6 = E5 * 2 F6 = F5 * 2 Fs6 = Fs5 * 2 Gb6 = Gb5 * 2 G6 = G5 * 2 Gs6 = Gs5 * 2 Ab6 = Ab5 * 2 A6 = A5 * 2 As6 = As5 * 2 Bb6 = Bb5 * 2 B6 = B5 * 2 if ringtone == 1: # Nokia nokia_ringtone = [[E6, eighth_note], [D6, eighth_note], [Fs5, quarter_note], [Gs5, quarter_note], [Cs6, eighth_note], [B5, eighth_note], [D5, quarter_note], [E5, quarter_note], [B5, eighth_note], [A5, eighth_note], [Cs5, quarter_note], [E5, quarter_note], [A5, whole_note]] for n in range(len(nokia_ringtone)): piezo.frequency = (nokia_ringtone[n][0]) piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(nokia_ringtone[n][1]) # note duration piezo.duty_cycle = 0 # off time.sleep(0.01) if ringtone == 2: # iPhone Marimba iPhone_ringtone = [[B4, eighth_note], [G4, eighth_note], [D5, eighth_note], [G4, eighth_note], [D5, eighth_note], [E5, eighth_note], [D5, eighth_note], [G4, eighth_note], [E5, eighth_note], [D5, eighth_note], [G4, eighth_note], [D5, eighth_note]] for n in range(len(iPhone_ringtone)): piezo.frequency = (iPhone_ringtone[n][0]) piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(iPhone_ringtone[n][1]) # note duration piezo.duty_cycle = 0 # off time.sleep(0.01) if ringtone == 3: # Rickroll rick_ringtone = [[A3, sixteenth_note], [B3, sixteenth_note], [D4, sixteenth_note], [B3, sixteenth_note], [Fs4, dotted_eighth_note], [Fs4, sixteenth_note], [Fs4, eighth_note], [E4, eighth_note], [E4, quarter_note], [A3, sixteenth_note], [B3, sixteenth_note], [Cs4, sixteenth_note], [A3, sixteenth_note], [E4, dotted_eighth_note], [E4, sixteenth_note], [E4, eighth_note], [D4, eighth_note], [D4, sixteenth_note], [Cs4, sixteenth_note], [B3, eighth_note]] for n in range(len(rick_ringtone)): piezo.frequency = (rick_ringtone[n][0]) piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(rick_ringtone[n][1]) # note duration piezo.duty_cycle = 0 # off time.sleep(0.035) time.sleep(interval) def annoy_crickets(repeat, interval): for _ in range(repeat): for _ in range(6): piezo.frequency = 8000 # 2600 is a nice choice piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(0.02) # sound on piezo.duty_cycle = 0 # off time.sleep(0.05) time.sleep(0.2) time.sleep(interval) # wait time until next beep def annoy_teen_tone(interval): piezo.frequency = 17400 piezo.duty_cycle = 65536 // 2 # on 50% time.sleep(10) piezo.duty_cycle = 0 time.sleep(interval) while True: if annoy_mode == 1: annoy_beep(frequency, length, repeat, rest, interval) elif annoy_mode == 2: annoy_doorbell(interval) elif annoy_mode == 3: annoy_ringtone(ringtone, ringtone_tempo, interval) elif annoy_mode == 4: annoy_crickets(repeat, interval) elif annoy_mode == 5: annoy_teen_tone(interval) elif annoy_mode == 6: annoy_beep(5000, 0.2, 2, 0.05, 3) annoy_doorbell(3) annoy_ringtone(1, 0.9, 3) annoy_ringtone(2, 1.3, 3) annoy_ringtone(3, 2.0, 3) annoy_crickets(3, 3) annoy_teen_tone(6)
Copy the full code, and paste it into Mu. Then, save the code as main.py onto your Gemma M0. The board will reboot and you'll hear your Annoy-O-Matic play its first sound! After that first instance, the device will wait five minutes before playing again.
Of course, you can change the delay by adjusting the value of the interval
variable at the top. The interval
value is in seconds, so if you want to have it wait for half an hour, the value would be 30 minutes * 60 seconds, or 1800 seconds.
Text editor powered by tinymce.