Lopaka Basics 03: Kolor

Ten sam pomysł co w pierwszych dwóch odcinkach, teraz w pełnym kolorze: pulpit salonu na kolorowym wyświetlaczu, zbudowany w kilka minut.
W tym odcinku dowiesz się, jak kolorowy ekran tworzy kolory, co oznacza RGB565 i dlaczego jeden obrazek na cały ekran nie mieści się na Arduino UNO. Następnie zbudujesz pulpit w Lopaka z zaokrąglonymi kartami, kolorowym tekstem, przyciemnionymi ikonami i jednym małym kolorowym obrazkiem oraz uruchomisz go na ESP32.
Co zbudujesz: kolorowy pulpit 320×240 z tytułem i godziną, trzema zaokrąglonymi kartami temperatury, wilgotności i jakości powietrza oraz wierszem o pogodzie na zewnątrz. Czego potrzebujesz: przeglądarki i symulatora online z odcinka 1. Prawdziwa płytka jest opcjonalna.
Jak działa kolorowy ekran
Jeden piksel to trzy malutkie światła
Na OLED z ostatnich dwóch odcinków piksel jest włączony albo wyłączony. Na kolorowym wyświetlaczu każdy piksel składa się z trzech malutkich świateł: czerwonego, zielonego i niebieskiego. Każde z nich może świecić z dowolną jasnością, a z normalnej odległości twoje oko miesza je w jeden kolor.
Zmieszaj je, a otrzymasz dowolny kolor. Czerwień i zieleń razem dają żółty. Wszystkie trzy na pełnej mocy dają biały. Wszystkie trzy wyłączone to czarny.
![]()
RGB565: kolor w dwóch bajtach
Twój komputer przechowuje kolor w 24 bitach: 8 na czerwień, 8 na zieleń i 8 na niebieski, około 16,7 miliona kolorów. To kolor, który wpisujesz jako #FF8200 na stronie internetowej lub w Lopaka: dwie cyfry szesnastkowe na światło.
Małe chipy i ich wyświetlacze zazwyczaj używają 16 bitów, w formacie zwanym RGB565:
- 5 bitów na czerwień,
- 6 bitów na zieleń,
- 5 bitów na niebieski.
Zieleń otrzymuje dodatkowy bit, ponieważ nasze oczy są na nią najbardziej wrażliwe. Daje to 65 536 kolorów, a każdy piksel zajmuje dokładnie dwa bajty.

Dlaczego obrazek nie mieści się na UNO
Teraz matematyka. Ekran 320×240 ma 320 × 240 = 76 800 pikseli. Przy dwóch bajtach na piksel jeden obrazek na cały ekran zajmuje 153 600 bajtów, około 150 KB.
Arduino UNO ma 32 KB flash na cały program. Jeden obrazek na cały ekran to prawie pięć razy tyle. Dlatego na kolorowych ekranach rysujesz kształtami i tekstem, a obrazki utrzymujesz małe.

Krok 1: nowy kolorowy projekt
Kliknij + Nowy projekt i otwórz listę Platforma. W tym odcinku wybierz AdafruitGFX Color: Adafruit GFX to jedna z najpopularniejszych bibliotek graficznych dla kolorowych wyświetlaczy. Lopaka opisuje ją jako „wspólną warstwę rysowania pod większością sterowników wyświetlaczy Adafruit”: łączysz ją ze sterownikiem dla swojego dokładnego panelu, takiego jak Adafruit_ILI9341, kolory są upakowane jako RGB565, a rysowanie trafia prosto na panel.
Następnie wypełnij resztę okna:
- Tytuł: „Color Weather”.
- Rozmiar ekranu: 320×240.
- Kolor tła:
#0F1B2D, ciemny niebieski.
Kliknij Zapisz.

