Displayed cute picture of cat with OLED Display on ESP32 + PWM

Hello, future engineers!!

Welcome to my blog!

My name is Muhamad Fariz Ramadhan from STI 2020 ITB. I made this blog to help you guys out about embedded system especially setting up ESP32 to have some conditions. At this time, I am going to show you how connecting ESP32 to OLED and try to show some figures on it, for example the picture of cat. Also in this tutorial, I am going to introduce the PWM signals with the ESP32 using Arduino IDE.

*DON'T YOU KNOW??*
ESP32 can make such a cool things, such as we can display a picture by connecting it to the OLED. Here is the example

Original picture

Displayed on OLED

   So, now we're going to connect ESP32 to OLED and display some pictures and even some animations on it. Let get started!

STEP 1 : Required Hardware

source: Hallroad.org

1. ESP32 Development Board
2. Laptop / PC
3. Micro USB cable
4. Motherboard
5. Jumper wires 
6. OLED (I'm going to use SSD1306 model 128x64 pixels)

STEP 2 : Required Software

1. Download and install Arduino IDE


You can download Arduino IDE from this link: https://www.arduino.cc/en/software and choose suitable version for your laptop / PC. After that, please install the app by following the instructions. You can check my other blog here for more information.

2. Open Arduino IDE and install Adafruit SSD1306 & GFX library
After Arduino get installed then we have to set up the app to suitable for OLED SSD1360.
Go to Tools > Manage Libraries. Then install "Adafruit SSD1306" and "Adafruit GFX Library"



STEP 3 : Circuit time & Demonstration

1. Learn the concept
   Here is the schematic circuit.


source : randomnerdtutorials


2. Set up the circuit
From the illustration above, we can state that the situation of the circuit is:
  • a. VCC connect to 3V3
    b. GND connect to GND
    c. SCL connect to GPIO (in this tutorial, I'm using GPIO22)
    d. SDA connect to GPIO (in this tutorial, I'm using GPIO21)
If you make it, then the circuit would be look like this.


3. Upload the code

Here is the code for this tutorial. You can go to File > Examples > Adafruit SSD1306 > SSD1306_128x64_i2c or you can simply copy this code.

/**************************************************************************
 This is an example for our Monochrome OLEDs based on SSD1306 drivers

 Pick one up today in the adafruit shop!
 ------> http://www.adafruit.com/category/63_98

 This example is for a 128x64 pixel display using I2C to communicate
 3 pins are required to interface (two I2C and one reset).

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source
 hardware by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries,
 with contributions from the open source community.
 BSD license, check license.txt for more information
 All text above, and the splash screen below must be
 included in any redistribution.
 **************************************************************************/

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

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000 };

void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

*BEWARE*
Make sure you already changed SCREEN_ADDRESS to 0x3c and OLED_RESET to -1 because the program won't work if the DEFINE doesn't suitable to OLED preference/

4. Demonstrations

If your code already uploaded, then test the circuit. If it works, the serial monitor will look like this.
*D


Here is the full video of demonstration



Bonus : 

EXPLORE : Display cute picture of cat to OLED! + PWM

A. Displayed Garfield on OLED 

At this bonus section, I am going to show you how to use an OLED to display the custom picture that we want to. Because the system output/function runs based on program code, the code can be manipulated to be able to output a certain output.

In this experiment, we will try to display random photos on an OLED screen. It should be underlined, the images that can be displayed are 128×64 monocolor bitmap images. In principle, we can convert an image into a bit code so that each bit value represents a hexadecimal value that represents a color, i.e. 0x00 is black and 0xFF is white.

We can directly generate bit-code at the following link https://javl.github.io/image2cpp/ . Make sure you have changed the canvas size to 128 x 64.

In this exploration, I will try to display Garfield the Cat image as shown below.



The results of converting images into bit-code are as follows.

const unsigned char epd_bitmap_Garfield_the_Cat [] PROGMEM = {
  0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xf0, 0xe4, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xc0, 0x18, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0x20, 0x38, 0xa3, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xfe, 0xc8, 0x31, 0xf2, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xf9, 0x8a, 0x87, 0xf3, 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xfb, 0x90, 0x8e, 0x77, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xf7, 0x17, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xe7, 0x3f, 0xcf, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0x78, 0x07, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0x73, 0xf1, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0xef, 0xfc, 0x7f, 0x07, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xcf, 0xce, 0xcf, 0xff, 0x3f, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xc1, 0xce, 0x1f, 0xff, 0x9f, 0xdf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0x83, 0xde, 0x1f, 0xff, 0xcf, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xe0, 0x8e, 0x9f, 0xff, 0xef, 0xef, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0x01, 0x17, 0x9f, 0xff, 0xe7, 0xf6, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x0f, 0x9f, 0xff, 0xf3, 0xf7, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x03, 0x9f, 0xff, 0xf3, 0xf3, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x4e, 0x1f, 0xff, 0xfb, 0xf3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x58, 0x1f, 0xff, 0xf9, 0xfb, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x77, 0xcf, 0xff, 0xfd, 0xf3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfd, 0xeb, 0xef, 0xff, 0xfd, 0xc3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0xef, 0xe7, 0xff, 0xfd, 0x37, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x5f, 0x77, 0xff, 0xf8, 0x77, 0xd9, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x17, 0x3b, 0xff, 0xc5, 0xef, 0x98, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x0f, 0xbd, 0xfc, 0x1c, 0x1f, 0xbc, 0xe7, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x00, 0xbe, 0x03, 0x79, 0xef, 0x79, 0xf3, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x1d, 0x9f, 0x3f, 0xf7, 0xde, 0xc1, 0xfb, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x5f, 0xdf, 0xcf, 0xe6, 0x01, 0xc2, 0xf9, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x3f, 0xcf, 0xf0, 0x39, 0x77, 0xe0, 0xfb, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x61, 0xe7, 0xff, 0xfe, 0xfe, 0xc6, 0xf3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x8c, 0xf3, 0xff, 0xf9, 0xfc, 0x3f, 0x03, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x3e, 0x78, 0xff, 0xe3, 0xf0, 0xff, 0xd8, 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x7e, 0xfe, 0x0e, 0x0f, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x7c, 0xc1, 0xc0, 0xff, 0xf7, 0xff, 0xff, 0xff, 0x3e, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 
  0xfa, 0xfc, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 
  0xf2, 0xf8, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 
  0xf4, 0xf8, 0xfc, 0x9f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 
  0xf4, 0xf8, 0xfc, 0x1f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 
  0xf7, 0xf9, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 
  0xf7, 0xfb, 0xf3, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 
  0xfb, 0xff, 0xef, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x88, 0x07, 0xfc, 0x8f, 0xff, 0xff, 0xff, 
  0xf9, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xfc, 0xe7, 0xff, 0xff, 0xff, 
  0xfc, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xfe, 0xf3, 0xff, 0xff, 0xff, 
  0xfe, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3c, 0xfe, 0x7b, 0xff, 0xff, 0xff, 
  0xff, 0x8f, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 
  0xff, 0xf0, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0x79, 0xff, 0xff, 0xff, 
  0xff, 0xfc, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0x26, 0xff, 0xff, 0xff, 
  0xff, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xbe, 0xfe, 0x0f, 0xff, 
  0xff, 0xf9, 0xfc, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x7f, 0x9e, 0x80, 0x00, 0x7f, 
  0xff, 0xfb, 0xfd, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x7f, 0x7f, 0x20, 0x7f, 0xff, 0x8f, 
  0xff, 0xfb, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x5f, 0x7f, 0x0f, 0xff, 0xff, 0xe7, 
  0xff, 0xf3, 0xff, 0xf9, 0x00, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x9c, 0x7f, 0xff, 0xff, 0xff, 0xfb, 
  0xff, 0xf7, 0xff, 0xe7, 0x80, 0xff, 0xff, 0xfc, 0x04, 0xff, 0x91, 0xff, 0xff, 0xff, 0xff, 0xf5, 
  0xff, 0xf7, 0xff, 0xdf, 0xc0, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x87, 0xff, 0xff, 0xff, 0xfd, 0xf9, 
  0xff, 0xf7, 0xff, 0x3f, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfe, 0xf8, 
  0xff, 0xf7, 0xfc, 0xff, 0xf8, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xfe, 0x7c, 
  0xff, 0xf7, 0xf3, 0xff, 0xfe, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x7d, 
  0xff, 0xf3, 0x87, 0xff, 0xff, 0x80, 0xe0, 0x7f, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xfb, 0xff, 0x79, 
  0xff, 0xe0, 0x07, 0xff, 0xff, 0xe0, 0x40, 0x03, 0xff, 0xff, 0xc0, 0x7f, 0xef, 0xf1, 0xfe, 0x7b, 
  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x7c, 0xe3, 
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xf8, 0x3f, 0x02, 0x01
};

Then, let's make the program for it based on the previous tutorial.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// 'Garfield_the_Cat', 128x64px
const unsigned char epd_bitmap_Garfield_the_Cat [] PROGMEM = {
  0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xf0, 0xe4, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xc0, 0x18, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0x20, 0x38, 0xa3, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xfe, 0xc8, 0x31, 0xf2, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xf9, 0x8a, 0x87, 0xf3, 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xfb, 0x90, 0x8e, 0x77, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xf7, 0x17, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xe7, 0x3f, 0xcf, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0x78, 0x07, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0x73, 0xf1, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0xee, 0xef, 0xfc, 0x7f, 0x07, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xcf, 0xce, 0xcf, 0xff, 0x3f, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xc1, 0xce, 0x1f, 0xff, 0x9f, 0xdf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0x83, 0xde, 0x1f, 0xff, 0xcf, 0xee, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xe0, 0x8e, 0x9f, 0xff, 0xef, 0xef, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0x01, 0x17, 0x9f, 0xff, 0xe7, 0xf6, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x0f, 0x9f, 0xff, 0xf3, 0xf7, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x03, 0x9f, 0xff, 0xf3, 0xf3, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x4e, 0x1f, 0xff, 0xfb, 0xf3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x58, 0x1f, 0xff, 0xf9, 0xfb, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x77, 0xcf, 0xff, 0xfd, 0xf3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfd, 0xeb, 0xef, 0xff, 0xfd, 0xc3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0xef, 0xe7, 0xff, 0xfd, 0x37, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x5f, 0x77, 0xff, 0xf8, 0x77, 0xd9, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x17, 0x3b, 0xff, 0xc5, 0xef, 0x98, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x0f, 0xbd, 0xfc, 0x1c, 0x1f, 0xbc, 0xe7, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x00, 0xbe, 0x03, 0x79, 0xef, 0x79, 0xf3, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x1d, 0x9f, 0x3f, 0xf7, 0xde, 0xc1, 0xfb, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x5f, 0xdf, 0xcf, 0xe6, 0x01, 0xc2, 0xf9, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x3f, 0xcf, 0xf0, 0x39, 0x77, 0xe0, 0xfb, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x61, 0xe7, 0xff, 0xfe, 0xfe, 0xc6, 0xf3, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x8c, 0xf3, 0xff, 0xf9, 0xfc, 0x3f, 0x03, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x3e, 0x78, 0xff, 0xe3, 0xf0, 0xff, 0xd8, 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfe, 0x7e, 0xfe, 0x0e, 0x0f, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
  0xfc, 0x7c, 0xc1, 0xc0, 0xff, 0xf7, 0xff, 0xff, 0xff, 0x3e, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 
  0xfa, 0xfc, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 
  0xf2, 0xf8, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 
  0xf4, 0xf8, 0xfc, 0x9f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 
  0xf4, 0xf8, 0xfc, 0x1f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 
  0xf7, 0xf9, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 
  0xf7, 0xfb, 0xf3, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 
  0xfb, 0xff, 0xef, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x88, 0x07, 0xfc, 0x8f, 0xff, 0xff, 0xff, 
  0xf9, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xfc, 0xe7, 0xff, 0xff, 0xff, 
  0xfc, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xfe, 0xf3, 0xff, 0xff, 0xff, 
  0xfe, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3c, 0xfe, 0x7b, 0xff, 0xff, 0xff, 
  0xff, 0x8f, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 
  0xff, 0xf0, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0x79, 0xff, 0xff, 0xff, 
  0xff, 0xfc, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0x26, 0xff, 0xff, 0xff, 
  0xff, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xbe, 0xfe, 0x0f, 0xff, 
  0xff, 0xf9, 0xfc, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x7f, 0x9e, 0x80, 0x00, 0x7f, 
  0xff, 0xfb, 0xfd, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x7f, 0x7f, 0x20, 0x7f, 0xff, 0x8f, 
  0xff, 0xfb, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x5f, 0x7f, 0x0f, 0xff, 0xff, 0xe7, 
  0xff, 0xf3, 0xff, 0xf9, 0x00, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x9c, 0x7f, 0xff, 0xff, 0xff, 0xfb, 
  0xff, 0xf7, 0xff, 0xe7, 0x80, 0xff, 0xff, 0xfc, 0x04, 0xff, 0x91, 0xff, 0xff, 0xff, 0xff, 0xf5, 
  0xff, 0xf7, 0xff, 0xdf, 0xc0, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x87, 0xff, 0xff, 0xff, 0xfd, 0xf9, 
  0xff, 0xf7, 0xff, 0x3f, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfe, 0xf8, 
  0xff, 0xf7, 0xfc, 0xff, 0xf8, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xfe, 0x7c, 
  0xff, 0xf7, 0xf3, 0xff, 0xfe, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x7d, 
  0xff, 0xf3, 0x87, 0xff, 0xff, 0x80, 0xe0, 0x7f, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xfb, 0xff, 0x79, 
  0xff, 0xe0, 0x07, 0xff, 0xff, 0xe0, 0x40, 0x03, 0xff, 0xff, 0xc0, 0x7f, 0xef, 0xf1, 0xfe, 0x7b, 
  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x7c, 0xe3, 
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xf8, 0x3f, 0x02, 0x01
};

// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
const int epd_bitmap_allArray_LEN = 1;
const unsigned char* epd_bitmap_allArray[1] = {
  epd_bitmap_Garfield_the_Cat
};

void setup() {
  Serial.begin(115200);
 
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000); // Pause for 2 seconds
 
  // Clear the buffer.
  display.clearDisplay();
  //draw it!
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,28);
  display.println("Say Hi to Garfield...");
  display.display();
  delay(3000);
  display.clearDisplay();
  display.drawBitmap(0,0,epd_bitmap_Garfield_the_Cat, 128,64,1);
  display.display();
}

