Week 10: Output Devices

Assignments:

Group Assignment

  • Measure the power consumption of an output device.
  • Document your work to the group work page and reflect on your individual page what you learned

Individual Assignment

  • Add an output device to a microcontroller board you’ve designed and program it to do something..

Things to Complete This Week

  • Explore different output devices
  • Document process
  • Work on Final Project PCB!!!

Here is my schedule for this week.

Weekly schedule

Here is the link to my schedule


Group Assignment

You can access our group assignment here.


Individual Assignment

For this week also, I am planning to use the same board that I designed during week 8 πŸ€—

Extracted template files

For this assignment, I want to make use of a 1.3-inch OLED display along with a buzzer 🀠.


OLED

An OLED (Organic Light-Emitting Diode) display is a screen that can show text, graphics, and animations with bright and clear visuals, even in low light.

It operates on a volatge supply of 3.3V - 5V. The OLED display usually has four pins: VCC for the power supply, GND for ground, SCL for the clock signal used in communication, and SDA for the data signal that carries information.

Extracted template files
Image source

How it works?

An OLED is made of many thin layers stacked together. At the bottom is the substrate (usually made of glass or flexible plastic) and this is what holds everything in place. On top of that is the anode, which helps current flow through the device. The middle part consists of the organic layers, which usually include a conductive layer that moves positive charges and an emissive layer where light is actually produced.

The top layer is the cathode which injects electrons into the organic layers so they can move toward the emissive layer. When these electrons meet the positive charges coming from the anode, they combine and release energy as light. Each pixel produces its own light when electricity passes through, allowing the display to show bright colors.

Extracted template files
Image source

Buzzer

A buzzer is an output device that produces sound when electrical signals are applied.

It usually operates on a voltage supply of 3V - 5V. A basic buzzer has two pins: VCC for the power supply and GND for ground. Some buzzers also have a signal input to control different sound patterns.

Extracted template files
Image source

How it works?

Inside, it contains either a piezoelectric element or a small electromagnetic coil with a diaphragm. In a piezo buzzer, applying voltage makes the material expand and contract rapidly which creates vibrations in the air that we hear as sound. In an electromagnetic buzzer, the current moves the diaphragm (Thin, flexible piece of material that can vibrate to create sound) back and forth to produce sound waves.

Each buzzer produces a specific tone, and by changing the signal or frequency, it can generate different sounds or even play simple melodies. This allows buzzers to give different audible feedback. πŸ”Š

There are two main types of buzzers: Active and Passive

Active Buzzer: An active buzzer has a built-in oscillator, so it only needs a DC voltage to make sound. You just have to connect it to power and it beeps on its own (Makes it super easy to use).

Passive Buzzer: A passive buzzer does not have an internal oscillator, so it needs an external signal (like a square wave from a microcontroller) to create sound. This lets you control the frequency, so you can make different tones or even play simple melodies. 🎡

An oscillator is a circuit that generates a repeating signal (usually in the form of a wave) and can be used to create sound or control timing in electronic devices.

Extracted template files
Image source

Using an OLED, a buzzer and my board, these are the connections I made:

Note: GPIO pins behave differently depending on whether they’re sending or receiving signals. Sending, like turning on an LED, works easily because you control the voltage. Receiving, like detecting a button press, is trickier because noise or leftover voltages can interfere. That’s why I had to use an external button (instead of the onboard one) to make sure the pin gets a clear signal.

OLED Connections

OLED Pin Connect to XIAO Pin Type
VCC 3.3V Power
GND GND Ground
SDA GPIO 6 I2C
SCL GPIO 7 I2C

Buzzer, Button, and LED Connections

Component Pin Connect to XIAO Pin Type
Buzzer + GPIO 9 Digital Output
Buzzer - GND Ground
Button side 1 GPIO 5 Digital Input (with pull-up)
Button side 2 GND Ground
LED + (long leg) GPIO 8 Digital Output
LED - (short leg) GND (through 220Ξ© resistor) Ground

Here is how the setup looks 😁:

Note: It is NOT at all recommended to use a breadboard πŸ™…β€β™€οΈ. However, I used one in my setup for the GND rail and the external button πŸ€¦β€β™‚οΈ.

Extracted template files

With this setup, I experimented with different codes and played different rhymes while displaying the lyrics as well πŸ˜ƒ

Note: I asked ChatGPT to generate the code for each of the rhymes below (Credit to AIπŸ₯³πŸ™)

Clap, Clap, Clap, Tap

Prompt: Can you generate a code so that after I press a button, the OLED shows the lyrics for the Clap Tap rhyme in time with the buzzer and LED following the same rhythm?


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

#define SDA_PIN 6
#define SCL_PIN 7
#define BUTTON_PIN 5
#define LED_PIN 8
#define BUZZER_PIN 21

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Rhythm durations (ms)
int beats[] = {
  300,300,  // Clap Clap
  300,300,  // Tap Tap
  300,300,300, // Clap Tap Clap
  800       // Stop (long)
};

// Words synced to beats
String words[] = {
  "Clap", "Clap",
  "Tap", "Tap",
  "Clap", "Tap", "Clap",
  "STOP!"
};

