Taki zegarek ... część 2

Taka nowość z uC RP2040 Dual CORE ARM Cortex M0+ pędzącym 133MHz
ODPOWIEDZ
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Taki zegarek ... część 2

Post autor: SunRiver »

Ewolucja Projektu: Od 8x16 do Cyfrowego Płótna 8x32 (matryca elastyczna)

Zgodnie z zasadą, że "zegarków w domu nigdy za wiele", projekt przeszedł gruntowną modernizację. Zastąpienie dwóch małych,
ale jakże wielkich matryc 8x8 zlepionych z taśmy nowoczesnym panelem 8x32 WS2812B otworzyło zupełnie nowe możliwości ekspresji i funkcjonalności.

Co zmienia rozmiar 8x32?

Szlachetna Typografia i Czytelność:
Dzięki szerokości 32 pikseli nie musimy już wybierać między godziną a sekundami. Możemy stosować autorskie czcionki (np. 4x7 lub 3x5),
które zachowują idealne proporcje i światło między znakami. Obraz jest spójny, a cyfry "oddychają", co znacząco poprawia komfort odczytu
nawet z dużej odległości.

Dynamika i Animacja (PIO Power):
Wykorzystanie maszyny stanowej PIO w Raspberry Pi Pico pozwala na odświeżanie matrycy z częstotliwością, która czyni animacje płynnymi (tzw. butter smooth). Pionowe przesuwanie cyfr podczas zmiany czasu sprawia, że zegar ożywa, a każda upływająca minuta jest subtelnym spektaklem.

Wielofunkcyjność Interfejsu (6-Button UI): Rozbudowa sterowania do 6 przycisków pozwoliła na stworzenie intuicyjnego zarządzania funkcjami:

Zarządzania czasem (ustawianie godziny/minuty)
Personalizacja estetyczna (13 schematów kolorystycznych, w tym tryb Rainbow)
Adaptacji do oświetlenia (8 poziomów jasności)
Tryb Nocny - subtelne czerwone światło, które nie razi w oczy na najniższym poziomie jasności
Wyboru Trybu Wyświetlania:
- pełny format HH:MM:SS,
- eleganckie, centrowane HH:MM,
- nowoczesna hybryda HH:MM z małymi sekundami.

Sercem pomiaru czasu pozostaje układ RTC DS1307, który w połączeniu z logiką zapobiegającą migotaniu,
czyni z projektu niezawodne urządzenie codziennego użytku.

Podsumowanie Techniczne

Ten projekt to nie tylko prosty miernik czasu. To połączenie precyzyjnego kodu z estetyką pixel-art.
Dzięki elastycznemu mapowaniu matrycy (logika zygzaka) i zaawansowanemu skalowaniu jasności,
zegar idealnie odnajdzie się zarówno w warsztacie elektronika, jak i w nowoczesnym salonie.

Choć zamysł w większości pozostał taki sam jak w poprzedniej wersji, tym razem jest bardziej spójny. Dzięki taniej i wygodnej matrycy 8x32 o większej gęstości diod, efekt jest bardziej elegancki i stylowy. Już teraz, choć jeszcze nie wydrukowałem ramek i dyfuzera,
możesz podziwiać nowe możliwości tego projektu.

Obrazek