Lopaka konwertuje każdy kolor na RGB565
Panel kodu ma już jedną linię:
tft.fillScreen(0x8C5);fillScreen maluje cały wyświetlacz jednym kolorem, a 0x8C5 to ciemny niebieski w RGB565. Lopaka wykonuje konwersję dla każdego wybranego koloru. Ręcznie działa to tak: zachowaj górne 5 bitów czerwieni, górne 6 bitów zieleni i górne 5 bitów błękitu i zapisz je jeden po drugim.
| Hex | Górne bity | |
|---|---|---|
| red | 0x0F | 00001 |
| green | 0x1B | 000110 |
| blue | 0x2D | 00101 |
Razem daje to 0000100011000101, czyli 0x08C5. Lopaka zapisuje to bez wiodącego zera.
Krok 2: trzy zaokrąglone karty
Wybierz narzędzie prostokąt i przeciągnij kartę na obszarze rysowania. W inspektorze ustaw R na 12, aby zaokrąglić rogi, włącz Wypełniony i wpisz #FF8200 w Kolor wypełnienia dla pomarańczowego. W kodzie pojawia się jedna linia:
tft.fillRoundRect(10, 56, 96, 140, 12, 0xFC00);Liczby to x, y, szerokość, wysokość, promień rogu i kolor. Kształt to jedna linia kodu, niezależnie od rozmiaru: ta karta obejmuje 96 × 140 pikseli, a linia, która ją rysuje, zajmuje kilka bajtów flash.
Powtórz to dla dwóch pozostałych kart: niebieskiej #2D7FF9 i zielonej #22B573. Wszystkie trzy mają 96 pikseli szerokości i 140 wysokości, na y 56, i zaczynają się na x 10, 112 i 214. Pozostawia to 10-pikselowy margines po obu stronach ekranu i 6 pikseli między kartami: 10 + 3 × 96 + 2 × 6 + 10 = 320.

Krok 3: tekst w kolorze
Tekst działa jak w pierwszych dwóch odcinkach, a teraz może przyjmować dowolny kolor. Wybierz narzędzie tekst (Aa): na obszarze rysowania pojawia się nowa warstwa tekstowa. Wpisz tekst do inspektora, wybierz czcionkę i ustaw Kolor wypełnienia. Nowy tekst zaczyna się od koloru użytego ostatnio, więc za każdym razem sprawdzaj kolor.
Tytuł i godzina
Living roomczcionką FreeSansBold12pt7b, biały#FFFFFF, w lewym górnym rogu.07:45czcionką FreeSans12pt7b, jasny szaroniebieski#9FB3C8, w prawym górnym rogu.
tft.setTextColor(0xFFFF);
tft.setTextWrap(false);
tft.setFont(&FreeSansBold12pt7b);
tft.setCursor(12, 35);
tft.print("Living room");setTextColor ustawia kolor dla każdego tekstu po nim, więc Lopaka pisze go ponownie tylko wtedy, gdy kolor się zmienia. setTextWrap(false) utrzymuje długi tekst w jednej linii zamiast zawijać go na krawędzi ekranu.
W przypadku czcionek FreeSans współrzędna y w setCursor to linia bazowa: ostatni wiersz pikseli liter. W inspektorze tytuł ma Y 36, linię pod tym wierszem (linijki liczą linie między pikselami, jak w odcinku 1), więc kod mówi 35.
Mała etykieta i duża liczba na każdej karcie
Każda karta otrzymuje małą etykietę klasyczną czcionką i dużą liczbę pogrubioną czcionką FreeSans:
- Etykiety
TEMP,HUMIDiAIRużywają Adafruit 5x7, klasycznej czcionki wbudowanej w bibliotekę, z Rozmiarem ustawionym na2. - Liczby
23C,48%iOKużywają FreeSansBold18pt7b.
Wszystkie sześć tekstów jest białych. Umieść każdą etykietę blisko góry jej karty, a każdą liczbę blisko dołu.