int totalNotes = 8;

void showText(String msg) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(10, 20);
  display.print(msg);
  display.display();
}

void playBeat(int duration) {
  int beepTime = duration * 0.6;
  int silenceTime = duration * 0.4;

  // ON = sound + LED ON
  digitalWrite(BUZZER_PIN, HIGH);
  digitalWrite(LED_PIN, LOW);
  delay(beepTime);

  // OFF = silence + LED OFF
  digitalWrite(BUZZER_PIN, LOW);
  digitalWrite(LED_PIN, HIGH);
  delay(silenceTime);
}

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  digitalWrite(LED_PIN, HIGH);
  digitalWrite(BUZZER_PIN, LOW);

  Wire.begin(SDA_PIN, SCL_PIN);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  showText("Press!");
}

void loop() {
  if (digitalRead(BUTTON_PIN) == LOW) {
    delay(50);

    if (digitalRead(BUTTON_PIN) == LOW) {

      for (int i = 0; i < totalNotes; i++) {
        showText(words[i]);     // Show word
        playBeat(beats[i]);     // Play rhythm
      }

      showText("Done!");
      delay(1000);

      // wait for button release
      while (digitalRead(BUTTON_PIN) == LOW);
    }
  }
}
  

How does the code work? πŸ€·β€β™€οΈ

The code starts by importing the necessary libraries for the OLED display and setting up the display object. It also defines the pins for the button, LED, and buzzer on the board. In the setup() function, the pins are initialized: the button uses INPUT_PULLUP, while the LED and buzzer are set as outputs. The OLED display is also initialized to show messages.

Inside the loop() function, the code checks if the button is pressed. When pressed, it goes through a predefined sequence of beats and words. For each beat, it turns the buzzer on while the LED flashes for part of the duration, then turns them off for the remaining duration. At the same time, the OLED displays the word corresponding to that beat. This creates a synchronized combination of sound, light, and text. After completing the sequence, the display shows β€œDone!” and the program waits for the button to be released before allowing the sequence to play again.



Happy Birthday

Prompt: Can you generate a code so that after I press a button, my OLED shows the words of Happy Birthday word by word, while a buzzer plays the rhyme in sync and an LED blinks with each note?


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ── Pin definitions ──────────────────────────────
#define SDA_PIN     6
#define SCL_PIN     7
#define BUTTON_PIN  5
#define LED_PIN     8
#define BUZZER_PIN  21

// ── Display ──────────────────────────────────────
#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT  64
#define OLED_RESET     -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ── Notes ────────────────────────────────────────
#define G4  392
#define A4  440
#define B4  494
#define C5  523
#define D5  587
#define E5  659
#define F5  698
#define G5  784

// ── Song data ────────────────────────────────────
#define TOTAL_NOTES 25

int melody[TOTAL_NOTES] = {
  G4, G4, A4, G4, C5, B4,
  G4, G4, A4, G4, D5, C5,
  G4, G4, G5, E5, C5, B4, A4,
  F5, F5, E5, C5, D5, C5
};

int dur[TOTAL_NOTES] = {
  300, 300, 500, 500, 500, 700,
  300, 300, 500, 500, 500, 700,
  300, 300, 500, 500, 500, 500, 700,
  300, 300, 500, 500, 500, 700
};

const char* words[TOTAL_NOTES] = {
  "Hap-", "py",  "Birth-", "day",  "to",   "You!",
  "Hap-", "py",  "Birth-", "day",  "to",   "You!",
  "Hap-", "py",  "Birth-", "day",  "Dear", "Fri-", "end!",
  "Hap-", "py",  "Birth-", "day",  "to",   "You!"
};

// ── Show text on OLED ─────────────────────────────
void showText(const char* msg) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 22);
  display.print(msg);
  display.display();
}

// ── Play one note + flash LED ─────────────────────
void playNote(int freq, int ms) {
  tone(BUZZER_PIN, freq);
  digitalWrite(LED_PIN, LOW);   // LED ON
  delay(ms - 40);
  noTone(BUZZER_PIN);
  digitalWrite(LED_PIN, HIGH);  // LED OFF
  delay(40);                    // short gap between notes
}

// ── Play the whole song ───────────────────────────
void playSong() {
  for (int i = 0; i < TOTAL_NOTES; i++) {
    showText(words[i]);
    playNote(melody[i], dur[i]);
  }
  showText("Done! :)");
  delay(2000);
  showText("Press btn!");
}

// ═════════════════════════════════════════════════
void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN,    OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);  // LED off

  Wire.begin(SDA_PIN, SCL_PIN);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    // OLED failed β€” blink LED forever so you know
    while (true) {
      digitalWrite(LED_PIN, LOW);
      delay(200);
      digitalWrite(LED_PIN, HIGH);
      delay(200);
    }
  }

  showText("Press btn!");
}

void loop() {
  if (digitalRead(BUTTON_PIN) == LOW) {
    delay(60);                          // debounce
    if (digitalRead(BUTTON_PIN) == LOW) {
      playSong();
      while (digitalRead(BUTTON_PIN) == LOW); // wait for release
    }
  }
}
  

