#include <Wire.h>
#include <RTClib.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);
RTC_DS3231 rtc;
const int button1Pin = 2;
const int button2Pin = 3;
bool lastButton1 = HIGH, lastButton2 = HIGH;
bool stopwatchRunning = false;
unsigned long stopwatchStart = 0;
unsigned long stopwatchElapsed = 0;
int mode = 0; // 0=jam, 1=stopwatch, 2=cube
bool clockVisible = true;
unsigned long lastInteraction = 0;
bool dimmed = false;
// cube
float angle = 0.0;
void setup() {
pinMode(button1Pin, INPUT_PULLUP);
pinMode(button2Pin, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for (;;);
}
display.clearDisplay();
display.display();
if (!rtc.begin()) {
for (;;);
}
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
bool b1 = digitalRead(button1Pin);
bool b2 = digitalRead(button2Pin);
if (lastButton1 == HIGH && b1 == LOW) { // tombol 1 ditekan
lastInteraction = millis();
dimmed = false;
if (mode == 0) {
mode = 1;
} else if (mode == 1) {
if (!stopwatchRunning && stopwatchElapsed > 0) {
stopwatchElapsed = 0;
} else if (!stopwatchRunning && stopwatchElapsed == 0) {
mode = 2; // masuk cube
}
} else if (mode == 2) {
mode = 0; // balik ke jam
}
}
if (lastButton2 == HIGH && b2 == LOW) { // tombol 2 ditekan
lastInteraction = millis();
dimmed = false;
if (mode == 0) {
clockVisible = !clockVisible;
} else if (mode == 1) {
if (stopwatchRunning) {
stopwatchElapsed += millis() - stopwatchStart;
stopwatchRunning = false;
} else {
stopwatchStart = millis();
stopwatchRunning = true;
}
}
}
lastButton1 = b1;
lastButton2 = b2;
if (millis() - lastInteraction > 15000 && !dimmed) {
display.ssd1306_command(SSD1306_DISPLAYOFF);
dimmed = true;
} else if (millis() - lastInteraction <= 15000 && dimmed) {
display.ssd1306_command(SSD1306_DISPLAYON);
dimmed = false;
}
if (!dimmed) {
display.clearDisplay();
if (mode == 0) {
drawClock();
} else if (mode == 1) {
drawStopwatch();
} else if (mode == 2) {
drawCube3D();
}
display.display();
}
delay(50);
}
void drawClock() {
if (!clockVisible) return;
DateTime now = rtc.now();
char buf[9];
sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, 10);
display.print(buf);
const char* days[] = {"Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"};
char datebuf[20];
sprintf(datebuf, "%s %02d/%02d/%04d", days[now.dayOfTheWeek()], now.day(), now.month(), now.year());
display.setTextSize(1);
display.setCursor((SCREEN_WIDTH - strlen(datebuf) * 6) / 2, 40);
display.print(datebuf);
}
void drawStopwatch() {
unsigned long elapsed = stopwatchElapsed;
if (stopwatchRunning) {
elapsed += millis() - stopwatchStart;
}
unsigned long ms = elapsed % 1000;
unsigned long sec = (elapsed / 1000) % 60;
unsigned long min = (elapsed / 60000);
char buf[12];
sprintf(buf, "%02lu:%02lu.%03lu", min, sec, ms);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print(buf);
}
void drawCube3D() {
float size = 20;
float cube[8][3] = {
{-size, -size, -size}, {size, -size, -size}, {size, size, -size}, {-size, size, -size},
{-size, -size, size}, {size, -size, size}, {size, size, size}, {-size, size, size}
};
int projected[8][2];
for (int i = 0; i < 8; i++) {
float x = cube[i][0];
float y = cube[i][1];
float z = cube[i][2];
float xRot = x * cos(angle) - z * sin(angle);
float zRot = x * sin(angle) + z * cos(angle);
float yRot = y;
float distance = 100;
float fov = 64;
float scale = fov / (distance + zRot + 60);
projected[i][0] = (int)(xRot * scale) + SCREEN_WIDTH / 2;
projected[i][1] = (int)(yRot * scale) + SCREEN_HEIGHT / 2;
}
int edges[12][2] = {
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};
for (int i = 0; i < 12; i++) {
int a = edges[i][0];
int b = edges[i][1];
display.drawLine(projected[a][0], projected[a][1], projected[b][0], projected[b][1], SSD1306_WHITE);
}
angle += 0.05;
}