// simple project using Arduino UNO and 128x64 OLED Display to display analog clock
// note - this project is meant for the 128x128 SH1107 OLED display, but WOKWI currently only supports 128x64 OLED display
// created by upir, 2023
// youtube channel: https://www.youtube.com/upir_upir, https://youtu.be/srgsBWHSNSQ
// IIC connection of the OLED display and Arduino UNO
// +5V > +5V
// GND > GND
// SCL (serial clock) > A5 or SCL
// SDA (serial data) > A4 or SDA
#include <Arduino.h>
#include <U8g2lib.h> // u8g2 library for drawing on OLED display - needs to be installed in Arduino IDE first
#include <Wire.h> // wire library for IIC communication with the OLED display
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0); // set the OLED display to 128x64px, HW IIC, no rotation, used in WOKWI
//U8G2_SH1107_128X128_1_4W_HW_SPI u8g2(U8G2_R0, 10, 9, 8); //[page buffer, size = 128 bytes]
const int center_x = 64;
const int center_y = 64;
// variables for the tides
const int min_radius = 4;
const int max_radius = 31;
int current_radius = min_radius;
bool growing = true;
// time variables
unsigned long previousTideMillis = 0;
unsigned long previousTickMillis = 0;
const unsigned long tideInterval = 1000; // 1 second
const unsigned long tickInterval = 5000;
int time_seconds = 0; // Tracks seconds for tick rotation
// Time structure
struct DateTimes {
const char* date;
float times[4]; // in hours (e.g., 5.75 for 5:45)
};
DateTimes dateTimesArray[] = {
{ "Step1", { 0.0, 5.75, 12.0, 18.5 } },
{ "Step2", { 0.75, 6.5, 12.5, 19.25 } },
{ "Step3", { 1.5, 7.5, 13.25, 20.0 } },
{ "Step4", { 2.0, 8.5, 14.0, 21.0 } },
{ "Step5", { 2.9, 8.75, 14.0, 21.75 } },
};
const int totalSteps = sizeof(dateTimesArray) / sizeof(dateTimesArray[0]);
int currentStep = 0;
void setup(void) { // Arduino setup
u8g2.begin(); // begin the u8g2 library
u8g2.setContrast(255); // set display contrast/brightness
}
void draw_background() {
u8g2.setDrawColor(1);
u8g2.drawCircle(center_x, center_y, 63, U8G2_DRAW_ALL);
float xpos_center = center_x; // drawing dot at center of the screen
float ypos_center = center_y;
u8g2.drawPixel(xpos_center,ypos_center);
}
void draw_ticks(float times[4]) {
for (int i = 0; i < 4; i++) {
float angle_deg = (times[i] / 24.0) * 360.0;
float angle_rad = angle_deg * PI / 180.0;
float x1 = center_x + sin(angle_rad) * 50;
float y1 = center_y - cos(angle_rad) * 50;
float x2 = center_x + sin(angle_rad) * 63;
float y2 = center_y - cos(angle_rad) * 63;
u8g2.drawLine(x1, y1, x2, y2);
}
}
void draw_tides(int radius, uint8_t color) {
u8g2.setDrawColor(color);
u8g2.drawDisc(center_x, center_y, radius, U8G2_DRAW_ALL);
}
void loop() {
unsigned long currentMillis = millis();
// Time-based animation update
if (currentMillis - previousTideMillis >= tideInterval) {
previousTideMillis = currentMillis;
time_seconds = (time_seconds + 1) % 60;
if (growing) {
current_radius++;
if (current_radius >= max_radius) {
growing = false;
}
} else {
current_radius--;
if (current_radius <= min_radius) {
growing = true;
}
}
}
if (currentMillis - previousTickMillis >= tickInterval) {
previousTickMillis = currentMillis;
currentStep = (currentStep + 1) % totalSteps;
}
// Render display
u8g2.firstPage();
do {
draw_background();
draw_tides(current_radius, 1);
draw_ticks(dateTimesArray[currentStep].times);
} while (u8g2.nextPage());
}