oled — Arduino Uno simulation

An interactive Arduino Uno circuit simulation you can run free in your browser on Velxio, by agungzbudiman.

Components

Sketch code

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

// ========== DEFINISI PIN UNTUK SPI ==========
#define OLED_DC    9
#define OLED_RST   8
#define OLED_CS    10

#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, 
                         &SPI, OLED_DC, OLED_RST, OLED_CS);

// ========== VARIABEL ANIMASI ==========
unsigned long lastBlinkTime = 0;
int blinkPhase = 0; // 0=terbuka, 1=setengah, 2=tertutup
bool isBlinking = false;

// Ekspresi robot
enum RobotExpr {
  NEUTRAL,    // ● ●
  ANGRY,      // > <
  SAD,        // ˘ ˘
  HAPPY,      // ^ ^
  SCAN,       // ◄ ● ► (bergerak)
  GLITCH      // ✦ ✦ (efek glitch)
};

RobotExpr currentExpr = SCAN;
unsigned long lastExprChange = 0;

// Untuk efek SCAN
int scanPos = 0;
int scanDirection = 1;

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

  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }

  display.clearDisplay();
  display.display();
  
  randomSeed(analogRead(0));
}

void loop() {
  unsigned long currentTime = millis();
  
  // ===== GANTI EKSPRESI ACAK =====
  if (currentTime - lastExprChange > 4000) {
    currentExpr = (RobotExpr)random(0, 6);
    lastExprChange = currentTime;
  }
  
  // ===== KEDIP MATA =====
  if (!isBlinking && random(0, 100) < 2) {
    isBlinking = true;
    lastBlinkTime = currentTime;
  }
  
  if (isBlinking) {
    unsigned long elapsed = currentTime - lastBlinkTime;
    if (elapsed < 80) {
      blinkPhase = 1;
    } else if (elapsed < 160) {
      blinkPhase = 2;
    } else if (elapsed < 240) {
      blinkPhase = 1;
    } else {
      blinkPhase = 0;
      isBlinking = false;
    }
  }

  switch (currentExpr) {
    case SCAN:
    case GLITCH:
        blinkPhase = 0;
        break;
    default:
        break;
  }
  
  // ===== UPDATE SCAN POS =====
  if (currentExpr == SCAN) {
    scanPos += scanDirection;
    if (scanPos > 10 || scanPos < -10) scanDirection *= -1;
  }
  
  // ===== GAMBAR MATA ROBOT =====
  drawRobotEyes(currentExpr, blinkPhase);
  
  delay(30);
}

// ============================================================
//  FUNGSI GAMBAR MATA ROBOT (HITAM-PUTIH MINIMALIS)
// ============================================================
void drawRobotEyes(RobotExpr expr, int blink) {
  display.clearDisplay();
  
  // Posisi mata
  int leftX = 32;
  int rightX = 96;
  int eyeY = 32;
  int size = 16;
  
  // ===== BINGKAI ROBOT (kotak di sekitar mata) =====
  // display.drawRect(8, 8, 48, 48, SSD1306_WHITE);
  // display.drawRect(72, 8, 48, 48, SSD1306_WHITE);
  
  // Sudut bingkai (efek robotik)
  // drawCorner(8, 8);
  // drawCorner(56, 8);
  // drawCorner(8, 56);
  // drawCorner(56, 56);
  // drawCorner(72, 8);
  // drawCorner(120, 8);
  // drawCorner(72, 56);
  // drawCorner(120, 56);
  
  // ===== GARIS PENGHUBUNG (seperti visor robot) =====
  // display.drawLine(56, 16, 72, 16, SSD1306_WHITE);
  // display.dra