How does the code work? πŸ€·β€β™‚οΈ

The code begins by importing the necessary libraries for the OLED display and defining the pins for the button, LED, and buzzer on the board. The OLED display object is created to handle text output. In the setup() function, the button is configured with INPUT_PULLUP, and the LED and buzzer are set as outputs. The display is initialized, and a β€œPress btn!” message appears to prompt the user to start.

Inside the loop() function, the program waits for the button to be pressed. Once pressed, it loops through a predefined sequence of musical notes and corresponding words for the β€œHappy Birthday” song. For each note, the buzzer produces the sound while the LED flashes, and the OLED shows the word synchronized with the note. After completing all the notes, the display shows β€œDone!” and waits for a short pause before prompting the user again. The program also ensures the button is released before allowing another playthrough.



Johny Johny

Prompt: Can you make a program so that when I press a button, the OLED displays the lyrics of Johny Johny Yes Papa while a buzzer plays the tune and an LED blinks along with each note?


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ── Pin definitions ──────────────────────────────
#define SDA_PIN     6
#define SCL_PIN     7
#define BUTTON_PIN  5
#define LED_PIN     8
#define BUZZER_PIN  21

// ── Display ──────────────────────────────────────
#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT  64
#define OLED_RESET     -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ── Notes ────────────────────────────────────────
#define C4  262
#define D4  294
#define E4  330
#define F4  349
#define G4  392
#define A4  440
#define B4  494
#define C5  523

// ── Song data ────────────────────────────────────
int melody[] = {
  C4, E4, G4, C5,
  G4, A4, G4,
  E4, F4, E4, D4,
  E4, D4, C4,
  G4, A4, B4,
  C5, B4, A4,
  G4, E4, F4, G4,
  C5, C5, C5,
  C4, E4, G4, C5,
  G4, A4, G4,
  E4, G4, C5,
  C5, B4, C5
};

int dur[] = {
  400, 400, 400, 600,
  400, 400, 700,
  400, 400, 400, 600,
  400, 400, 700,
  400, 400, 600,
  400, 400, 700,
  400, 400, 400, 600,
  300, 300, 700,
  400, 400, 400, 600,
  400, 400, 700,
  300, 300, 600,
  300, 300, 900
};

const char* words[] = {
  "Joh-", "ny", "Joh-", "ny!",
  "Yes", "Pa-", "pa!",
  "Eat-", "ing", "su-", "gar?",
  "No", "Pa-", "pa!",
  "Tel-", "ling", "lies?",
  "No", "Pa-", "pa!",
  "O-", "pen", "your", "mouth!",
  "Ha", "ha", "ha!",
  "Joh-", "ny", "Joh-", "ny!",
  "Yes", "Pa-", "pa!",
  "Ha", "ha", "ha!",
  "Ha", "ha", "ha!!!"
};

// Automatically get total notes
int totalNotes = sizeof(melody) / sizeof(melody[0]);

// ── Show text on OLED ─────────────────────────────
void showText(const char* msg) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 22);
  display.print(msg);
  display.display();
}

// ── Play one note + flash LED ─────────────────────
void playNote(int freq, int ms) {
  tone(BUZZER_PIN, freq);
  digitalWrite(LED_PIN, LOW);
  delay(ms - 40);
  noTone(BUZZER_PIN);
  digitalWrite(LED_PIN, HIGH);
  delay(40);
}

// ── Play the whole song ───────────────────────────
void playSong() {
  for (int i = 0; i < totalNotes; i++) {
    showText(words[i]);
    playNote(melody[i], dur[i]);
  }
  showText("Ha ha ha!");
  delay(1000);
  showText("Done! :)");
  delay(2000);
  showText("Press btn!");
}

// ═════════════════════════════════════════════════
void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN,    OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  Wire.begin(SDA_PIN, SCL_PIN);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  

How does the code work? 🀷

Like the two above codes above, this code starts by importing the necessary libraries to control the OLED display and defining the pins for the button, LED, and buzzer. The OLED display object is created using Adafruit_SSD1306 to manage text output. In the setup() function, the button is configured with INPUT_PULLUP to detect presses, and the LED and buzzer are set as outputs. The OLED display is initialized, and if initialization fails, the LED blinks repeatedly to indicate an error. Once the setup is complete, the display shows β€œPress btn!” to prompt the user.

Inside the loop() function, the code continuously checks if the button is pressed. When pressed, it calls the playSong() function and waits for the button to be released before allowing the song to play again. The playSong() function loops through a predefined sequence of musical notes and corresponding words for the β€œJohny Johny” rhyme. For each note, the buzzer produces sound while the LED flashes, and the OLED shows the matching syllable, keeping the text synchronized with the audio and visual signals. After completing the song, the display shows β€œHa ha ha!”, then β€œDone! :)”, and finally prompts the user again to press the button.



I had a great time this week. There wasn't a lot of stress about finishing the assignment quickly so I could genuinely focus on and enjoy the whole process.πŸ˜„

Thank you!!! (‾◑◝) Bye~Bye~