This project uses a buzzer with Arduino, and focuses on learning the method of generating sounds, programming techniques with array, if-else, for-loop. This project is designed to be used for 2-3 learning sessions, it contains several practical tasks brining the students step-by-step deeper experiences, and eventually create a song melody. The project avoids using tone() function from Arduino library, so that the designed knowledge points are better learnt. Goals:
Comprehensive basic programming knowledge in C++: Variables, if-else, array, for-loop
Understand the sound generation theory and use digital signals to form square wares to drive sounds
Fun experience with the playful project, inspire interests for future making
START A BIT > Projects Library > This page
[ ] Simple: 30-60 minutes
[ ] Moderate: 1-2 hours
[x] Challenging: more than 2 hours
The estimation bases on average situation without unexpected troubleshooting, assuming that the student meets prerequisites. It only indicates rough time needed to complete this project, but not about technical difficulty, not covering discussion and sharing time. Here is a possible breakdown:
20-30 minutes: Basic knowledge input, preparations, and Task 1
30-45 minutes: Task 2
45-60 minutes: Task 3
45-60minutes: Task 4
30-45 minutes: Task 5, take it as optional
15-30 minutes: Task 6
One should have prior knowledge
Nice to have: Micro:bit and basic projects experiences
KB028: Arduino IDE Basic Knowledge, KB027: Arduino UNO Boards
PJ019: 1st Experience with Arduino , and preferably PJ020: Starting Experience of C++ with Arduino
Purpose: Get to know how the sound is generated, and program the tone in a specific frequency
What is buzzer and how it works
How is sound generated
Macro
Square ware and duty-cycle
What if using "int" instead of "long"?
What if using delay() insteady of delayMicroseconds()?
Does it sound like the C4 tone? Calibrate the period time and control the ON/OFF more accurately to reach the goal
Try some different tones, find the frequency in pitches.h
NOTE_C4 26
NOTE_D4 294
NOTE_E4 330
NOTE_F4 349
NOTE_G4 392
/*
Task 1: Make a sound in specified frequency
Please correct "FIX ME!" and test it working!
*/
// Use macro to define constant
#define BUZZ_PIN 10
// C4 note frequency = 262 Hz
int hertz = 262;
long half_period_us = 1000000 / hertz / 2;
void setup() {
pinMode(BUZZ_PIN, OUTPUT);
}
void loop() {
// Alternate digital output HIGH/LOW to generate vibration
digitalWrite(BUZZ_PIN, /* FIX ME! */);
delayMicroseconds(half_period_us);
digitalWrite(BUZZ_PIN, /* FIX ME! */);
delayMicroseconds(half_period_us);
}
digitalWrite(BUZZ_PIN, HIGH);
digitalWrite(BUZZ_PIN, LOW);
Purpose: Practice serial communication and receiving handling, add a little more fun on top of Task 1
"int" type in Arduino UNO stores a 16-bit (2-byte) value, has a limitation range of value as -32,768 to 32,767
If hertz goes too small (< 15Hz), then half_period_us will overflow the max int, the resulted value becomes wrongly as minus. So half_period_us must be "unsigned int" or "long" type
"long" type in Arduino UNO is 32-bits(4-bytes), has a limitation range of value as -2,147,483,648 to 2,147,483,647
What if using "int" instead of "long"?
What if using delay() instead of delayMicroseconds()?
What if the input is not an integer-like string?
Test some different tones, find the frequency in pitches.h
NOTE_C4 26
NOTE_D4 294
NOTE_E4 330
NOTE_F4 349
NOTE_G4 392
/*
Task 2: Make a tone in specified frequency input from serial port
Please correct "FIX ME!" and test it working!
*/
#define BUZZ_PIN 10
// 262Hz is C4 note
long hertz = 262;
long half_period_us = 1000000 / hertz / 2;
String received_string;
void setup() {
Serial.begin(115200);
pinMode(BUZZ_PIN, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
received_string = /* FIX ME! */
received_string.trim();
hertz = received_string.toInt();
half_period_us = 1000000 / hertz / 2;
Serial.print("Updated: hertz ");
Serial.print(hertz);
Serial.print(", half period in us: ");
Serial.println(half_period_us);
}
// Alternate digital output HIGH/LOW to generate vibration
digitalWrite(BUZZ_PIN, HIGH);
/* FIX ME! */
digitalWrite(BUZZ_PIN, LOW);
delayMicroseconds(half_period_us);
}
Serial.readString();
delayMicroseconds(half_period_us);
Purpose: Understand the "note" => "pitch" + "duration", first practice of "for-looping"
Moderato
120
bpm
120 beats per minute means:
1 beat is 60s/120=0.5s=500ms
A whole note = 4 beats = 2s=2000ms
for-looping
Macro
Where to use "int" or "unsigned int" or "long" type variables
Fix some syntax issue in the code to pass compilation
Test some different pitch and/or durations, find the pitch frequency in pitches.h
/*
Task 3: Make a Musical Note in Specified Pitch(Frequency) and Duration
Please FIX some syntax issues and test working!
*/
#define BUZZ_PIN 10
#define NOTE_C4 262
#define NOTE_TYPE_4 4
// Note pitch, and period of vibration
int hertz = NOTE_C4
long full_period_us = 1000000 / hertz;
// Note duration, and how many counts of periods
// take BPM=120, so a whole note duration is 2s=2000ms
long note_duration_ms = 2000 / NOTE_TYPE_4;
int count_periods_in_duration = note_duration_ms * 1000 / full_period_us;
void setup() {
pinMode(BUZZ_PIN, OUTPUT);
// Repeat these many periods
// to keep the sound for a specific note duration
for (int i = 0; i < count_periods_in_duration; i++) {
// Alternate digital output HIGH/LOW
// to generate vibration for specific note pitch
digitalWrite(BUZZ_PIN, HIGH);
delayMicroseconds(full_period_us / 2);
digitalWrite(BUZZ_PIN, LOW
delayMicroseconds(full_period_us / 2);
}
}
void loop() {
// Do nothing in main loop
// Please use reset button in Arduino board to repeat testing
}
long hertz = NOTE_C4;
digitalWrite(BUZZ_PIN, LOW);
Purpose: Understand the "note" => "pitch" + "duration", practice array, continue practicing of "for-looping" and experience nested looping
for-looping
Simple nested for-looping
Macro
Where to use "int" or "unsigned int" or "long" type variables
Fix some syntax issue in the code to pass compilation
Can you complete the full melody of this song?
/*
Task 4: Make a Happy Birthday Melody
Please FIX some syntax issues and test working!
*/
#define BUZZ_PIN 10
#define NOTE_C4 262
#define NOTE_D4 294
#define NOTE_E4 330
#define NOTE_F4 349
// Note pitches array
int hertz[] = {NOTE_C4, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_F4, NOTE_E4};
// Note types array
int note_types[] = {4, 8, 4, 4, 4, 2;
// Count of notes, smarter to use sizeof(), simply hardcode for now
int count_of_notes = 6
void setup() {
pinMode(BUZZ_PIN, OUTPUT);
for (int i = 0; i < count_of_notes; i++) {
long full_period_us = 1000000 / hertz[i];
// Note duration, and how many counts of periods
// take BPM=120, so a full note duration is 2s=2000ms
long note_duration_ms = 2000 / note_types[i];
int count_periods_in_duration = note_duration_ms * 1000 / full_period_us;
// Repeat these many periods
// to keep the sound for a specific note duration
for (int j = 0; j < count_periods_in_duration; j++) {
// Alternate digital output HIGH/LOW
// to generate vibration for specific note pitch
digitalWrite(BUZZ_PIN, HIGH);
delayMicroseconds(full_period_us / 2);
digitalWrite(BUZZ_PIN, LOW);
delayMicroseconds(full_period_us / 2);
}
// Optional: Rest a while between notes, please calibrate
//delay(note_duration_ms);
}
}
void loop() {
// Do nothing in main loop
// Please use reset button in Arduino board to repeat testing
}
int note_types[] = {4, 8, 4, 4, 4, 2};
int count_of_notes = 6;
Purpose: Creative task for your favorite song melody, as an optional challenge task
For those who have experience in C/C++, please try to wrap the note playing as a function, this will make the code in better structure, easier to read and maintain.
In Task 3, the key factors of hertz(pitch) and duration can define a note, please try to explore using serial ports receiving both information of hertz and duration input, parse the string and extract the numbers to update the note to play.
As you have noticed, we used different numeric type variable int and long, it's about the maximum number that we might reach, so a proper type is used to avoid overflowing. Please write test program, practicing looping, to find the edge of how big number is fine for int and long.
Purpose: Enhance basic knowledge understanding, reflect and summarize what we have learnt
Go to this test: https://forms.gle/attDiNHh8zhXbjeH8
No time limit, but should be possibly done within 15 minutes
Expectation is at least 60% correctness
Follow the tutor to take 5-10 minutes to review the questions and answers, correct some possible misunderstood issues or faults
Take 1-2 minutes to explore anything on the tools and the making flow, with curiosity, no matter how much prior knowledge you have, you should make
At least 1 interesting finding
At least 1 curious question
Used by LP2512: Basic Array and Looping in C++, 25w12 for the continuous 3 sessions