Klasyczną czcionkę można powiększyć dwa lub trzy razy: Rozmiar 2 zamienia każdy piksel litery w blok 2×2. Kod etykiety i liczby:
tft.setTextSize(2);
tft.setFont();
tft.setCursor(20, 72);
tft.print("TEMP");
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(20, 179);
tft.print("23C");setFont() bez niczego w nawiasach przełącza z powrotem na klasyczną czcionkę. Klasyczna czcionka liczy y inaczej: setCursor przyjmuje lewy górny róg tekstu, a nie linię bazową. Litery etykiety mają 7 pikseli wysokości, 14 przy rozmiarze 2, więc 86 z inspektora staje się w kodzie 86 − 14 = 72. Lopaka wykonuje tę konwersję za ciebie. Przed liczbą FreeSans resetuje rozmiar do 1, aby duża czcionka nie została podwojona.
Tekst mówi 23C, a nie 23°C: czcionki FreeSans zawierają tylko podstawowe znaki ASCII, a znak stopnia do nich nie należy.
Czcionki kosztują flash tylko wtedy, gdy ich używasz
FreeSans i pozostałe czcionki z listy są dostarczane z biblioteką Adafruit GFX. Każda czcionka to osobny plik i zajmuje flash tylko wtedy, gdy twój ekran jej używa. Lopaka dodaje #include dla każdej czcionki używanej przez projekt, tutaj trzy:
#include "FreeSans12pt7b.h"
#include "FreeSansBold12pt7b.h"
#include "FreeSansBold18pt7b.h"Krok 4: przyciemnione ikony
Otwórz kartę Obrazy, wyszukaj ikonę i kliknij ją, aby dodać ją do ekranu. Dodaj trzy:
- termometr (szukaj „thermo”),
- kroplę (szukaj „drop”),
- liść (szukaj „leaf”).
Wróć do Warstw i umieść każdą ikonę pod etykietą jej karty.
Ikony z biblioteki są jednokolorowe, więc możesz je przyciemnić, aby pasowały do projektu. Zaznacz każdą ikonę i ustaw jej Kolor wypełnienia na ciemny niebieski tła, #0F1B2D. Na jasnych kartach ikony wyglądają teraz jak wycięte.
![]()
W kodzie jednokolorowa ikona staje się drawBitmap:
tft.drawBitmap(20, 104, image_streamline_weather_temperature_thermometer__weather_png_bits, 21, 21, 0x8C5);Argumenty to pozycja, tablica bitów, szerokość i wysokość oraz kolor. Tablica przechowuje jeden bit na piksel, jak na OLED w odcinku 2: termometr ma 21×21 pikseli, 3 bajty na wiersz, łącznie 63 bajty. Kolor jest osobną liczbą w kodzie, więc tę samą ikonę można narysować w dowolnym kolorze bez drugiej kopii.
Krok 5: kolorowy obrazek
Prześlij go jako RGB
Obrazki też mogą być w pełnym kolorze. W karcie Obrazy kliknij Prześlij i wybierz obrazek, tak samo jak w odcinku 2. Tym razem przełącz konwerter z Monochromatyczny na RGB.

Licznik u góry pokazuje koszt. W pełnym rozmiarze 240×240 pikseli ten obrazek zająłby 240 × 240 × 2 = 115 200 bajtów, ponad trzy razy więcej niż cały flash UNO.
Zmniejsz go do 40×40
Ustaw Wymiary na W 40 i H 40. Teraz obrazek zajmuje 40 × 40 × 2 = 3200 bajtów, około trzech kilobajtów. To idealny rozmiar dla kolorowych obrazków: małe, kolorowe szczegóły. Kliknij Importuj.
W kodzie obrazek staje się tablicą 1600 liczb RGB565, po jednej na piksel, oraz jedną linią, która go rysuje:
tft.drawRGBBitmap(12, 197, image_sun_cloud_pixels, 40, 40);W przeciwieństwie do drawBitmap to wywołanie nie przyjmuje koloru: każdy piksel przynosi własny.
Podsumowanie
Umieść obrazek w lewym dolnym rogu i dodaj obok niego jeszcze jedną linię tekstu: Outside: 18C, sunny czcionką Adafruit 5x7, Rozmiar 2, w tym samym szaroniebieskim #9FB3C8 co godzina.
Krok 6: pobierz kod
Jedna karta, trzy dialekty
Każda biblioteka mówi własnym dialektem. Ta sama zaokrąglona karta to drawRBox w U8g2, fillRoundRect w Adafruit GFX i stylizowany obiekt w LVGL. Lopaka pisze ten dla platformy, którą wybrałeś.

Kopiuj i pobierz pliki czcionek
Kliknij Kopiuj nad kodem. Pod przełącznikami obok kodu Lopaka wymienia Czcionki i Obrazy używane przez projekt. Kliknij każdy z trzech plików czcionek, aby go pobrać, i umieść pliki obok swojego szkicu. Obrazek i ikony znajdują się już w skopiowanym kodzie jako tablice, więc nie potrzebujesz plików obrazów.