Po uporządkowaniu kod prezentuje się następująco:
  1.  
  2. /*******************************************************************************
  3.  * Projekt: Kolejny Zegar LED DS1309 8x32 WS2812B  
  4.  * Autor  : SunRiver / Lothar TeaM
  5.  * Strona : https://forum.lothar-team.pl
  6.  *
  7.  * Plik   : main.c
  8.  * Specyfikacja:
  9.  *   - Mikrokontroler: RP2040 (Raspberry Pi Pico)
  10.  *   - Wyświetlacz: Matryca LED 8x32 WS2812B
  11.  *   - RTC: DS1307 przez I2C
  12.  *   - Sterowanie: 6 przycisków (godziny, minuty, kolor, jasność,
  13.  *      tryb wyświetlania , tryb nocny )
  14.  ******************************************************************************/
  15.  
  16.  
  17. // -- Pliki nagłówkowe i bliblioteki
  18. #include <stdio.h>
  19. #include "pico/stdlib.h"
  20. #include "hardware/pio.h"
  21. #include "hardware/clocks.h"
  22. #include "ws2812.pio.h"
  23. #include "hardware/i2c.h"
  24. #include "hardware/gpio.h"
  25.  
  26. // ---- Parametry zdefiniowane
  27. // -- Matryca
  28. #define LED_PIN          2
  29. #define LED_COUNT       256
  30. #define MATRIX_WIDTH    32
  31. #define MATRIX_HEIGHT    8
  32.  
  33. // -- Przyciski
  34. #define KEY_HOURS       14
  35. #define KEY_MINUTES     15
  36. #define KEY_COLOR       16
  37. #define KEY_BRIGHTNESS  17
  38. #define KEY_MODE        18
  39. #define KEY_NIGHT       19
  40.  
  41. // -- RTC DS1307
  42. #define I2C_SDA_PIN      4
  43. #define I2C_SCL_PIN      5
  44. #define DS1307_ADDR     0x68
  45.  
  46. // -- Pozostałe parametry programu
  47. #define ANIM_STEPS       7
  48. #define ANIM_INTERVAL_MS 40
  49. #define RGB_COLOR(r, g, b) (((uint32_t)(g) << 16) | ((uint32_t)(r) << 8) | (b))
  50. #define RAINBOW_SCHEME_INDEX 12
  51. // -- KONWERSJE
  52. #define BCD_TO_BIN(val) ( ( (val) / 16 * 10 ) + ( (val) % 16 ) )
  53. #define BIN_TO_BCD(val) ( ( (val) / 10 * 16 ) + ( (val) % 10 ) )
  54.  
  55. uint32_t led_buffer[LED_COUNT];
  56.  
  57. // Zmienne pomocnicze trybu nocnego
  58. bool is_night_mode = false;
  59. uint8_t saved_brightness = 4;
  60. uint8_t saved_color = 0;
  61.  
  62. // Struktury
  63. typedef struct {
  64.     uint8_t second, minute, hour;
  65. } rtc_time_t;
  66.  
  67. rtc_time_t current_rtc_time;
  68.  
  69. typedef struct {
  70.     uint32_t digit_color, colon_color;
  71. } color_scheme_t;
  72.  
  73. const color_scheme_t color_schemes[] = {
  74.     { RGB_COLOR(0, 40, 0), RGB_COLOR(40, 0, 0) },   // 0
  75.     { RGB_COLOR(0, 0, 40), RGB_COLOR(0, 40, 0) },   // 1
  76.     { RGB_COLOR(40, 0, 40), RGB_COLOR(0, 40, 40) }, // 2
  77.     { RGB_COLOR(40, 40, 0), RGB_COLOR(40, 0, 0) },  // 3
  78.     { RGB_COLOR(40, 40, 40), RGB_COLOR(40, 0, 0) }, // 4
  79.     { RGB_COLOR(40, 10, 0), RGB_COLOR(0, 40, 0) },  // 5
  80.     { RGB_COLOR(40, 0, 15), RGB_COLOR(0, 0, 40) },  // 6
  81.     { RGB_COLOR(0, 40, 40), RGB_COLOR(40, 40, 40) },// 7
  82.     { RGB_COLOR(0, 10, 40), RGB_COLOR(40, 40, 0) }, // 8
  83.     { RGB_COLOR(15, 40, 0), RGB_COLOR(40, 40, 40) },// 9
  84.     { RGB_COLOR(40, 20, 0), RGB_COLOR(0, 0, 40) },  // 10
  85.     { RGB_COLOR(40, 0, 0), RGB_COLOR(0, 40, 0) },   // 11
  86.     { RGB_COLOR(40, 40, 40), RGB_COLOR(40, 40, 40) } // 12
  87. };
  88.  
  89. uint8_t current_color_index = 0;
  90. uint8_t current_brightness_index = 4;
  91. uint8_t rainbow_hue = 0;
  92. const uint8_t BRIGHTNESS_LEVELS[] = { 5, 10, 20, 30, 40, 80, 150, 255 };
  93.  
  94. // Czcionka 4x7 dla matrycy 8x32
  95. const uint8_t font_4x7[10][7] = {
  96.     { 0b0110, 0b1001, 0b1001, 0b1001, 0b1001, 0b1001, 0b0110 }, // 0
  97.     { 0b0100, 0b1100, 0b0100, 0b0100, 0b0100, 0b0100, 0b1110 }, // 1
  98.     { 0b1110, 0b0001, 0b0001, 0b0110, 0b1000, 0b1000, 0b1111 }, // 2
  99.     { 0b1110, 0b0001, 0b0001, 0b0110, 0b0001, 0b0001, 0b1110 }, // 3
  100.     { 0b1001, 0b1001, 0b1001, 0b1111, 0b0001, 0b0001, 0b0001 }, // 4
  101.     { 0b1111, 0b1000, 0b1000, 0b1110, 0b0001, 0b0001, 0b1110 }, // 5
  102.     { 0b0110, 0b1000, 0b1000, 0b1110, 0b1001, 0b1001, 0b0110 }, // 6
  103.     { 0b1111, 0b0001, 0b0001, 0b0010, 0b0100, 0b0100, 0b0100 }, // 7
  104.     { 0b0110, 0b1001, 0b1001, 0b0110, 0b1001, 0b1001, 0b0110 }, // 8
  105.     { 0b0110, 0b1001, 0b1001, 0b0111, 0b0001, 0b0001, 0b0110 }  // 9
  106. };
  107.  
  108. // Mała czcionka 3x5 dla sekund
  109. const uint8_t font_3x5[10][5] = {
  110.     { 0b111, 0b101, 0b101, 0b101, 0b111 },  // 0
  111.     { 0b010, 0b110, 0b010, 0b010, 0b111 },  // 1
  112.     { 0b111, 0b001, 0b111, 0b100, 0b111 },  // 2
  113.     { 0b111, 0b001, 0b011, 0b001, 0b111 },  // 3
  114.     { 0b101, 0b101, 0b111, 0b001, 0b001 },  // 4
  115.     { 0b111, 0b100, 0b111, 0b001, 0b111 },  // 5
  116.     { 0b111, 0b100, 0b111, 0b101, 0b111 },  // 6
  117.     { 0b111, 0b001, 0b001, 0b001, 0b001 },  // 7
  118.     { 0b111, 0b101, 0b111, 0b101, 0b111 },  // 8
  119.     { 0b111, 0b101, 0b111, 0b001, 0b111 }   // 9
  120. };
  121.  
  122. uint8_t current_display_mode = 0;   // 0: HH:MM:SS, 1: Centered HH:MM, 2: HH:MM ss
  123.  
  124. // Mapowanie matrycy 8x32 - zigzak - kolumnami parzyste w dół, nieparzyste w góre
  125. uint16_t get_led_index(uint8_t x, uint8_t y) {
  126.     if (x >= MATRIX_WIDTH || y >= MATRIX_HEIGHT) return 0;
  127.     if (x % 2 == 0) {
  128.         return (x * 8) + y;
  129.     }
  130.     else {
  131.         return (x * 8) + (7 - y);
  132.     }
  133. }
  134.  
  135. // Rysowanie pikseli
  136. void draw_pixel(uint8_t x, uint8_t y, uint32_t color) {
  137.     if (x < MATRIX_WIDTH && y < MATRIX_HEIGHT)
  138.         led_buffer[get_led_index(x, y)] = color;
  139. }
  140.  
  141. void draw_digit_offset(uint8_t digit, int8_t x, int8_t y, int8_t y_offset, uint32_t color) {
  142.     for (uint8_t row = 0; row < 7; row++)
  143.         for (uint8_t col = 0; col < 4; col++)
  144.             if (font_4x7[digit][row] & (1 << (3 - col)))
  145.                 draw_pixel(x + col, y + row + y_offset, color);
  146. }
  147.  
  148. void draw_small_digit(uint8_t digit, int8_t x, int8_t y, uint32_t color) {
  149.     for (uint8_t row = 0; row < 5; row++)
  150.         for (uint8_t col = 0; col < 3; col++)
  151.             if (font_3x5[digit][row] & (1 << (2 - col)))
  152.                 draw_pixel(x + col, y + row, color);
  153. }
  154.  
  155. // --- FUNKCJE POMOCNICZE ---
  156. uint32_t hsv_to_rgb(uint8_t h) {
  157.     uint8_t r = 0, g = 0, b = 0;
  158.     const uint8_t max_val = 40;
  159.     uint8_t section = h / 43;
  160.     uint8_t remainder = (h % 43) * 6;
  161.     uint8_t q = (max_val * (255 - remainder)) >> 8;
  162.     uint8_t t = (max_val * remainder) >> 8;
  163.     switch (section) {
  164.     case 0: r = max_val; g = t; b = 0; break;
  165.     case 1: r = q; g = max_val; b = 0; break;
  166.     case 2: r = 0; g = max_val; b = t; break;
  167.     case 3: r = 0; g = q; b = max_val; break;
  168.     case 4: r = t; g = 0; b = max_val; break;
  169.     default: r = max_val; g = 0; b = q; break;
  170.     }
  171.     return RGB_COLOR(r, g, b);
  172. }
  173.  
  174. uint32_t scale_color_by_brightness(uint32_t color) {
  175.     uint8_t target_max = BRIGHTNESS_LEVELS[current_brightness_index];
  176.     uint8_t g = (color >> 16) & 0xFF, r = (color >> 8) & 0xFF, b = color & 0xFF;
  177.     return RGB_COLOR((uint8_t)((r * target_max) / 40), (uint8_t)((g * target_max) / 40), (uint8_t)((b * target_max) / 40));
  178. }
  179.  
  180. // --- RTC DS1307 ---
  181. void ds1307_read_time(void) {
  182.     uint8_t time_buffer[7];
  183.     i2c_write_blocking(i2c0, DS1307_ADDR, (const uint8_t[]){ 0x00 }, 1, true);
  184.     i2c_read_blocking(i2c0, DS1307_ADDR, time_buffer, 7, false);
  185.     current_rtc_time.second = BCD_TO_BIN(time_buffer[0] & 0x7F);
  186.     current_rtc_time.minute = BCD_TO_BIN(time_buffer[1] & 0x7F);
  187.     current_rtc_time.hour = BCD_TO_BIN(time_buffer[2] & 0x3F);
  188. }
  189.  
  190. void ds1307_set_time(uint8_t h, uint8_t m, uint8_t s) {
  191.     uint8_t data[4] = { 0x00, BIN_TO_BCD(s) & 0x7F, BIN_TO_BCD(m), BIN_TO_BCD(h) & 0x3F };
  192.     i2c_write_blocking(i2c0, DS1307_ADDR, data, 4, false);
  193. }
  194.  
  195. // --- ANIMACJA ---
  196. typedef struct { uint8_t current, next, step; bool animating; } digit_anim_t;
  197. digit_anim_t digits[6];
  198.  
  199. void animation_tick(void) {
  200.     for (int i = 0; i < 6; i++)
  201.         if (digits[i].animating) {
  202.             digits[i].step++;
  203.             if (digits[i].step >= ANIM_STEPS) { digits[i].current = digits[i].next; digits[i].animating = false; }
  204.         }
  205. }
  206.  
  207. void start_digit_animation(int index, uint8_t value) {
  208.     if (digits[index].current == value) return;
  209.     digits[index].next = value; digits[index].step = 0; digits[index].animating = true;
  210. }
  211.  
  212. void draw_clock_animated(void) {
  213.     for (int i = 0; i < LED_COUNT; i++) led_buffer[i] = 0;
  214.    
  215.     uint32_t color = scale_color_by_brightness(current_color_index == RAINBOW_SCHEME_INDEX ? hsv_to_rgb(rainbow_hue) : color_schemes[current_color_index].digit_color);
  216.     uint32_t colon_color = scale_color_by_brightness(current_color_index == RAINBOW_SCHEME_INDEX ? hsv_to_rgb(rainbow_hue + 128) : color_schemes[current_color_index].colon_color);
  217.  
  218.     if (current_display_mode == 0) {
  219.         // --- TRYB 0: HH:MM:SS (Standardowy - Twój obecny) ---
  220.         const uint8_t x_pos[6] = { 0, 5, 11, 16, 22, 27 };
  221.         for (int i = 0; i < 6; i++) {
  222.             if (digits[i].animating) {
  223.                 draw_digit_offset(digits[i].current, x_pos[i], 0, digits[i].step, color);
  224.                 draw_digit_offset(digits[i].next, x_pos[i], 0, digits[i].step - ANIM_STEPS, color);
  225.             }
  226.             else {
  227.                 draw_digit_offset(digits[i].current, x_pos[i], 0, 0, color);
  228.             }
  229.         }
  230.         if (current_rtc_time.second % 2 == 0) {
  231.             draw_pixel(10, 2, colon_color); draw_pixel(10, 5, colon_color);
  232.             draw_pixel(21, 2, colon_color); draw_pixel(21, 5, colon_color);
  233.         }
  234.     }
  235.     else if (current_display_mode == 1) {
  236.         // --- TRYB 1: HH:MM Centrowany (Brak sekund) ---
  237.         const uint8_t x_pos[4] = { 6, 11, 18, 23 }; // Wyśrodkowane na 32 px
  238.         for (int i = 0; i < 4; i++) {
  239.             if (digits[i].animating) {
  240.                 draw_digit_offset(digits[i].current, x_pos[i], 0, digits[i].step, color);
  241.                 draw_digit_offset(digits[i].next, x_pos[i], 0, digits[i].step - ANIM_STEPS, color);
  242.             }
  243.             else {
  244.                 draw_digit_offset(digits[i].current, x_pos[i], 0, 0, color);
  245.             }
  246.         }
  247.         if (current_rtc_time.second % 2 == 0) {
  248.             draw_pixel(16, 2, colon_color); draw_pixel(16, 5, colon_color);
  249.         }
  250.     }
  251.     else if (current_display_mode == 2) {
  252.         // --- TRYB 2: HH:MM i małe ss ---
  253.         const uint8_t x_pos[4] = { 2, 7, 13, 18 }; // Godziny i minuty po lewej
  254.         for (int i = 0; i < 4; i++) {
  255.             if (digits[i].animating) {
  256.                 draw_digit_offset(digits[i].current, x_pos[i], 0, digits[i].step, color);
  257.                 draw_digit_offset(digits[i].next, x_pos[i], 0, digits[i].step - ANIM_STEPS, color);
  258.             }
  259.             else {
  260.                 draw_digit_offset(digits[i].current, x_pos[i], 0, 0, color);
  261.             }
  262.         }
  263.         // Małe sekundy (bez animacji dla prostoty, na dole po prawej)
  264.         draw_small_digit(current_rtc_time.second / 10, 25, 2, color);
  265.         draw_small_digit(current_rtc_time.second % 10, 29, 2, color);
  266.  
  267.         if (current_rtc_time.second % 2 == 0) {
  268.             draw_pixel(12, 2, colon_color); draw_pixel(12, 5, colon_color);
  269.         }
  270.     }
  271. }
  272.  
  273. // --- PIO dla WS2812B ----------------------------
  274. void ws2812_show(PIO pio, uint sm) {
  275.     for (int i = 0; i < LED_COUNT; i++) pio_sm_put_blocking(pio, sm, led_buffer[i] << 8u);
  276. }
  277.  
  278. static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
  279.     pio_sm_config c = ws2812_program_get_default_config(offset);
  280.     sm_config_set_sideset_pins(&c, pin);
  281.     sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
  282.     sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
  283.     int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
  284.     float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
  285.     sm_config_set_clkdiv(&c, div);
  286.     pio_gpio_init(pio, pin);
  287.     pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
  288.     pio_sm_init(pio, sm, offset, &c);
  289.     pio_sm_set_enabled(pio, sm, true);
  290. }
  291.  
  292. // --- GŁÓWNA FUNKCJA PROGRAMU ----
  293. int main() {
  294.    
  295.     // --- INICJALIZACJA ---
  296.     stdio_init_all();
  297.     PIO pio = pio0; uint sm = 0;
  298.     uint offset = pio_add_program(pio, &ws2812_program);
  299.     ws2812_program_init(pio, sm, offset, LED_PIN, 800000, false);
  300.    
  301.     // --- INICJALIZACJA I2C DLA RTC DS1307 ----
  302.     i2c_init(i2c0, 400 * 1000);
  303.     gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
  304.     gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
  305.     gpio_pull_up(I2C_SDA_PIN); gpio_pull_up(I2C_SCL_PIN);
  306.    
  307.     // --- INICJALIZACJA PRZYCISKÓW ----
  308.     uint8_t keys[] = {
  309.         KEY_HOURS,
  310.         KEY_MINUTES,
  311.         KEY_COLOR,
  312.         KEY_BRIGHTNESS,
  313.         KEY_MODE,
  314.         KEY_NIGHT  
  315.     };
  316.    
  317.     const uint8_t num_keys = sizeof(keys) / sizeof(keys[0]);
  318.  
  319.     for (int i = 0; i < num_keys; i++) {
  320.         gpio_init(keys[i]);
  321.         gpio_set_dir(keys[i], GPIO_IN);
  322.         gpio_pull_up(keys[i]);
  323.     }
  324.    
  325.     // --- POCZĄTKOWY ODCZYT CZASU Z RTC ----
  326.     ds1307_read_time();
  327.     uint8_t h = current_rtc_time.hour, m = current_rtc_time.minute, s = current_rtc_time.second;
  328.     uint8_t v[6] = { h / 10, h % 10, m / 10, m % 10, s / 10, s % 10 };
  329.     for (int i = 0; i < 6; i++) { digits[i].current = v[i]; digits[i].animating = false; }
  330.    
  331.     // --- ZMIENNE POMOCNICZE ----
  332.     uint32_t last_rtc = 0, last_btn = 0;
  333.     const uint16_t TICK_MS = 20;
  334.     uint8_t anim_loop_counter = 0;
  335.    
  336.     // --- GŁÓWNA PĘTLA PROGRAMU ----
  337.     while (true) {
  338.         sleep_ms(TICK_MS);
  339.         anim_loop_counter++;
  340.         rainbow_hue++;
  341.         uint32_t now_ms = time_us_64() / 1000;
  342.  
  343.         // --- ODCZYT CZASU Z RTC CO 200ms ----
  344.         if (now_ms - last_rtc >= 200) {
  345.             last_rtc = now_ms;
  346.             ds1307_read_time();
  347.             uint8_t target[6] = {
  348.                  current_rtc_time.hour / 10,
  349.                 current_rtc_time.hour % 10,
  350.                 current_rtc_time.minute / 10,
  351.                 current_rtc_time.minute % 10,
  352.                 current_rtc_time.second / 10,
  353.                 current_rtc_time.second % 10
  354.              };
  355.            
  356.             bool any_anim = false;
  357.             for (int i = 0; i < 6; i++) if (digits[i].animating) any_anim = true;
  358.            
  359.             if (!any_anim) {
  360.                 for (int i = 0; i < 6; i++) start_digit_animation(i, target[i]);
  361.             }
  362.         }
  363.  
  364.         // --- OBSŁUGA PRZYCISKÓW ----
  365.         if (now_ms - last_btn > 200) {
  366.             if (!gpio_get(KEY_HOURS)) {
  367.                 uint8_t nh = (current_rtc_time.hour + 1) % 24;
  368.                 ds1307_set_time(nh, current_rtc_time.minute, 0);
  369.                 start_digit_animation(0, nh / 10); start_digit_animation(1, nh % 10);
  370.                 last_btn = now_ms; while (!gpio_get(KEY_HOURS)) sleep_ms(10);
  371.             }
  372.             else if (!gpio_get(KEY_MINUTES)) {
  373.                 uint8_t nm = (current_rtc_time.minute + 1) % 60;
  374.                 ds1307_set_time(current_rtc_time.hour, nm, 0);
  375.                 start_digit_animation(2, nm / 10); start_digit_animation(3, nm % 10);
  376.                 last_btn = now_ms; while (!gpio_get(KEY_MINUTES)) sleep_ms(10);
  377.             }
  378.             else if (!gpio_get(KEY_COLOR)) {
  379.                 current_color_index = (current_color_index + 1) % 13;
  380.                 last_btn = now_ms; while (!gpio_get(KEY_COLOR)) sleep_ms(10);
  381.             }
  382.             else if (!gpio_get(KEY_BRIGHTNESS)) {
  383.                 current_brightness_index = (current_brightness_index + 1) % 8;
  384.                 is_night_mode = false; // Każda ręczna zmiana wyłącza tryb nocny
  385.                 last_btn = now_ms; while (!gpio_get(KEY_BRIGHTNESS)) sleep_ms(10);
  386.             }
  387.             else if (!gpio_get(KEY_MODE)) {
  388.                 current_display_mode = (current_display_mode + 1) % 3; // Mamy 3 tryby
  389.                 last_btn = now_ms;
  390.                 while (!gpio_get(KEY_MODE)) sleep_ms(10); // Debouncing
  391.             }
  392.             else if (!gpio_get(KEY_NIGHT)) {
  393.                 if (!is_night_mode) {
  394.                     // WŁĄCZAMY TRYB NOCNY
  395.                     saved_brightness = current_brightness_index;
  396.                     saved_color = current_color_index;
  397.        
  398.                     current_brightness_index = 0; // Najniższy poziom z BRIGHTNESS_LEVELS (5)
  399.                     current_color_index = 11;     // Czerwony (według tabeli color_schemes)
  400.                     is_night_mode = true;
  401.                 } else {
  402.                     // WYŁĄCZAMY TRYB NOCNY - przywracamy stare ustawienia
  403.                     current_brightness_index = saved_brightness;
  404.                     current_color_index = saved_color;
  405.                     is_night_mode = false;
  406.                 }
  407.    
  408.                 last_btn = now_ms;
  409.                 while (!gpio_get(KEY_NIGHT)) sleep_ms(10);  // Debouncing
  410.             }
  411.         }
  412.        
  413.         // --- RYSOWANIE I ANIMACJA ---
  414.         if (anim_loop_counter >= 2) { anim_loop_counter = 0; animation_tick(); }
  415.         draw_clock_animated();
  416.         ws2812_show(pio, sm);
  417.     }
  418. }
  419.  
  420.  
Awatar użytkownika
gufim
Użytkownik
Posty: 170
Rejestracja: 16 paź 2017, 16:58

Re: Taki zegarek ... część 2

Post autor: gufim »

Śliczny i zegarków nigdy dość :)
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1488
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

Re: Taki zegarek ... część 2

Post autor: SunRiver »

Matrix doczekał się obudowy :

Filmik: https://photos.app.goo.gl/rC5zfhLViMriW6cWA

Zdjęcia części z wydruku 3d

Obrazek

Obrazek

Obrazek

Obrazek
ODPOWIEDZ

Wróć do „Raspberry Pi Pico”