#define LGFX_USE_V1
#include <LovyanGFX.hpp>
static LGFX lcd;
static LGFX_Sprite canvas(&lcd); // Bufor rysowania poza ekranem
static LGFX_Sprite clockbase(&canvas); // Części tarczy zegara
static LGFX_Sprite needle1(&canvas); // Długie i krótkie części ramion
static LGFX_Sprite shadow1(&canvas); // Cienie wskazówek godzinowej i minutowej
static LGFX_Sprite needle2(&canvas); // Części używane
static LGFX_Sprite shadow2(&canvas); // Część cienia z drugiego ramienia
static constexpr uint64_t oneday = 86400000; // 1 dzień = 1000 ms x 60 s x 60 min x 24 godziny = 86400000
static uint64_t count = rand() % oneday; // Aktualny czas (licznik milisekund)
static int32_t width = 239; // Rozmiar obrazu zegara
static int32_t halfwidth = width >> 1; // Współrzędne środka tarczy zegara
static auto transpalette = 0; // Numer transparentnej palety kolorów
static float zoom; // Oznacza powiększenie
#ifdef min
#undef min
#endif
void setup(void) {
lcd.init();
// Dostosuj powiększenie, aby dopasować je do wyświetlacza na ekranie
zoom = (float)(std::min(lcd.width(), lcd.height())) / width;
// Wyrównaj środek rysunku zegara do środka ekranu
lcd.setPivot(lcd.width() >> 1, lcd.height() >> 1);
// Przygotuj każdą część w trybie palety 4-bitowej
canvas.setColorDepth(lgfx::palette_4bit);
clockbase.setColorDepth(lgfx::palette_4bit);
needle1.setColorDepth(lgfx::palette_4bit);
shadow1.setColorDepth(lgfx::palette_4bit);
needle2.setColorDepth(lgfx::palette_4bit);
shadow2.setColorDepth(lgfx::palette_4bit);
// Początkowe kolory w palecie to gradient skali szarości
// Liczba 0 to czerń (0,0,0), a liczba 15 to biel (255,255,255)
// Liczby od 1 do 14 mają stopniowo zwiększającą się jasność od czerni do bieli
// Podczas korzystania z palety funkcja rysowania określa numer palety (od 0 do 15) zamiast koloru
// Alokacja pamięci
canvas.createSprite(width, width);
clockbase.createSprite(width, width);
needle1.createSprite(9, 119);
shadow1.createSprite(9, 119);
needle2.createSprite(3, 119);
shadow2.createSprite(3, 119);
// Wypełnij tło przezroczystym kolorem (można to pominąć, ponieważ od razu po utworzeniu tło zostanie wypełnione zerami)
canvas.fillScreen(transpalette);
clockbase.fillScreen(transpalette);
needle1.fillScreen(transpalette);
shadow1.fillScreen(transpalette);
// Zmień rodzaj czcionki (dla tekstu na tarczy zegara)
clockbase.setTextFont(4);
clockbase.setTextDatum(lgfx::middle_center);
// Namaluj tło tarczy zegara w kształcie koła
clockbase.fillCircle(halfwidth, halfwidth, halfwidth, 6);
clockbase.drawCircle(halfwidth, halfwidth, halfwidth - 1, 15);
for (int i = 1; i <= 60; ++i) {
// Znajdź współrzędne skali na zewnętrznej krawędzi tarczy zegara
float rad = i * 6 * - 0.0174532925;
float cosy = - cos(rad) * (halfwidth * 10 / 11);
float sinx = - sin(rad) * (halfwidth * 10 / 11);
// Flaga co 5 skalę
bool flg = 0 == (i % 5);
// Narysuj znaczniki
clockbase.fillCircle(halfwidth + sinx + 1, halfwidth + cosy + 1, flg * 3 + 1, 4);
clockbase.fillCircle(halfwidth + sinx, halfwidth + cosy, flg * 3 + 1, 12);
// Rysowanie postaci
if (flg) {
cosy = - cos(rad) * (halfwidth * 10 / 13);
sinx = - sin(rad) * (halfwidth * 10 / 13);
clockbase.setTextColor(1);
clockbase.drawNumber(i / 5, halfwidth + sinx + 1, halfwidth + cosy + 4);
clockbase.setTextColor(15);
clockbase.drawNumber(i / 5, halfwidth + sinx, halfwidth + cosy + 3);
}
}
clockbase.setTextFont(7);
// Ustaw współrzędne środka obrotu części igły
needle1.setPivot(4, 100);
shadow1.setPivot(4, 100);
needle2.setPivot(1, 100);
shadow2.setPivot(1, 100);
// Tworzenie obrazu części igły
for (int i = 6; i >= 0; --i) {
needle1.fillTriangle(4, - 16 - (i << 1), 8, needle1.height() - (i << 1), 0, needle1.height() - (i << 1), 15 - i);
shadow1.fillTriangle(4, - 16 - (i << 1), 8, shadow1.height() - (i << 1), 0, shadow1.height() - (i << 1), 1 + i);
}
for (int i = 0; i < 7; ++i) {
needle1.fillTriangle(4, 16 + (i << 1), 8, needle1.height() + 32 + (i << 1), 0, needle1.height() + 32 + (i << 1), 15 - i);
shadow1.fillTriangle(4, 16 + (i << 1), 8, shadow1.height() + 32 + (i << 1), 0, shadow1.height() + 32 + (i << 1), 1 + i);
}
needle1.fillTriangle(4, 32, 8, needle1.height() + 64, 0, needle1.height() + 64, 0);
shadow1.fillTriangle(4, 32, 8, shadow1.height() + 64, 0, shadow1.height() + 64, 0);
needle1.fillRect(0, 117, 9, 2, 15);
shadow1.fillRect(0, 117, 9, 2, 1);
needle1.drawFastHLine(1, 117, 7, 12);
shadow1.drawFastHLine(1, 117, 7, 4);
needle1.fillCircle(4, 100, 4, 15);
shadow1.fillCircle(4, 100, 4, 1);
needle1.drawCircle(4, 100, 4, 14);
needle2.fillScreen(9);
shadow2.fillScreen(3);
needle2.drawFastVLine(1, 0, 119, 8);
shadow2.drawFastVLine(1, 0, 119, 1);
needle2.fillRect(0, 99, 3, 3, 8);
lcd.startWrite();
// W celu debugowania narysuj części bezpośrednio na wyświetlaczu LCD
// shadow1.pushSprite(&lcd, 0, 0);
// needle1.pushSprite(&lcd, 10, 0);
// shadow2.pushSprite(&lcd, 20, 0);
// needle2.pushSprite(&lcd, 25, 0);
}
// Rysowanie wyświetlacza cyfrowego na tarczy zegara
void update7Seg(int32_t hour, int32_t min) {
int x = clockbase.getPivotX() - 69;
int y = clockbase.getPivotY();
clockbase.setCursor(x, y);
// Narysuj 88:88 kolorem gumki
clockbase.setTextColor(5);
clockbase.print("88:88");
clockbase.setCursor(x, y);
// Narysuj godziny i minuty w kolorze
clockbase.setTextColor(12);
clockbase.printf("%02d:%02d", hour, min);
}
void drawDot(int pos, int palette) {
// Flaga co 5 skalę
bool flg = 0 == (pos % 5);
// Znajdź współrzędne skali na zewnętrznej krawędzi tarczy zegara
float rad = pos * 6 * - 0.0174532925;
float cosy = - cos(rad) * (halfwidth * 10 / 11);
float sinx = - sin(rad) * (halfwidth * 10 / 11);
canvas.fillCircle(halfwidth + sinx, halfwidth + cosy, flg * 3 + 1, palette);
}
// Rysunek zegara
void drawClock(uint64_t time) {
static int32_t p_min = -1;
int32_t sec = time / 1000;
int32_t min = sec / 60;
// Jeśli wartość minut uległa zmianie, należy zaktualizować wyświetlacz cyfrowy na tarczy zegara
if (p_min != min) {
p_min = min;
update7Seg(min / 60, min % 60);
}
// Nadpisz obraz tarczy zegara w buforze rysowania
clockbase.pushSprite(0, 0);
drawDot(sec % 60, 14);
drawDot(min % 60, 15);
drawDot(((min / 60) * 5) % 60, 15);
// Kąt wskazówki godzinowej
float fhour = (float)time / 120000;
// Kąt wskazówki minutowej
float fmin = (float)time / 10000;
// Kąt drugiej ręki
float fsec = (float)time * 6 / 1000;
int px = canvas.getPivotX();
int py = canvas.getPivotY();
// Narysuj cień igły przesunięty w prawy dolny róg
shadow1.pushRotateZoom(px + 2, py + 2, fhour, 1.0, 0.7, transpalette);
shadow1.pushRotateZoom(px + 3, py + 3, fmin, 1.0, 1.0, transpalette);
shadow2.pushRotateZoom(px + 4, py + 4, fsec, 1.0, 1.0, transpalette);
// Narysuj igłę
needle1.pushRotateZoom(fhour, 1.0, 0.7, transpalette);
needle1.pushRotateZoom(fmin, 1.0, 1.0, transpalette);
needle2.pushRotateZoom(fsec, 1.0, 1.0, transpalette);
// Narysuj ukończoną tarczę zegara na wyświetlaczu LCD
canvas.pushRotateZoom(0, zoom, zoom, transpalette);
lcd.display();
}
void loop(void) {
static uint32_t p_milli = 0;
uint32_t milli = lgfx::millis() % 1000;
if (p_milli > milli)
count += 1000 + (milli - p_milli);
else
count += (milli - p_milli);
p_milli = milli;
int32_t tmp = (count % 1000) >> 3;
// 秒針の描画色を変化させる
canvas.setPaletteColor(8, 255 - (tmp >> 1), 255 - (tmp >> 1), 200 - tmp);
//count += 60000;
if ( count > oneday ) {
count -= oneday;
}
drawClock(count);
}