Pixel OLED Display
Gauri
Pixel OLED Display
Gauri
I wanted to learn how to get a small OLED screen working and see what I could make it show, from text in different sizes to my own images and maybe simple animations. I chose it because a tiny screen feels like a quick way to give a physical object a bit of personality. I could see myself using it in future projects where a product needs to show something without a full display.
Final outcome: I got the display working with text in three different sizes and my own bitmap image. Then I made it into a little photo album with eight of pictures that changes every few minutes or when you press the button. Right now it's all on the breadboard, I'm hoping to make a small case for it next so it can sit on a desk.
Images of final creative/exploratory output
The video shows my display working and going through a series of high-contrast images every 10 secs, but when the button is pressed, the image changes immediately.
Process and reflection:
I started by wiring up the display and following the Adafruit tutorial. Once it was working, I tried out the different text sizes and made a small bitmap image to understand how drawing on the screen works. After that I moved on to the photo album. I used a website to crop some photos i found online to fit the wide screen and to see what they would look like in black and white first. That helped me figure out which photos would still read well with only black and white pixels and which ones would get too messy.
The main thing I learned was how the Arduino IDE handles the photos. They go in their own separate file in the same folder as the sketch, and the code pulls them in from there and goes through them one by one. I didn't know a sketch could be split up like that, and it makes it really easy to swap in new photos without touching the main code. A surprise was how good the high contrast photos looked, like the horse and the lighthouse. Seeing them on the actual device was really cute, it felt like a tiny little album. I'm really happy with where it ended up, and I want to make a small case for it next so it can sit on my desk.
Technical details
Schematic Diagram from the project
/*
Domain-specific Skill Building exercise 1: Tiny Photo Album
This sketch turns a small OLED display into a little photo
album. It shows one black and white photo at a time and chnages to the
next one every 10 secs, or right away when you press the button
Photos change with transition and a new photo comes from the left side
The photos are stored as bitmaps in a separate file, photos.h, in the same folder
as this sketch.
Arduino pin | role | details
------------------------------
A4 I2C OLED SDA
A5 I2C OLED SCL
2 input button
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "photos.h"
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SCREEN_ADDRESS 0x3C
const int BUTTON_PIN = 2;
//photo stays on for 10 secs
const unsigned long PHOTO_INTERVAL = 10UL * 1000UL;
const int WIPE_STEP = 8; // pixels per frame
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
int currentPhoto = 0;
unsigned long lastChangeTime = 0;
// button debounce state
int lastButtonReading = HIGH;
int buttonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_MS = 30;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP); // reads it as LOW when the button is pressed
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 not found. Check wiring and address."));
while (true);
}
Wire.setClock(400000); // this is added for a smoother swipe of the photos
drawPhoto(currentPhoto);
display.display();
lastChangeTime = millis();
}
void loop() {
bool pressed = checkButton();
bool timeUp = (millis() - lastChangeTime >= PHOTO_INTERVAL);
if (pressed || timeUp) {
int nextPhoto = (currentPhoto + 1) % NUM_PHOTOS;
wipeTo(nextPhoto);
currentPhoto = nextPhoto;
lastChangeTime = millis(); // pressing the button also resets the timer
}
}
// Returns true once per press - ont eh moment when the button is pressed down
bool checkButton() {
int reading = digitalRead(BUTTON_PIN);
bool justPressed = false;
if (reading != lastButtonReading) {
lastDebounceTime = millis();
}
if (millis() - lastDebounceTime > DEBOUNCE_MS && reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) justPressed = true;
}
lastButtonReading = reading;
return justPressed;
}
void drawPhoto(int index) {
const unsigned char* bmp = (const unsigned char*)pgm_read_ptr(&photos[index]);
display.clearDisplay();
display.drawBitmap(0, 0, bmp, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
}
void wipeTo(int nextIndex) {
// BLACK screen slides onto the photo for a smoother transition
for (int x = 0; x <= SCREEN_WIDTH; x += WIPE_STEP) {
display.fillRect(0, 0, x, SCREEN_HEIGHT, SSD1306_BLACK);
display.display();
}
// new photo is revealed from the left
for (int x = 0; x <= SCREEN_WIDTH; x += WIPE_STEP) {
drawPhoto(nextIndex);
display.fillRect(x, 0, SCREEN_WIDTH - x, SCREEN_HEIGHT, SSD1306_BLACK);
display.display();
}
}