/*
UNO Neopixel Clock with RTC
60 Neopixels from 6:00 to 20:59 - One pixel per quarter
https://forum.arduino.cc/t/zeitanzeige-uber-led-balken/1237662/
2024-03-20 by noiasca : inital version: https://wokwi.com/projects/392897977230186497
2024-04-02 by noiasca : Variant if buttons to change the time https://wokwi.com/projects/394075485276791809
2024-04-05 by wwerner : Variant with nano and LED Stripe: https://wokwi.com/projects/394346180260683777
*/
#include <Wire.h> // Default library for I2C
#include <Adafruit_NeoPixel.h> // Install via Library Manager
#include <RTClib.h> // Install via Library Manager
#include <OneButton.h> // Install via Library Manager
#include <TM1637Display.h> // TM1637 by Avishay Orpaz - Install via Library Manager
OneButton btnA(A1, true); // a button which will close to GND (activeLOW)
OneButton btnB(A0, true); // another button
constexpr uint8_t pixelPin {2}; // input pin Neopixel is attached to
constexpr uint8_t pixelNum {60}; // number of neopixels
constexpr uint8_t dioPin{3}; // DIO pin of TM1637
constexpr uint8_t clkPin {4}; // CLK pin of TM1637
TM1637Display display(clkPin, dioPin);
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(pixelNum, pixelPin, NEO_GRB + NEO_KHZ800);
RTC_DS1307 rtc;
// Debug Ausgabe der Uhrzeit auf Serial und Display
void showTime() {
DateTime now = rtc.now();
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
// Ausgabe auf Hilfsdisplay
//showNumberDec(int num, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
display.showNumberDec(now.hour(), false, 2, 0);
display.showNumberDec(now.minute(), true, 2, 2); // möglicherweise muss man den Startdigit (pos) an die tatsächliche Hardware anpassen. Hier im Simulator ist 2 offenbar richtig.
}
// Anzeige auf 60 Neopixel
void showNeopixel(uint8_t hour, uint8_t minute) {
const uint32_t colorOff = 0x000000; // inaktiv
const uint32_t colorOn = 0x00FF00; // aktiv
const uint32_t colorOffMarker = 0x808000; // 3h Stundenmarker inaktiv
const uint32_t colorOnMarker = 0xFF0000; // 3h Stundenmarker aktiv
uint32_t color = colorOff;
int quarter = hour * 4 + minute / 15;
int startQuarter = 6 * 4;
Serial.print("quarter="); Serial.println(quarter);
for (uint16_t i = 0; i < pixelNum; i++) {
if ((quarter - startQuarter) >= i) {
if (i == 0 || i == 12 || i == 24 || i == 36 || i == 48) // die 3h Stundenmarker
color = colorOnMarker;
else
color = colorOn;
}
else {
if (i == 0 || i == 12 || i == 24 || i == 36 || i == 48) // jaja ich weis ...
color = colorOffMarker;
else
color = colorOff;
}
pixels.setPixelColor(i, color);
//Serial.print(i); Serial.print("\t 0x"); Serial.println(color, HEX);
}
pixels.show();
}
// trigger update of clock - if necessary
void timer() {
static uint16_t previousMinute = 65;
DateTime now = rtc.now();
if (now.minute() != previousMinute) {
previousMinute = now.minute();
showNeopixel(now.hour(), now.minute()); // update Neopixel
showTime(); // update Time on Serial
}
}
// Uhrzeit um n Minuten verändern
// wird nicht mehr benötigt - mir gefällt das aber so gut, dass ich es drinnen lasse
void change(int8_t offset = 15) {
DateTime now = rtc.now();
uint16_t minuteOfDay = now.hour() * 60 + now.minute(); // Minute des Tages, (hour*60 + minute)
uint32_t minuteOfDayRounded = (minuteOfDay / abs(offset)) * abs(offset) * 1UL; // runden (z.B. auf volle 15 Minuten)
uint16_t minuteOfDayNew = minuteOfDayRounded + offset; // Neue Uhrzeit ermitteln
uint8_t newHour = minuteOfDayNew / 60 % 24; // ergibt neue Stunde
uint8_t newMinute = minuteOfDayNew % 60; // ergibt neue Minute
Serial.print("now="); Serial.println(minuteOfDay);
Serial.print("rounded="); Serial.println(minuteOfDayRounded);
Serial.print("new="); Serial.println(minuteOfDayNew);
Serial.print("new time="); Serial.print(newHour); Serial.print(":"); Serial.println(newMinute);
// (year, month, day, hour, minute, second)
rtc.adjust(DateTime(now.year(), now.month(), now.day(), newHour, newMinute, 0));
showTime(); // triggers also the output on the Neopixels
}
void actionA() {
Serial.println("H up");
DateTime now = rtc.now();
uint8_t h = now.hour();
h = (h + 1) % 24;
rtc.adjust(DateTime(now.year(), now.month(), now.day(), h, now.minute(), now.second()));
showTime(); // triggers also the output on the Neopixels
showNeopixel(h, now.minute()); // update Neopixel
}
void actionB() {
Serial.println("M up");
DateTime now = rtc.now();
uint8_t m = now.minute();
m = (m + 1) % 60;
rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), m, 0));
showTime();
// implicit trigger of neopixel through change of minute
}
void setup() {
Serial.begin(115200);
pixels.begin(); // Initializes the NeoPixel library.
display.setBrightness(0x0f);
Wire.begin();
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
}
btnA.attachClick(actionA);
btnB.attachClick(actionB);
// only test - einzeln aktivieren - und im loop den timer auskommentieren
//showNeopixel(6, 14); // nur 6 Uhr
//showNeopixel(6, 15); // 6 Uhr + 1 Viertelstunde
//showNeopixel(6, 16); // 6 Uhr + 1 Viertelstunde
//showNeopixel(12, 0);
//showNeopixel(19, 0); // 18 Uhr + 4 Viertelstunde
}
void loop() {
timer();
btnA.tick();
btnB.tick();
}
9 o'clock
18 o'clock
15 o'clock
12 o'clock
6 o'clock
Set Time
21 o'clock