Christmas Time is one of the most amazing times of the year and as we are technical people, we should have our own way to celebrate it. So let's make a project today that will help us to celebrate Christmas in a unique way. Today, we are going to make a project which will play 'We Wish you a Merry Christmas' Carol on Buzzer with Tone() and display a Customized Message with Pine trees on SSD1306 OLED Display.
Its an easy and yet an amazing project to make. You can minimize the whole thing to a PCB board and hang it on your Christmas Tree. We will be using an SSD1306 OLED for the display of the message - "Merry Christmas" with a basic animation of snowflakes. Also, this project is not limited to Christmas only. You can customize it for other occasions or you can also use it as a normal home decor kind of thing. You just need to make some changes in the code according to the tone you want to play and the message you want to display.
Want to know how to do that? Then go ahead and check this out.
Get PCBs for Your Projects Manufactured
You must check out PCBWAY for ordering PCBs online for cheap!
You get 10 good-quality PCBs manufactured and shipped to your doorstep for cheap. You will also get a discount on shipping on your first order. Upload your Gerber files onto PCBWAY to get them manufactured with good quality and quick turnaround time. PCBWay now could provide a complete product solution, from design to enclosure production. Check out their online Gerber viewer function. With reward points, you can get free stuff from their gift shop.
About the Components
Before we start let's have a closer look at the components that we are going to use and get an understanding of how they work and what applications they can be used for:-
Piezo Buzzer: In simplest terms, a piezo buzzer is a type of electronic device that’s used to produce a tone, alarm, or sound. It’s lightweight with simple construction, and it’s typically a low-cost product. Yet at the same time, depending on the piezo ceramic buzzer specifications, it’s also reliable and can be constructed in a wide range of sizes that work across varying frequencies to produce different sound outputs. when certain piezoelectric materials are subjected to an alternating field of electricity, the piezo buzzer element — often a manmade piezoceramic material — stretches and compresses in sequence with the frequency of the current. As a result, it produces an audible sound. Piezo buzzers can typically operate anywhere between three and 250 volts. In addition, they consume less than 30 milliamperes — even at higher rate frequencies
OLED Display: There are 2 types of OLED displays based on the mode of communication they use. The names of these displays are SPI-based and I2C-based. These are explained below:-
SPI based SSD1306
A 7-pin OLED module offers all interfacing options like 3-wire SPI, 4-wire SPI, and I2C. The default 4-wire SPI is the fastest communication mode with the OLED. It has the following pin configuration -
For interfacing, the module with Arduino connects the GND and VCC/VDD pins to the ground and 5V out of the Arduino, respectively. The D0, D1, RST, DC, and CS pins can be connected to any GPIO. A 6-pin module doesn't have Chip Select (CS) pin.
I2C based SSD1306
The 4-pin OLED modules offer only an I2C interface to communicate with it. It has the following pin configuration.
To interface the 4-pin module, connect the GND and VCC pins to this ground and 5V out of the Arduino. Connect the SDA and SCL pins to the pins of Arduino (check for your board's Pinout).
I have used a similar OLED, but only the difference is, in the above images the resolution of the OLED is 128x64 (bigger screen). What I used is a smaller height of 32 pixels. Therefore my OLED display was of resolution 128x32.
Libraries and Code Setup
In Arduino IDE, Go to Tools > Manage Libraries > Search "SSD1306" on the Library Manager.
This library will help to initiate and set up the OLED screen from the preferred Communication easily with the Arduino IDE.
Below code will initiate the library and define the screen resolution (we use) -
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
For SPI,
#define OLED_MOSI 9
#define OLED_CLK 10
#define OLED_DC 11
#define OLED_CS 12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
For I2C,
#include "Wire.h"
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Next, we also need to make sure I2C communication does not fail or informs us at least, so we add the below inside setup function -
void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
}
That's it for the setup process. You can now directly put your display function inside the setup function (print once - static image or text) or inside the loop function (prints seamlessly - dynamic image or text).
Here are some functions that will help to handle the OLED display library to write text or draw simple graphics -
display.clearDisplay() – all pixels are off
display.drawPixel(x,y, color) – plot a pixel in the x, y coordinates
display.setTextSize(n) – set the font size, supports sizes from 1 to 8
display.setCursor(x,y) – set the coordinates to start writing text
display.print(“message”) – print the characters at location x, y
display.display() – call this method for the changes to take effect
For more such functions - https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives
Sample Code (OLED)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup()
{
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(2000);
}
void loop()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.print("Temperature - ");
temp = random(20,30);
display.print(temp);
display.print(char(247));
display.println("C");
Serial.println(temp);
display.setCursor(0, 10);
display.print("Humidity - ");
humid = random(10,60);
display.print(humid);
display.println(" %");
Serial.println(humid);
display.setCursor(0, 20);
display.print("Pressure - ");
pressure = random(0,10);
display.print(pressure);
display.println("hPa");
Serial.println(pressure);
display.display();
delay(2000);
}
Now that the basics are over, let us use a much better function, i.e. bitmap for printing images on the OLED screen.
display.drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
This function draws the bitmap format into the XY plane. Let us take a sample image and convert it to Bitmap. Then apply random snowflakes above it.
Display "Merry Christmas" with Trees - using BitMap
What we will do for this, is create an image file of the resolution of 128 x 32 pixels. Then convert the image to get a Bitmap Layout of the same.
I used Photoshop as it is the ready-to-go platform for editing/creating custom images.
After creating one, go to https://javl.github.io/image2cpp/ and do the following -
Step 1 - Select the image file
Step 2 - Select the appropriate functions and see the LIVE changes in thePreview section
Step 3 - Click on Generate code to get the bitmap of the image in array format.
Now, that you have the Bitmap array, you can simply assign a variable name and assign the same directly to the bitmap function.
Sample -
const unsigned char bitmap_Christmas [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
display.drawBitmap(0, 0, bitmap_Christmas, 128, 32, 0);
display.display();
That's it. You can now try the same on your Image. Just make sure to select the correct background in Image settings -
Black BG - White FG means LED on those parts will glowWhite BG - Black FG means Background will glow and image part will be black
Code for OLED Christmas Version -
#include "Wire.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define LOGO_HEIGHT 4
#define LOGO_WIDTH 4
int frame_delay =800;
const int NUMFLAKES = 1000;
int8_t f=0;
int8_t icons[NUMFLAKES][3];
int rad=0;
int a, b, c, d;
int rnd = random(17, 110);
#define XPOS 0
#define YPOS 1
const unsigned char epd_bitmap_blackBG_old_6 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
0x00, 0xe0, 0x19, 0x9e, 0x79, 0xf3, 0x61, 0xec, 0xff, 0x3c, 0xf7, 0xd9, 0x8e, 0x3c, 0x0e, 0x00,
0x00, 0x60, 0x19, 0x9e, 0x79, 0xf3, 0x63, 0xec, 0xff, 0x3d, 0xf7, 0xdd, 0x9f, 0x7c, 0x06, 0x00,
0x00, 0x00, 0x1f, 0x98, 0x79, 0xb3, 0x63, 0x8c, 0xdb, 0x19, 0xc1, 0x9f, 0x9f, 0x70, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x9e, 0x79, 0xf3, 0x63, 0x8f, 0xdf, 0x19, 0xf1, 0x9f, 0x9b, 0x7c, 0x00, 0x00,
0x00, 0x60, 0x1f, 0x9e, 0x7d, 0xfb, 0xc3, 0x8f, 0xdf, 0x98, 0xf1, 0x9f, 0x9f, 0x3c, 0x06, 0x00,
0x00, 0xa0, 0x19, 0x98, 0x6d, 0x99, 0xc3, 0x8c, 0xd9, 0x98, 0x31, 0x99, 0x9f, 0x0c, 0x0a, 0x00,
0x01, 0xb0, 0x19, 0x9e, 0x6d, 0x99, 0x83, 0xec, 0xd9, 0xbd, 0xf1, 0x99, 0x9b, 0x7c, 0x1b, 0x00,
0x03, 0xf8, 0x19, 0x9e, 0x6d, 0x99, 0x81, 0xec, 0xd9, 0xbd, 0xf1, 0x99, 0x9b, 0x7c, 0x3f, 0x80,
0x01, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00,
0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00,
0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x80,
0x06, 0x6c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xc0,
0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0,
0x03, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xc0,
0x03, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xc0,
0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0xe0,
0x0c, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x70,
0x3c, 0xf7, 0x80, 0x00, 0x00, 0x01, 0xdc, 0x62, 0x43, 0x24, 0xc0, 0x00, 0x00, 0x03, 0xcf, 0x78,
0x3f, 0xff, 0x80, 0x00, 0x00, 0x03, 0xde, 0xf7, 0xc7, 0xbd, 0xe0, 0x00, 0x00, 0x03, 0xff, 0xf8,
0x01, 0x98, 0x00, 0x00, 0x00, 0x03, 0x16, 0xd7, 0xc7, 0xbc, 0xc0, 0x00, 0x00, 0x00, 0x19, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9e, 0xd7, 0xc7, 0xbc, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x16, 0xf6, 0x47, 0xb5, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x16, 0xf6, 0x46, 0xb5, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
=
void setup() {
Serial.begin(9600);
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.display();
delay(2000);
display.clearDisplay();
display.drawBitmap(0,0,epd_bitmap_blackBG_old_6, 128, 32, 1);
display.display();
int n=0;
for (static unsigned long thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
//------------------------ R E S E T ---------------------------
rst();
display.display();
//------------------------S N O W F L A K E S---------------------------
snowflakes();
display.display();
//-----------------------------------------------------------
}
}
void loop() {
}
void rst(){
display.fillCircle(15, 12, 2, 0);
display.fillCircle(15, 5, 2, 0);
display.fillCircle(15, 28, 2, 0);
display.fillCircle(rnd, 17, 2, 0);
display.fillCircle(25, 20, 2, 0);
display.fillCircle(50, 17, 2, 0);
display.fillCircle(50, 30, 2, 0);
display.fillCircle(75, 15, 2, 0);
display.fillCircle(90, 15, 2, 0);
display.fillCircle(90, 28, 2, 0);
display.fillCircle(110, 5, 2, 0);
display.fillCircle(110, 28, 2, 0);
display.fillCircle(125, 8, 2, 0);
display.fillCircle(125, 29, 2, 0);
}
void snowflakes(){
display.fillCircle(15, 12, random(0,3) , random(-2,2));
display.fillCircle(15, 5, random(0,2) , random(-2,2));
display.fillCircle(15, 28, random(0,2) , random(-2,2));
display.fillCircle(rnd, 17, random(0,2), random(-2,2));
display.fillCircle(25, 20, random(0,2) ,random(-2,2));
display.fillCircle(50, 17, random(0,2) ,random(-2,2));
display.fillCircle(50, 30, random(0,2) ,random(-2,2));
display.fillCircle(75, 15, random(0,2), random(-2,2));
display.fillCircle(90, 15, random(0,2), random(-2,2));
display.fillCircle(90, 28, random(0,2), random(-2,2));
display.fillCircle(110, 5, random(0,2), random(-2,2));
display.fillCircle(110, 28, random(0,2), random(-2,2));
display.fillCircle(125, 8, random(0,2), random(-2,2));
display.fillCircle(125, 29, random(0,2), random(-2,2));
}
Now let us now use a melody and use it on the Buzzer. The notes of the song "We wish you a Merry Christmas" were converted to tone() to be used with the piezo buzzer.
You can see in the documentation of the function - https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody that usual Notes can be directly used to apply and play a particular song. We accurate delays, it can be put inside a loop for error control.
Music Sample -
int melody[] = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
4, 8, 8, 4, 4, 4, 4, 4
};
void setup() {
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000 / noteDurations[thisNote];
tone(8, melody[thisNote], noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}
}
void loop() {
// no need to repeat the melody.
}
Now that the basics are clear, you can use the already existing Notes for different songs from - https://github.com/robsoncouto/arduino-songs
And that's it, we are done with the code. You can check the complete code for this project on the Github page of the project which you can access from here.
Connections to be done
Now as we are done with the code setup and other important things. The last thing we are left with is the hardware connections and code uploading to the Arduino board. For this project, I am using an I2C-based SSD1306 OLED display. The connections to be done are as given below:-
Connect the GND pins of the buzzer and the OLED display to the GND pin of the Arduino Nano.
Connect the Vcc pin of the buzzer to the D4 pin of the Arduino Nano.
Connect the Vcc pin of the OLED display to the 5V pin of the Arduino Nano.
Connect the SDA pin of the display to the A4 pin of the Arduino Nano.
Connect the SCL pin of the display to the A5 pin of the Arduino Nano.
And in this way, we are done with the Connections that are needed for this project. Now we need to connect the Arduino Nano to the Computer and upload the code to the Arduino board using Arduino IDE. The Complete code can be accessed from https://github.com/akarsh98/Christmas_OLED-Buzzer_Carol_Arduino/blob/master/Arduino_Code.ino.
And we are done
In this way, the project is complete and ready to be used. You can create the same prototype on a PCB and hang it on your Christmas Tree or anywhere you want. As we said the project was fun and easy to make. Another good thing about this project is that it is completely customizable. You can use it as it is for Christmas or you can change the message and Tone according to your need and use it for other occasions as well. Not only on occasions You can also use it for home decoration.
So that's it for this project. I will be back with some more fun and amazing projects very soon.