I love pixel art and OLED display makes it even cooler!
It may seem really hard to draw on this type of display, but with some practice you can make your own logo, even animation!
We will use a 128x32 display (128x64 are also really common if you want more space) so it's best to choose a small image.
GameBoy sprites are the easiest to work with but keep in mind we are limited to black/white while the GameBoy can display 4 shades of gray.
You can download sprites from https://www.spriters-resource.com/ to get you started.
In our first example we will use the hackster.io logo.
We need to :
You can use any software to make your images, but I recommend Krita. https://krita.org/en/
In brush presets, choose Pixel Art
Then redraw your image:
White will be no color (black) and black will be color (Blue / White depending on your screen).
Press X to switch between color on Krita
Open the xbm file with a text editor and change the variable name
Original file
#define _width 128 #define _height 32 static char _bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00... };
Readytousefile
#define logo_width 128 #define logo_height 32 static const unsigned char logo[] U8X8_PROGMEM = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00... };
It's best to keep the logo in another.hfile, so it will be easier to read your code.
We will use U8g2 library (which supports a LOT of screens)
#include <Wire.h> //I2C #include <U8g2lib.h> #include "logo.h" //I2C SSD1306 128x32 (search U8g2 examples for other display) U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); void setup() { u8g2.begin(); //Start Screen drawLogo(); } void loop() { } void drawLogo() { u8g2.firstPage(); do { u8g2.drawXBMP(0, 0, logo_width, logo_height, logo); } while ( u8g2.nextPage() ); }
I also put the png and xbm files inside a res/ folder in my code, so I can remember what was my logo.h file.
Upload your code, and voilà!
You can animate your pixel art in two ways:
So if we want to move your sprite from left to right, we just have to change his x position right?
If you use an Arduino Uno, this will work but with more powerful boards (like the Arduino MKR1010) your animation will go too fast!
We need to limit the refresh rate of our animation, of course, we could simply use a delay but it will not allow us to do other things at the same time.
So we will use AsyncDelay library to manage this efficiently
#include <AsyncDelay.h> const int FPS = 1000 / 30; //30 FPS AsyncDelay tick; void setup(){ tick.start(FPS, AsyncDelay::MILLIS); } void loop(){ if(tick.isExpired()){ //ANIMATION HERE tick.repeat(); } }
Last thing, we want our image to go outside the screen at the right and slowly appears on the left.
So we reset the position at the size of the OLED Width (128) with the width of the image (128+36).
And set the position to -36 so the image appears to be coming from the left.
void loop() { if (tick.isExpired()) { drawAnimation(); pos_x = pos_x + X; if (pos_x > OLED_WIDTH + cannon_width) { pos_x = -cannon_width; } tick.repeat(); } }
And here is the result !
Another way to animate image is to use multiple images.
Instead of changing the X position, I make a switch conditionand increase the value animation_state.
void drawAnimation() { u8g2.firstPage(); do { switch (animation_state) { case 0: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_1); break; case 1: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_2); break; case 2: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_3); break; case 3: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_4); break; case 4: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_5); break; case 5: u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_6); break; } } while ( u8g2.nextPage() ); }
Since I want to reverse the animation I used a boolean (animation_direction) so the animation will go backward.
drawAnimation(); if (animation_direction) { animation_state--; } else { animation_state++; } if (animation_state == 5) { animation_direction = true; } if (animation_state == 0) { animation_direction = false; }
Here is the result:
If you combine these two techniques, we can make complex animation:
I hope this tutorial will be useful and you will have as much fun with your OLED screen as I have.
If you made some pixel art please share them in the comment or mention me on twitter @m4dnerd.
| × | 1 | ||||
| × | 1 |
I love pixel art and OLED display makes it even cooler!
It may seem really hard to draw on this type of display, but with some practice you can make your own logo, even animation!
We will use a 128x32 display (128x64 are also really common if you want more space) so it's best to choose a small image.
GameBoy sprites are the easiest to work with but keep in mind we are limited to black/white while the GameBoy can display 4 shades of gray.
You can download sprites from https://www.spriters-resource.com/ to get you started.
In our first example we will use the hackster.io logo.
We need to :
You can use any software to make your images, but I recommend Krita. https://krita.org/en/
In brush presets, choose Pixel Art
Then redraw your image:
White will be no color (black) and black will be color (Blue / White depending on your screen).
Press X to switch between color on Krita
Open the xbm file with a text editor and change the variable name
Original file
#define _width 128
#define _height 32
static char _bits[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00... };
Readytousefile
#define logo_width 128
#define logo_height 32
static const unsigned char logo[] U8X8_PROGMEM = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00... };
It's best to keep the logo in another.hfile, so it will be easier to read your code.
We will use U8g2 library (which supports a LOT of screens)
#include <Wire.h> //I2C
#include <U8g2lib.h>
#include "logo.h"
//I2C SSD1306 128x32 (search U8g2 examples for other display)
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
void setup() {
u8g2.begin(); //Start Screen
drawLogo();
}
void loop() {
}
void drawLogo() {
u8g2.firstPage();
do {
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo);
} while ( u8g2.nextPage() );
}
I also put the png and xbm files inside a res/ folder in my code, so I can remember what was my logo.h file.
Upload your code, and voilà!
You can animate your pixel art in two ways:
So if we want to move your sprite from left to right, we just have to change his x position right?
If you use an Arduino Uno, this will work but with more powerful boards (like the Arduino MKR1010) your animation will go too fast!
We need to limit the refresh rate of our animation, of course, we could simply use a delay but it will not allow us to do other things at the same time.
So we will use AsyncDelay library to manage this efficiently
#include <AsyncDelay.h>
const int FPS = 1000 / 30; //30 FPS
AsyncDelay tick;
void setup(){
tick.start(FPS, AsyncDelay::MILLIS);
}
void loop(){
if(tick.isExpired()){
//ANIMATION HERE
tick.repeat();
}
}
Last thing, we want our image to go outside the screen at the right and slowly appears on the left.
So we reset the position at the size of the OLED Width (128) with the width of the image (128+36).
And set the position to -36 so the image appears to be coming from the left.
void loop() {
if (tick.isExpired()) {
drawAnimation();
pos_x = pos_x + X;
if (pos_x > OLED_WIDTH + cannon_width) {
pos_x = -cannon_width;
}
tick.repeat();
}
}
And here is the result !
Another way to animate image is to use multiple images.
Instead of changing the X position, I make a switch conditionand increase the value animation_state.
void drawAnimation() {
u8g2.firstPage();
do {
switch (animation_state) {
case 0:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_1);
break;
case 1:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_2);
break;
case 2:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_3);
break;
case 3:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_4);
break;
case 4:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_5);
break;
case 5:
u8g2.drawXBMP(0, 0, logo_width, logo_height, logo_6);
break;
}
} while ( u8g2.nextPage() );
}
Since I want to reverse the animation I used a boolean (animation_direction) so the animation will go backward.
drawAnimation();
if (animation_direction) {
animation_state--;
} else {
animation_state++;
}
if (animation_state == 5) {
animation_direction = true;
}
if (animation_state == 0) {
animation_direction = false;
}
Here is the result:
If you combine these two techniques, we can make complex animation:
I hope this tutorial will be useful and you will have as much fun with your OLED screen as I have.
If you made some pixel art please share them in the comment or mention me on twitter @m4dnerd.