void loop() {
}

Here is the result.

Also the demonstration video:

2. PWM
1. Learn the concept
   PWM or Pulse Width Modulation is a technique for getting analog results with digital means. Digital control is used to crrate a square wave, a signal swtiched between on and off (source : arduino.cc).
To do PWM let's use the circuit schematic below.

source : randomnerdtutorials


2. Set up the circuit
From the illustration above, we can state that the situation of the circuit is:
  • a.. GND connect to negative side of breadboard
    b. Resistor 330 Ohm connect to negative pin of LEDs and negative side of breadboard
    c. GPIO connect to positive pin of LEDs (in this tutorial, I'm using GPIO18, GPIO21, GPIO22)
If you make it, then the circuit would be look like this.


3. Upload the code

Here is the code for this tutorial. You can simply copy this code.

   // the number of the LED pin
const int ledPin = 18; 
const int ledPin2 = 21; 
const int ledPin3 = 22; 

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
 
void setup(){
  // configure LED PWM functionalitites
  ledcSetup(ledChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(ledPin, ledChannel);
  ledcAttachPin(ledPin2, ledChannel);
  ledcAttachPin(ledPin3, ledChannel);
}
 
void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);
    delay(15);
  }

  // decrease the LED brightness
  for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);   
    delay(15);
  }
}

4. Demonstrations

If your code already uploaded, then test the program. If it works, the circuit will look like this.



That's it. Thank you guys.
Semoga bermanfaat!!
- Fariz STI'20 

Komentar

Postingan populer dari blog ini

ESP32 with Multiple I2C Devices

ESP32 Web Server : Turn on LED using WiFi from Your Mobile or Desktop