Jeśli zapomnisz plików czcionek, kompilator zatrzyma się z błędem fatal error: FreeSans12pt7b.h: No such file or directory.
Lopaka generuje ten kod dla pulpitu. Tablica obrazka ma 1600 liczb, więc jest tutaj skrócona; Kopiuj daje ci całość.
// [BEGIN lopaka generated]
#include "FreeSans12pt7b.h"
#include "FreeSansBold12pt7b.h"
#include "FreeSansBold18pt7b.h"
static const unsigned char PROGMEM image_drop_bits[] = {0x10,0x38,0x7c,0x7c,0xfe,0xde,0xde,0xde,0x7c,0x38};
static const unsigned char PROGMEM image_streamline_ecology_leaf_bug__ecology_png_bits[] = {0x00,0x00,0x30,0x00,0x00,0x48,0x00,0x00,0x88,0x00,0x3f,0x08,0x03,0xe0,0x08,0x0c,0x00,0x08,0x10,0xe0,0x08,0x21,0x70,0x88,0x41,0xd1,0x08,0x40,0xe2,0x08,0x80,0x0c,0x08,0x80,0x30,0x10,0x80,0xc0,0x10,0x83,0x00,0x20,0x84,0x00,0x20,0x88,0x00,0x40,0x50,0x00,0x80,0x20,0x03,0x00,0x50,0x0c,0x00,0x8f,0xf0,0x00,0x80,0x00,0x00};
static const unsigned char PROGMEM image_streamline_weather_temperature_thermometer__weather_png_bits[] = {0x03,0x00,0x00,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x87,0x80,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x87,0x80,0x04,0x80,0x00,0x04,0x80,0x00,0x07,0x80,0x00,0x07,0x87,0x80,0x07,0x80,0x00,0x07,0x80,0x00,0x0f,0xc0,0x00,0x1f,0x60,0x00,0x1f,0xa0,0x00,0x1f,0xa0,0x00,0x1f,0xe0,0x00,0x0f,0xc0,0x00,0x07,0x80,0x00};
static const uint16_t PROGMEM image_sun_cloud_pixels[] = {/* 1,600 RGB565 values, shortened here */};
void drawScreen_1(void) {
tft.fillScreen(0x8C5);
// rect 1
tft.fillRoundRect(10, 56, 96, 140, 12, 0xFC00);
// rect 2
tft.fillRoundRect(112, 56, 96, 140, 12, 0x2BFF);
// rect 3
tft.fillRoundRect(214, 56, 96, 140, 12, 0x25AE);
// string 4
tft.setTextColor(0xFFFF);
tft.setTextWrap(false);
tft.setFont(&FreeSansBold12pt7b);
tft.setCursor(12, 35);
tft.print("Living room");
// string 5
tft.setTextColor(0x9D99);
tft.setFont(&FreeSans12pt7b);
tft.setCursor(246, 35);
tft.print("07:45");
// string 6
tft.setTextColor(0xFFFF);
tft.setTextSize(2);
tft.setFont();
tft.setCursor(20, 72);
tft.print("TEMP");
// string 7
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(20, 179);
tft.print("23C");
// string 8
tft.setTextSize(2);
tft.setFont();
tft.setCursor(122, 72);
tft.print("HUMID");
// string 9
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(122, 179);
tft.print("48%");
// string 10
tft.setTextSize(2);
tft.setFont();
tft.setCursor(224, 72);
tft.print("AIR");
// string 11
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(224, 179);
tft.print("OK");
// streamline-weather-temperature-thermometer--weather.png
tft.drawBitmap(20, 104, image_streamline_weather_temperature_thermometer__weather_png_bits, 21, 21, 0x8C5);
// drop
tft.drawBitmap(122, 104, image_drop_bits, 7, 10, 0x8C5);
// streamline-ecology-leaf-bug--ecology.png
tft.drawBitmap(224, 104, image_streamline_ecology_leaf_bug__ecology_png_bits, 21, 21, 0x8C5);
// sun_cloud
tft.drawRGBBitmap(12, 197, image_sun_cloud_pixels, 40, 40);
// string 16
tft.setTextColor(0x9D99);
tft.setTextSize(2);
tft.setFont();
tft.setCursor(62, 211);
tft.print("Outside: 18C, sunny");
}
// [END lopaka generated]Krok 7: uruchom to na ESP32
Szkic
Tym razem uruchamiamy ekran na ESP32, szybszej płytce, popularnej przy kolorowych ekranach; typowa płytka ESP32 ma 4 MB flash. Wyświetlacz to moduł ILI9341 320×240 na SPI.
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// ILI9341 320x240 color display on SPI
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);
// Paste the Lopaka code here
void setup() {
tft.begin();
tft.setRotation(1); // landscape, 320x240
drawScreen_1();
}
void loop() {
}Adafruit_ILI9341 tft(...)tworzy obiekt wyświetlacza i mówi mu, których pinów używa do wyboru chipa, danych/poleceń i resetu. Kod Lopaka nazywa gotft, więc zachowaj tę nazwę.- ILI9341 to panel portretowy, szeroki na 240 i wysoki na 320.
setRotation(1)obraca go do orientacji poziomej, 320×240, rozmiaru, który zaprojektowaliśmy. drawScreen_1()uruchamia się raz, wsetup(). Ekran zachowuje swój obraz, dopóki coś nie narysuje na nim, więcloop()na razie pozostaje puste.
Podłącz to w symulatorze
W symulatorze z odcinka 1 rozpocznij nowy projekt ESP32 i dodaj wyświetlacz ILI9341. Podłącz go:
- VCC i LED (podświetlenie) do 3V3, GND do GND,
- CS do 15, D/C do 2, RST do 4,
- MOSI do 23, SCK do 18, MISO do 19.
Dodaj biblioteki Adafruit ILI9341 i Adafruit GFX Library, wklej szkic z kodem Lopaka w jego miejsce, dodaj trzy pliki czcionek do projektu i naciśnij Play. Pulpit pojawia się na symulowanym wyświetlaczu.

