#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Clock variables
int hour = 12, minute = 0, second = 0;
unsigned long prevMillis = 0;
bool colonVisible = true;
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED not found");
while(true);
}
// Eye animation sequence
eyeLookingAnimation();
// Loading animation
showLoadingScreen();
// Initial clock display
showClockHeader();
}
void loop() {
updateClock();
}
void eyeLookingAnimation() {
const int leftEyeX = 38, rightEyeX = 90;
const int eyeY = 32;
const int pupilRadius = 4;
const int eyeRadius = 12;
// Animation sequence (left-center-right-center)
for(int i = 0; i < 2; i++) {
// Look straight
drawEyes(leftEyeX, eyeY, rightEyeX, eyeY, 0, eyeRadius, pupilRadius);
delay(800);
// Look right
drawEyes(leftEyeX, eyeY, rightEyeX, eyeY, 6, eyeRadius, pupilRadius);
delay(500);
// Look straight
drawEyes(leftEyeX, eyeY, rightEyeX, eyeY, 0, eyeRadius, pupilRadius);
delay(800);
// Look left
drawEyes(leftEyeX, eyeY, rightEyeX, eyeY, -6, eyeRadius, pupilRadius);
delay(500);
}
// Blink animation
for(int i = 0; i < 2; i++) {
// Open eyes
drawEyes(leftEyeX, eyeY, rightEyeX, eyeY, 0, eyeRadius, pupilRadius);
delay(300);
// Closed eyes
drawClosedEyes(leftEyeX, eyeY, rightEyeX, eyeY, eyeRadius);
delay(300);
}
}
void drawEyes(int leftX, int y, int rightX, int eyeY, int pupilOffset, int eyeRadius, int pupilRadius) {
display.clearDisplay();
// Draw eyebrows (position changes with look direction)
drawEyebrows(leftX, eyeY-18, rightX, eyeY-18, pupilOffset);
// Draw eye outlines
display.drawCircle(leftX, eyeY, eyeRadius, SSD1306_WHITE);
display.drawCircle(rightX, eyeY, eyeRadius, SSD1306_WHITE);
// Draw pupils with offset
display.fillCircle(leftX + pupilOffset, eyeY, pupilRadius, SSD1306_WHITE);
display.fillCircle(rightX + pupilOffset, eyeY, pupilRadius, SSD1306_WHITE);
display.display();
}
void drawEyebrows(int leftX, int y, int rightX, int eyebrowY, int expression) {
// Left eyebrow
if(expression > 0) { // Looking right - left eyebrow raised
display.drawLine(leftX-15, eyebrowY-2, leftX+5, eyebrowY+1, SSD1306_WHITE);
} else if(expression < 0) { // Looking left - left eyebrow lowered
display.drawLine(leftX-15, eyebrowY+2, leftX+5, eyebrowY, SSD1306_WHITE);
} else { // Neutral
display.drawLine(leftX-15, eyebrowY, leftX+5, eyebrowY, SSD1306_WHITE);
}
// Right eyebrow
if(expression > 0) { // Looking right - right eyebrow lowered
display.drawLine(rightX-5, eyebrowY+1, rightX+15, eyebrowY-2, SSD1306_WHITE);
} else if(expression < 0) { // Looking left - right eyebrow raised
display.drawLine(rightX-5, eyebrowY, rightX+15, eyebrowY+2, SSD1306_WHITE);
} else { // Neutral
display.drawLine(rightX-5, eyebrowY, rightX+15, eyebrowY, SSD1306_WHITE);
}
}
void drawClosedEyes(int leftX, int y, int rightX, int eyeY, int eyeRadius) {
display.clearDisplay();
// Draw straight eyebrows
drawEyebrows(leftX, eyeY-18, rightX, eyeY-18, 0);
// Draw closed eyes as arcs
display.drawFastHLine(leftX-eyeRadius, eyeY, eyeRadius*2, SSD1306_WHITE);
display.drawFastHLine(rightX-eyeRadius, eyeY, eyeRadius*2, SSD1306_WHITE);
display.display();
}
void showLoadingScreen() {
display.clearDisplay();
// Smiley face
display.drawCircle(64, 20, 15, SSD1306_WHITE); // Head
display.drawPixel(60, 15, SSD1306_WHITE); // Left eye
display.drawPixel(68, 15, SSD1306_WHITE); // Right eye
display.drawLine(60, 25, 68, 25, SSD1306_WHITE); // Mouth
// Loading text
display.setTextSize(1);
display.setCursor(35, 45);
display.print("Initializing...");
display.display();
delay(1000);
// Animated progress bar
for(int i = 0; i <= 100; i+=5) {
display.drawRect(10, 55, 108, 6, SSD1306_WHITE);
display.fillRect(10, 55, i, 6, SSD1306_WHITE);
display.display();
delay(50);
}
delay(300);
}
// ========== CLOCK FUNCTIONS ==========
void showClockHeader() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(20, 0);
display.println("DIGITAL CLOCK");
display.display();
delay(1000);
}
void updateClock() {
unsigned long currentMillis = millis();
if(currentMillis - prevMillis >= 1000) {
prevMillis = currentMillis;
second++;
colonVisible = !colonVisible;
if(second >= 60) {
second = 0;
minute++;
if(minute >= 60) {
minute = 0;
hour++;
if(hour >= 24) hour = 0;
}
}
displayClock();
}
}
void displayClock() {
display.clearDisplay();
// Header
display.setTextSize(1);
display.setCursor(35, 0);
display.print("DIGITAL CLOCK");
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Time display
display.setTextSize(2);
display.setCursor(15, 25);
if(colonVisible) {
display.printf("%02d:%02d:%02d", hour, minute, second);
} else {
display.printf("%02d %02d %02d", hour, minute, second);
}
// Border
display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
// Footer
display.setTextSize(1);
display.setCursor(28, 55);
display.print("OLED Display");
display.display();
}