Skip to content

Output Devices

Group Assignment:

  • measure the power consumption of an output device

Individual Assignment:

  • add an output device to a microcontroller board you've designed and program it to do something

OLED

OLED is a self-illuminating display technology that provides superior image quality with perfect blacks, high contrast, and fast response times. It's widely used in premium displays but has limitations including potential burn-in and shorter lifespan compared to some alternatives. (From Claude, Prompt: What are OLED?)

I started by using an OLED from the fab inventory. It is very simple to connect VCC, GND, SDA, and SCL. But make sure you connect it correctly, as I did not and fried one screen. I plugged it in, went to connect my microcontroller, and then there was smoke and it was dead. Second try it worked, and I was able to display text on the screen. Next, I went to Claude and asked it to change the script I got from Adrian and made it count how many times I pressed a button. When I was about to take a video, the screen decided to stop working. Once I figure that out, I will add a video here.

(Video)

Here is the code

#include <U8g2lib.h>

// OLED display using SSD1306 driver
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset= */ U8X8_PIN_NONE);

const int buttonPin = D7;  // Button connected to 3.3V
int buttonState = LOW;     // Current state of the button
int lastButtonState = LOW; // Previous state of the button
int pressCount = 0;        // Number of button presses
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) {}
  delay(100);
  Serial.println("OLED Button Counter - Setup (3.3V logic)");

  pinMode(buttonPin, INPUT);  // For 3.3V button, use INPUT with external pulldown
  u8g2.begin();
}

void loop(void) {
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading; 

      // Count only when button is pressed (HIGH)
      if (buttonState == HIGH) {
        pressCount++;
      }
    }
  }

  lastButtonState = reading;

  // Display on OLED
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);
  u8g2.drawStr(0, 10, "Puffin has entered:");
  char buf[20];
  snprintf(buf, sizeof(buf), "%d times", pressCount);
  u8g2.drawStr(0, 30, buf);
  u8g2.sendBuffer();

  delay(50);
}

E-ink

E-Ink is a paper-like display technology that uses electrically charged particles to create images, offering high readability and extremely low power consumption, but with slower refresh rates than conventional displays. (From Claude, Prompt: What is E-Ink?)

I used the E-Ink breakout board from Seeed. It was a bit of a hassle to get working. One thing to note here is the screen takes a while to update, so it confused me when nothing was happening, but I just had to wait a little bit. Also, you have to let the screen rest in between refreshes; otherwise, it will not turn white. I used this documentation from Seeed and the example clock script. Here is an image:

Image of an E-INK display

LCD

I think this is what i am going to use for my final project. It is simple to connect and the code is very simple. I began by getting a grove LCD and connecting it to a board with a XIAO ESP32C3 and asked my good friend ChatGPT to write some code. Most is written by AI but a good portion is my own. Quick note is i am using a custom Arduino Libery from Seed. Downloadable here. Here is the main code. It is quite simple but a good start the next step will be adding a step response and making it count when someone touches it.

#include <Wire.h>
#include "rgb_lcd.h"

rgb_lcd lcd;

const int buttonPin = 20;

int lastButtonState = LOW;
int pressState = 0;

int inCount = 0;
int outCount = 0;

void setup() {
  delay(500);

  pinMode(buttonPin, INPUT); 

  lcd.begin(16, 2);
  lcd.clear();

  // --- LOADING SCREEN ---
  lcd.setCursor(0, 0); // Left-aligned
  lcd.print("PuffIN & OUT!");

  const char* dots[] = { "Loading.  ", "Loading.. ", "Loading..." };
  for (int i = 0; i < 5; i++) {
    lcd.setCursor(0, 1);
    lcd.print(dots[i % 3]);
    delay(1000);
  }

  // --- MAIN DISPLAY ---
  lcd.clear();
  lcd.setCursor(0, 0); // Left-aligned again
  lcd.print("PuffIN & OUT!");

  lcd.setCursor(0, 1);
  lcd.print("IN: 0   OUT: 0");
}

void loop() {
  int buttonState = digitalRead(buttonPin);

  if (lastButtonState == LOW && buttonState == HIGH) {
    if (pressState == 0) {
      inCount++;
    } else {
      outCount++;
    }

    pressState = 1 - pressState;

    lcd.setCursor(0, 1);
    lcd.print("                ");
    char buffer[17];
    snprintf(buffer, sizeof(buffer), "IN: %-3d OUT: %-3d", inCount, outCount);
    lcd.setCursor(0, 1);
    lcd.print(buffer);

    delay(200); // debounce
  }

  lastButtonState = buttonState;
}