Brak bufora ramki
Pamiętasz bufor ramki z odcinka 1, cały obraz przechowywany w RAM przed wysłaniem na wyświetlacz? Przy 320×240 w kolorze potrzebowałby tych samych 150 KB co obrazek na cały ekran. Kolorowe biblioteki takie jak Adafruit GFX pomijają go i rysują prosto na wyświetlacz: każde fillRoundRect i print wysyła swoje piksele przez SPI od razu.
Dzięki temu zużycie RAM jest malutkie. Po skompilowaniu dla ESP32 szkic używa 23% przestrzeni programu i 7% RAM. Ten sam szkic skompilowany dla Arduino UNO:
Sketch uses 25946 bytes (80%) of program storage space. Maximum is 32256 bytes.
Global variables use 317 bytes (15%) of dynamic memory, leaving 1731 bytes for local variables. Maximum is 2048 bytes.Tylko 15% RAM UNO. Ciasna jest pamięć flash: 80%, a trzy czcionki i obrazek o rozmiarze 3200 bajtów stanowią jej dużą część.
Na prawdziwej płytce
- Napięcie sygnału. ESP32 działa na 3,3 V, podobnie jak ILI9341. Wiele niedrogich modułów ILI9341 nie ma przesuwnika poziomu, więc na płytce 5 V, takiej jak UNO, przed podłączeniem sprawdź opis swojego modułu.
- Kontroler. Niektóre moduły 320×240 używają zamiast tego kontrolera ST7789. W ich przypadku dołącz
Adafruit_ST7789.h, utwórz wyświetlacz jakoAdafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST);i uruchom go za pomocątft.init(240, 320);zamiasttft.begin();. Kod Lopaka pozostaje ten sam.
Krok 8: pomysły z galerii
Potrzebujesz pomysłów? Galeria projektów zawiera tysiące publicznych projektów. Otwórz jeden, naciśnij Kopia, a Lopaka skopiuje go do twoich projektów, gotowego do zmiany.
Podsumowanie
- Trzy światła tworzą każdy kolor: każdy piksel miesza czerwień, zieleń i niebieski.
- RGB565 upycha je w dwóch bajtach: 5 bitów czerwieni, 6 zieleni, 5 błękitu, a Lopaka konwertuje każdy kolor za ciebie.
- Kształty wygrywają z dużymi obrazkami: karta to jedna linia kodu, obrazek na cały ekran to 150 KB, więc utrzymuj obrazki małe.
Następny odcinek: Dane na żywo. Sprawiamy, że te liczby zmieniają się same. Przeczytaj odcinek 4 lub obejrzyj go na YouTube.
Gotowy, aby spróbować? Otwórz Lopaka i zbuduj własny kolorowy pulpit.