Week 09 — Output Devices. This week I redesigned and milled a new PCB to start my final project. The output device is a 0.96″ OLED display, driven over I²C and controlled by four buttons that switch the on‑screen scenes.
Assignments
- Group: measure the power consumption of an output device.
- Individual: add an output device to a microcontroller board I designed, and program it to do something.
Group assignment (1–5)
We profiled the current draw of small LEDs and an OLED breakout at different voltages/brightness levels using a bench supply and a DMM inline. Gert also showed what happens when an LED is driven past its safe voltage — a brief flash, then a visible failure. It was a vivid reminder to respect datasheets and series resistors.
Individual assignment (6–15)
I redesigned my ESP32‑S3 board to include a 4‑button input cluster and an I²C header for the SSD1306 OLED (0x3C/0x3D). After milling and soldering, I verified continuity, then brought the display up on I2C1 to avoid conflicts with default pins. Each button selects a different scene label on the screen — a tiny UI prototype for the final project’s environmental “modes.”
Firmware — Four‑button OLED UI
I used Adafruit_GFX and Adafruit_SSD1306 on I2C(1). Four buttons (D0–D3) are debounced in software; a falling edge updates the center‑aligned label on the screen. SDA/SCL are on D8/D7. The sketch below is what’s running in the video.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define W 128
#define H 64
const int SDA_PIN = D8;
const int SCL_PIN = D7;
TwoWire I2C(1);
Adafruit_SSD1306 display(W, H, &I2C, -1);
const int BTN[4] = { D0, D1, D2, D3 };
const char* LABEL[4] = { "RIVER", "LAKE", "OCEAN", "???" };
void showText(const char* s) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
int16_t x1, y1; uint16_t w, h;
display.getTextBounds(s, 0, 0, &x1, &y1, &w, &h);
int x = (W - (int)w) / 2;
int y = (H - (int)h) / 2;
display.setCursor(x, y);
display.println(s);
display.display();
}
void setup() {
Serial.begin(115200);
delay(200);
pinMode(SDA_PIN, INPUT_PULLUP);
pinMode(SCL_PIN, INPUT_PULLUP);
I2C.begin(SDA_PIN, SCL_PIN, 100000);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println("OLED init failed.");
while (1) delay(10);
}
}
for (int i = 0; i < 4; i++) pinMode(BTN[i], INPUT_PULLUP);
showText("READY");
}
void loop() {
static uint8_t last[4] = {HIGH, HIGH, HIGH, HIGH};
static unsigned long lastDebounce[4] = {0,0,0,0};
const unsigned long DEBOUNCE_MS = 30;
for (int i = 0; i < 4; i++) {
uint8_t now = digitalRead(BTN[i]);
if (now != last[i]) {
lastDebounce[i] = millis();
last[i] = now;
}
if ((millis() - lastDebounce[i]) > DEBOUNCE_MS) {
static uint8_t stablePrev[4] = {HIGH, HIGH, HIGH, HIGH};
if (stablePrev[i] == HIGH && now == LOW) {
showText(LABEL[i]);
Serial.print("Button "); Serial.print(i); Serial.println(" pressed.");
}
stablePrev[i] = now;
}
}
}