-
1Introduction
So it's Christmas Time!! Get ready to build an Easy yet AMAZING mini-project. 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. To do that, let us go through the basics of How to use the OLED screen first.
There are 2 types of Communication used for different OLED displays - SPI and I2C.
-
2Get 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.
-
3SPI 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.
-
4I2C 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.
-
5Libraries
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
-
6Sample 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.
-
7Display "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
-
8Code 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.
-
9Music 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
That's All !! You can now directly move to the Code section and start using the code from my Repo. It is a Plug and Play most likely, but watch out and add more songs to it.
COMMENT down the Song and Image you used when you Built this Project.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.