#include <TinyWireM.h>
#include <Adafruit_NeoPixel.h>
#define PIN_WS2812 1 // Pin untuk WS2812B
#define NUM_LEDS 30 // Jumlah LED
#define DS1307_ADDR 0x68 // Alamat I2C RTC DS1307
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN_WS2812, NEO_GRB + NEO_KHZ800);
// Konfigurasi posisi LED untuk setiap segmen
const uint8_t dpMapping[2] = {0, 1}; // Titik desimal (DP)
const uint8_t digitMapping[4][7] = {
{2, 3, 4, 5, 6, 7, 8}, // Digit 1 (jam puluhan)
{9, 10, 11, 12, 13, 14, 15}, // Digit 2 (jam satuan)
{16, 17, 18, 19, 20, 21, 22}, // Digit 3 (menit puluhan)
{23, 24, 25, 26, 27, 28, 29} // Digit 4 (menit satuan)
};
// Angka 7-segment dalam bentuk bitmask
const uint8_t segmentMap[10] = {
0b0111111, // 0
0b0000110, // 1
0b1011011, // 2
0b1001111, // 3
0b1100110, // 4
0b1101101, // 5
0b1111101, // 6
0b0000111, // 7
0b1111111, // 8
0b1101111 // 9
};
uint8_t time[4] = {0, 0, 0, 0};
uint8_t seconds, minutes, hours;
bool colon = false;
uint8_t wheelPos = 0; // Posisi roda warna
unsigned long lastBlinkTime = 0; // Waktu untuk mengatur blink DP
bool dpState = false; // Status nyala/mati DP
void setup() {
TinyWireM.begin(); // Setup TinyWire I2C
strip.begin(); // Inisialisasi WS2812B
strip.setBrightness(255); // Set brightness maksimal
strip.show(); // Matikan semua LED
}
void loop() {
updateClock(); // Perbarui waktu dari RTC
displayTime(); // Tampilkan waktu pada WS2812B
animateWheel(); // Animasi wheel berjalan dari kiri bawah ke kanan atas
blinkDP(); // Blink titik desimal (DP)
delay(100); // Delay untuk animasi
}
void updateClock() {
TinyWireM.beginTransmission(DS1307_ADDR); // Reset DS1307 register pointer
TinyWireM.send(0x00);
TinyWireM.endTransmission();
// Request 7 bytes dari DS1307
TinyWireM.requestFrom(DS1307_ADDR, 7);
seconds = bcdToDec(TinyWireM.receive() & 0x7F);
minutes = bcdToDec(TinyWireM.receive());
hours = bcdToDec(TinyWireM.receive());
// Konversi jam ke format 12 jam
if (hours >= 12) {
if (hours > 12) hours -= 12;
} else {
if (hours == 0) hours = 12; // Jam 0 pada format 24 jam menjadi 12 pada format 12 jam
}
time[0] = hours / 10;
time[1] = hours % 10;
time[2] = minutes / 10;
time[3] = minutes % 10;
colon = seconds & 1; // Kolon menyala setiap detik
}
void displayTime() {
strip.clear(); // Matikan semua LED
// Tampilkan angka pada setiap digit
for (int digit = 0; digit < 4; digit++) {
uint8_t segments = segmentMap[time[digit]];
for (int segment = 0; segment < 7; segment++) {
if (segments & (1 << segment)) {
strip.setPixelColor(
digitMapping[digit][segment],
colorWheel((digit * 7 + segment + wheelPos) & 255) // Warna berdasarkan roda warna
);
}
}
}
// Tampilkan titik desimal (colon) jika menyala
if (dpState) {
strip.setPixelColor(dpMapping[0], strip.Color(255, 255, 255)); // Putih
strip.setPixelColor(dpMapping[1], strip.Color(255, 255, 255)); // Putih
}
strip.show(); // Tampilkan semua perubahan
}
void animateWheel() {
wheelPos = (wheelPos + 1) & 255; // Update posisi roda warna
}
void blinkDP() {
unsigned long currentMillis = millis();
// Blink DP setiap detik dengan durasi nyala 50ms
if (currentMillis - lastBlinkTime >= 1000) {
lastBlinkTime = currentMillis;
dpState = !dpState; // Toggle antara nyala dan mati
}
if (dpState) {
// DP menyala selama 50ms
if (currentMillis - lastBlinkTime < 50) {
dpState = true;
} else {
dpState = false;
}
}
}
uint32_t colorWheel(uint8_t position) {
// Fungsi untuk menghasilkan solid warna dari roda warna (rainbow)
if (position < 85) {
return strip.Color(255 - position * 3, 0, position * 3); // Merah ke biru
} else if (position < 170) {
position -= 85;
return strip.Color(0, position * 3, 255 - position * 3); // Hijau ke biru
} else {
position -= 170;
return strip.Color(position * 3, 255 - position * 3, 0); // Kuning ke merah
}
}
uint8_t bcdToDec(uint8_t value) {
return ((value / 16 * 10) + (value % 16));
}