
cena jak na aliexpress .... no cóż 1 056,39zł ---- ale sami zobaczcie filmik prezentujący jest ładna
i matrix robi robotę
https://pl.aliexpress.com/item/1005007771843412.html
Więc pomyślałem że mam 4x 8x8 zielone wiec dlaczego by nie zrobić takiego efektu ??
No więc zrobiłem
Język C, Raspberry SDK, RP2040 ...
Miłej zabawy ...
- #include "pico/stdlib.h"
- #include "hardware/spi.h"
- #include <string.h>
- #define SPI_PORT spi0
- #define PIN_CS 17
- #define PIN_SCK 18
- #define PIN_MOSI 19
- // Font 6x6 - każda litera ma 6 bajtów szerokości (margines 1px góra/dół)
- const uint8_t font6x6[11][6] = {
- { 0x7E, 0x08, 0x08, 0x08, 0x08, 0x7E }, // H (0)
- { 0x7C, 0x12, 0x12, 0x12, 0x12, 0x7C }, // A (1)
- { 0x02, 0x02, 0x7E, 0x02, 0x02, 0x00 }, // T (2)
- { 0x44, 0x4A, 0x4A, 0x4A, 0x4A, 0x30 }, // S (3)
- { 0x3E, 0x40, 0x40, 0x40, 0x40, 0x3E }, // U (4)
- { 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E }, // N (5)
- { 0x7E, 0x4A, 0x4A, 0x4A, 0x4A, 0x42 }, // E (6)
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Spacja (7)
- { 0x7E, 0x04, 0x08, 0x04, 0x08, 0x7E }, // M (8)
- { 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00 }, // I (9)
- { 0x7E, 0x08, 0x14, 0x22, 0x42, 0x00 } // K (10)
- };
- const int char_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 4 };
- #define MAP_SIZE 12
- uint8_t frame_buffer[32];
- void max7219_cmd(uint8_t reg, uint8_t data) {
- uint8_t buf[2] = { reg, data };
- gpio_put(PIN_CS, 0);
- for (int i = 0; i < 4; i++) spi_write_blocking(SPI_PORT, buf, 2);
- gpio_put(PIN_CS, 1);
- }
- void send_row_all(uint8_t row, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4) {
- uint8_t reg = row + 1;
- uint8_t data_to_send[8] = { reg, d1, reg, d2, reg, d3, reg, d4 };
- gpio_put(PIN_CS, 0);
- spi_write_blocking(SPI_PORT, data_to_send, 8);
- gpio_put(PIN_CS, 1);
- }
- void update_display() {
- for (int row = 0; row < 8; row++) {
- uint8_t b[4] = { 0, 0, 0, 0 };
- for (int col = 0; col < 32; col++) {
- if (frame_buffer[col] & (1 << row)) {
- int m_idx = col / 8;
- int l_col = col % 8;
- b[m_idx] |= (1 << (7 - l_col));
- }
- }
- send_row_all(row, b[0], b[1], b[2], b[3]);
- }
- }
- void clear_buffer() { memset(frame_buffer, 0, 32); }
- // Pomocnicza funkcja do umieszczania znaku na konkretnej matrycy (0-3)
- void draw_char(int matrix_idx, int char_idx) {
- int start_col = matrix_idx * 8 + 1; // +1 daje margines z lewej
- for (int i = 0; i < 6; i++) {
- frame_buffer[start_col + i] = font6x6[char_idx][i];
- }
- }
- void init_spi() {
- spi_init(SPI_PORT, 5000 * 1000);
- gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
- gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
- gpio_init(PIN_CS);
- gpio_set_dir(PIN_CS, GPIO_OUT);
- gpio_put(PIN_CS, 1);
- max7219_cmd(0x0c, 1); max7219_cmd(0x09, 0);
- max7219_cmd(0x0b, 7); max7219_cmd(0x0a, 2);
- clear_buffer(); update_display();
- }
- int main() {
- stdio_init_all();
- init_spi();
- while (true) {
- // Zewnętrzne do środka (Wiersz 1 i 8)
- clear_buffer();
- for (int i = 0; i < 16; i++) {
- frame_buffer[i] |= 0x81;
- frame_buffer[31 - i] |= 0x81;
- update_display();
- sleep_ms(30);
- }
- // Do środka (zostawiamy linie na wierszach 4 i 5 - środek)
- sleep_ms(200);
- for (int step = 0; step < 3; step++) {
- // NIE czyścimy całego bufora, tylko nadpisujemy maskę
- uint8_t mask = (1 << (1 + step)) | (1 << (6 - step));
- for (int j = 0; j < 32; j++) frame_buffer[j] = mask;
- update_display();
- sleep_ms(150);
- }
- //Pionowe linie od środka na zewnątrz - WYGASZANIE
- for (int i = 0; i < 16; i++) {
- // NIE dajemy clear_buffer(), żeby poziome linie zostały
- // Rysujemy pionowe linie (0xFF)
- if (15 - i >= 0) frame_buffer[15 - i] = 0xFF;
- if (16 + i < 32) frame_buffer[16 + i] = 0xFF;
- update_display();
- sleep_ms(40);
- // Po wyświetleniu pionowej linii, "gasimy" kolumnę,
- // którą właśnie minęliśmy, żeby sprzątnąć ekran pod napis
- if (15 - i >= 0) frame_buffer[15 - i] = 0x00;
- if (16 + i < 32) frame_buffer[16 + i] = 0x00;
- }
- //Przewijanie napisu HATSUNE MIKU
- uint8_t text_full[120];
- int total_px = 0;
- memset(text_full, 0, 120);
- for (int i = 0; i < MAP_SIZE; i++) {
- for (int c = 0; c < 6; c++) text_full[total_px++] = font6x6[char_map[i]][c];
- total_px += 2; // Odstęp między literami
- }
- for (int shift = 0; shift < total_px + 32; shift++) {
- clear_buffer();
- for (int x = 0; x < 32; x++) {
- int pos = shift + x - 32;
- if (pos >= 0 && pos < total_px) {
- frame_buffer[x] = text_full[pos];
- }
- }
- update_display();
- sleep_ms(45);
- }
- // Efekt Migania napisu MIKU (ostanie 4 znaki z mapy)
- for (int blink = 0; blink < 5; blink++) {
- // Zgaś
- clear_buffer();
- update_display();
- sleep_ms(200);
- // Zapal MIKU
- draw_char(0, 8); // M
- draw_char(1, 9); // I
- draw_char(2, 10); // K
- draw_char(3, 4); // U
- update_display();
- sleep_ms(200);
- }
- //ANIMACJA KOŃCOWA: Odwrotność początku
- for (int i = 0; i < 16; i++) {
- // Rysujemy pionowe linie wpadające do środka
- if (i < 16) frame_buffer[i] = 0xFF;
- if (31 - i >= 16) frame_buffer[31 - i] = 0xFF;
- update_display();
- sleep_ms(30);
- // Zostawiamy tylko poziome linie na środku (wiersze 3 i 4)
- frame_buffer[i] = 0x18;
- frame_buffer[31 - i] = 0x18;
- }
- // Teraz poziome linie rozszerzają się ze środka do brzegów (góra/dół) i znikają
- for (int step = 2; step >= 0; step--) {
- uint8_t mask = (1 << (1 + step)) | (1 << (6 - step));
- for (int j = 0; j < 32; j++) frame_buffer[j] = mask;
- update_display();
- sleep_ms(150);
- }
- // Ostatni błysk brzegów i czysty ekran
- clear_buffer();
- for (int j = 0; j < 32; j++) frame_buffer[j] = 0x81; // Wiersz 0 i 7
- update_display();
- sleep_ms(150);
- clear_buffer();
- update_display();
- sleep_ms(2000);
- }
- }