Lopaka Basics 01: Twój pierwszy ekran

Termostaty, smartwatche, drukarki 3D, stacje pogodowe: prawie każdy gadżet ma mały ekran i ktoś musiał go narysować. Lopaka Basics to dziesięcioczęściowa seria dla osób, które nigdy nie miały do czynienia z mikrokontrolerem i nigdy nie otwierały Lopaka.
Każdy odcinek podąża tą samą ścieżką: narysuj to, pobierz kod, zobacz to na ekranie. W tym pierwszym zobaczysz, co dzieje się wewnątrz gadżetu, gdy pokazuje obraz, a następnie zaprojektujesz mały ekran w Lopaka i uruchomisz wygenerowany kod na symulowanym Arduino.
Co zbudujesz: ekran OLED 128×64 z ramką, dużym napisem „HELLO!”, podpisem, linią podziału i małą kropką statusu. Czego potrzebujesz: przeglądarki. Prawdziwa płytka jest opcjonalna; uruchamiamy kod w darmowym symulatorze online.
Co kryje się wewnątrz gadżetu
Malutki komputer, który uruchamia jeden program
Większość małych urządzeń ma wewnątrz płytkę mikrokontrolera: Arduino UNO, ESP32, Raspberry Pi Pico lub coś podobnego. Mikrokontroler to malutki komputer. W przeciwieństwie do twojego laptopa uruchamia jeden program — twój firmware. W szkicu Arduino funkcja loop() tego programu powtarza się tak długo, jak płytka ma zasilanie.
Twój program rysuje wszystko, co pojawia się na ekranie. Płytka nie daje ci pulpitu, okien ani gotowych przycisków na start.

Ekran to siatka pikseli
Wyświetlacz, którego używamy w pierwszych odcinkach, jest jednym z najpopularniejszych w elektronice hobbystycznej: mały monochromatyczny OLED o szerokości 128 pikseli i wysokości 64 pikseli. Popularny moduł to płytka 0,96 cala z kontrolerem SSD1306. Daje to 8192 piksele, a każdy z nich jest włączony albo wyłączony. Bez odcieni szarości wszystko na nim, łącznie z tekstem, wygląda ostro i kanciasto.
Wersja I2C modułu łączy się z płytką czterema przewodami: dwoma do zasilania (GND i VCC) i dwoma do danych (SCL i SDA).
![]()
Każdy piksel ma adres
Aby zapalić konkretny piksel, twój program musi powiedzieć, który. Każdy piksel ma adres złożony z dwóch liczb:
- x liczy od lewej krawędzi,
- y liczy w dół od górnej krawędzi.
Zatem (0, 0) to lewy górny róg. Dwa szczegóły sprawiają problem większości początkujących:
- Y rośnie w dół, odwrotnie niż w matematyce szkolnej. Piksel w
(40, 20)znajduje się 40 pikseli w prawo i 20 pikseli w dół od rogu. - Liczenie zaczyna się od zera. Na wyświetlaczu 128×64 ostatnia kolumna to 127, a ostatni wiersz to 63.
![]()
Biblioteka graficzna zamienia polecenia w piksele
Nie przełączasz 8192 pikseli samodzielnie. Twój program wywołuje bibliotekę graficzną i komunikuje się z nią kształtami: narysuj ramkę tutaj, napisz ten tekst tam. Biblioteka ustala, które piksele to oznacza, i wysyła je do wyświetlacza.
W przypadku małych wyświetlaczy monochromatycznych jedną z najpopularniejszych bibliotek jest U8g2. Dwie linie wystarczą, aby narysować początek naszego ekranu:
u8g2.drawFrame(2, 2, 124, 60); // a frame: x, y, width, height
u8g2.drawStr(28, 32, "HELLO!"); // text at x = 28, y = 32
Stary sposób: zgaduj, kompiluj, wgrywaj, patrz
Każdą liczbę w tym kodzie wpisujesz ręcznie. Zgadujesz, gdzie tekst powinien się zaczynać, kompilujesz szkic, wgrywasz go na płytkę i patrzysz na ekran. Tekst jest trzy piksele za daleko w prawo? Zmień liczbę i przejdź rundę od nowa: kompiluj, wgrywaj, patrz.

Każda runda kosztuje kompilację i wgranie, często dziesiątki sekund, a do zobaczenia czegokolwiek potrzebujesz podłączonej płytki. Nawet prosty ekran taki jak nasz może wymagać dziesiątek rund, zanim wszystko się wyrówna.
Lopaka usuwa tę pętlę. To edytor działający w twojej przeglądarce. Rysujesz ekran, a Lopaka pisze kod dla twojej biblioteki graficznej podczas rysowania.
Lopaka: logowanie, projekty i galeria
Otwórz lopaka.app i zaloguj się za pomocą e-maila, Google lub GitHub. Lopaka przechowuje twoje projekty w chmurze, więc możesz otwierać je z dowolnego komputera.

Krok 1: utwórz nowy projekt
Kliknij + Nowy projekt. Pierwszym i najważniejszym wyborem jest Platforma, czyli biblioteka graficzna, której będzie używał twój firmware. Decyduje to o tym, jaki kod wygeneruje Lopaka, więc wybierz bibliotekę, którą zainstalujesz na płytce.
Dla każdej biblioteki Lopaka pisze kod w sposób, jakiego oczekuje ta biblioteka.
W przypadku małego czarno-białego OLED wybierz U8g2. Jego opis nazywa go „domyślnym wyborem dla monochromatycznych paneli OLED i LCD, takich jak SSD1306, SH1106 i ST7565, gdzie każdy piksel jest po prostu włączony lub wyłączony”, a kod można wyeksportować jako Arduino C++ lub ESP-IDF C.
Następnie wypełnij resztę okna:
- Tytuł: „My First Screen”.
- Rozmiar ekranu: 128×64. Dla U8g2 jest już wybrany; lista zawiera dziesiątki innych rozmiarów. Przełącznik Niestandardowy pozwala wpisać dowolny rozmiar, a Zaokrąglony jest przeznaczony dla okrągłych wyświetlaczy.
Kliknij Zapisz.

Krok 2: szybkie zwiedzanie edytora
To jest edytor. Wszystko, czego potrzebujesz w tym odcinku, mieści się na jednym ekranie:

- Górny pasek. Nazwa projektu, a po niej dwie plakietki: biblioteka (
u8g2) i rozmiar ekranu (128×64). Ikona koła zębatego obok nich otwiera ustawienia projektu. Po prawej są Kopia i Udostępnij. - Narzędzia rysowania nad obszarem rysowania: cofnij i ponów, narzędzie zaznaczania, a następnie pędzel, tekst (
Aa), prostokąt, elipsa (ikona koła), linia, trójkąt i wielokąt. - Obszar rysowania pośrodku to twój ekran 128×64 z linijkami wzdłuż krawędzi. Gdy zaznaczysz kształt, linijki zaznaczają jego dokładne krawędzie w pikselach.
- Warstwy po lewej. Każdy narysowany kształt staje się tutaj warstwą, pogrupowaną pod swoim ekranem. Dodaj ekran tworzy kolejny ekran w tym samym projekcie; karty Obrazy i Animacje poniżej przechowują twoje bitmapy i animacje.
- Właściwości po prawej, nazywane też inspektorem: dokładna pozycja, rozmiar i styl tego, co jest zaznaczone.
- Wygenerowany kod na dole. Aktualizuje się na żywo podczas rysowania. Obok niego znajduje się przełącznik Składnia (Arduino C++ lub ESP-IDF C dla U8g2) oraz przełączniki kontrolujące, co trafia do kodu.
Krok 3: narysuj ekran
Ramka i twoja pierwsza linia kodu
Wybierz narzędzie prostokąt i przeciągnij po obszarze rysowania. Na ekranie pojawia się ramka, a w tym samym momencie w kodzie pojawia się nowa linia:
u8g2.drawFrame(2, 2, 124, 60);Te cztery liczby to x, y, szerokość i wysokość: te same adresy pikseli z początku artykułu. Pomiń precyzyjne przeciąganie i wpisz dokładne wartości do inspektora: X 2, Y 2, W 124, H 60. Linijki podążają za twoimi liczbami i zaznaczają krawędzie kształtu na 2 i 126 w poziomie oraz 2 i 62 w pionie. Linijki liczą linie między pikselami, więc prawa krawędź na 126 oznacza, że ostatnia zapalona kolumna to 125.

Ramka zaczynająca się na x = 2 i szeroka na 124 piksele obejmuje kolumny od 2 do 125. Pozostawia to dwie puste kolumny po każdej stronie ekranu o szerokości 128 pikseli oraz ten sam dwupikselowy margines u góry i u dołu. Ręcznie wykonywałbyś te obliczenia w głowie przed każdą kompilacją.
Pozostałe właściwości prostokąta też zmieniają kod:
- R zaokrągla rogi, a wywołanie staje się
drawRFrame. - Wypełniony zamienia kontur w solidny blok,
drawBox. - Odwrócony (XOR) odwraca piksele pod kształtem zamiast je włączać, co przydaje się przy podświetlonych pozycjach menu.
Tekst i czcionki
Wybierz narzędzie tekst (Aa) i kliknij obszar rysowania. Pojawia się nowa warstwa ze słowem Text; zaznacz ją, jeśli nie jest jeszcze zaznaczona, i wpisz HELLO! w pole tekstowe w inspektorze. Pierwszy tekst w projekcie używa domyślnej czcionki 4x6, która jest malutka: każdy znak ma cztery piksele szerokości. Każdy tekst dodany później zaczyna się od ostatniej wybranej czcionki.
Otwórz listę Czcionka. Lopaka oferuje 42 wbudowane czcionki U8g2, od mikrotekstu 4×6 po duże kroje wyświetlaczowe. Pierwsza pozycja na liście, Importuj czcionkę..., dodaje własną. Wybierz profont22.

W kodzie przed tekstem pojawia się linia setFont, aby biblioteka wiedziała, którą czcionką go narysować:
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.drawStr(56, 35, "HELLO!");Wyrównaj i obserwuj, jak liczby się poruszają
Teraz umieść tekst przyciskami wyrównania u góry inspektora: dwa przyciski środkowe umieszczają tekst pośrodku ekranu w poziomie i w pionie. Albo przeciągnij go w dowolne miejsce.
Obserwuj kod, gdy to robisz. Każdy ruch aktualizuje liczby naraz, a wyśrodkowanie ustawia X na 28. Widzisz wynik podczas zmiany, bez kompilacji i wgrywania.

Spójrz na linijki na tym zrzucie: zaznaczają ramkę wokół liter od 25 do 39, a kod mówi drawStr(28, 39, ...). W U8g2 współrzędna y tekstu to jego linia bazowa, linia, na której stoją litery, a litery wypełniają wiersze powyżej niej. Tekst umieszczony ręcznie na y = 0 ląduje nad ekranem — klasyczny pierwszy błąd. Inspektor Lopaka używa tej samej linii bazowej dla Y, więc liczba z pola trafia wprost do kodu, a obszar rysowania pokazuje, gdzie wylądują litery.
W gotowym projekcie przesuwamy „HELLO!” nieco wyżej, na y = 32, aby zrobić miejsce na linię i podpis poniżej.
Podpis, linia i kropka statusu
Ukończ ekran trzema kolejnymi warstwami:
- Podpis. Kolejna warstwa tekstowa,
my first screen. Zaczyna się od profont22, ostatniej użytej czcionki, więc przełącz ją na mniejszą6x10, wyśrodkuj w poziomie i ustaw Y na 52:drawStr(19, 52, "my first screen"). Ponieważ ten tekst używa innej czcionki, Lopaka dodaje kolejnesetFontprzed nim. Jeśli dwa teksty z rzędu używają tej samej czcionki, wywołanie się nie powtarza. - Linia pod „HELLO!”:
drawLine(24, 39, 103, 39). W przypadku linii cztery liczby to punkt początkowy i końcowy. - Mała kropka w prawym górnym rogu, utworzona narzędziem elipsy, z włączoną opcją Wypełniony.
W inspektorze kropka ma X 117, Y 10, RX 2 i RY 2: lewy górny róg ramki wokół niej oraz jej dwa promienie. Funkcja elipsy U8g2 przyjmuje środek, więc kod mówi drawFilledEllipse(119, 12, 2, 2). Każda biblioteka ma takie konwencje. Lopaka konwertuje je za ciebie, a ty pracujesz z tym, co widzisz na obszarze rysowania.
Spójrz teraz na panel warstw: rect 1, string 2, string 3, line 4, ellipse 5. Każdy kształt jest warstwą, a każda warstwa jest linią kodu, z nazwą jako komentarzem nad nią.
Krok 4: pobierz kod
Gdy ekran wygląda dobrze, kliknij Kopiuj nad kodem. Otrzymasz gotową funkcję nazwaną od ekranu:
// [BEGIN lopaka generated]
void drawScreen_1(void) {
u8g2.setFontMode(1);
u8g2.setBitmapMode(1);
// rect 1
u8g2.drawFrame(2, 2, 124, 60);
// string 2
u8g2.setFont(u8g2_font_profont22_tr);
u8g2.drawStr(28, 32, "HELLO!");
// string 3
u8g2.setFont(u8g2_font_6x10_tr);
u8g2.drawStr(19, 52, "my first screen");
// line 4
u8g2.drawLine(24, 39, 103, 39);
// ellipse 5
u8g2.drawFilledEllipse(119, 12, 2, 2);
}
// [END lopaka generated]
Cztery szczegóły w tym kodzie:
- Czcionki są już ustawione. Każdy tekst otrzymuje czcionkę wybraną w edytorze, z właściwą nazwą czcionki U8g2. W
u8g2_font_profont22_trliteratoznacza przezroczyste tło, aroznacza zredukowany zestaw znaków: podstawowe litery łacińskie, cyfry i znaki interpunkcyjne, co utrzymuje czcionkę małą w pamięci. setFontMode(1)isetBitmapMode(1)sprawiają, że tekst i obrazy są przezroczyste, więc litera narysowana nad linią nie wymazuje jej swoim tłem.- Znaczniki
BEGINiENDpokazują, która część twojego szkicu pochodzi z Lopaka. Gdy zmienisz projekt, zamień wszystko między nimi. - Przełączniki obok kodu kontrolują, co do niego trafia: opakowanie rysowania w funkcję, deklarowanie obrazów jako
PROGMEM, dołączanie czcionek i danych obrazów, komentarze z nazwami warstw i więcej. Ustawienia domyślne są odpowiednie dla tego odcinka.
Krok 5: uruchom to
Dokąd trafia funkcja: bufor ramki
Twój szkic musi wywołać skopiowaną funkcję. Minimalny szkic Arduino dla naszego wyświetlacza:
#include <U8g2lib.h>
#include <Wire.h>
// 128x64 SSD1306 OLED on I2C, full frame buffer
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
// Paste the Lopaka code here
void setup() {
u8g2.begin();
}
void loop() {
u8g2.clearBuffer();
drawScreen_1();
u8g2.sendBuffer();
}Długa nazwa obiektu wyświetlacza czytana jest od lewej do prawej: kontroler SSD1306, panel 128X64, moduł generyczny (NONAME), pełny bufor ramki F, podłączony przez sprzętowe I2C. U8G2_R0 oznacza brak rotacji, a U8X8_PIN_NONE mówi, że moduł nie ma podłączonego pinu reset.
W loop() wywołaj swoją funkcję między clearBuffer() a sendBuffer():
clearBuffer()czyści obraz.drawScreen_1()rysuje wszystko w pamięci, a nie na wyświetlaczu.sendBuffer()wysyła gotowy obraz do wyświetlacza za jednym razem.
Ten obraz w pamięci nazywany jest buforem ramki. Wyświetlacz otrzymuje tylko kompletne ramki, więc nigdy nie widzisz ekranu narysowanego w połowie. Ceną jest pamięć: 128 × 64 piksele po jednym bicie to 1024 bajty, połowa 2 KB RAM Arduino UNO. Cały nasz szkic zajmuje 12 218 bajtów flash (37%) i 1578 bajtów RAM (77%) na UNO, a większość tego RAM to bufor ramki. W tak małym szkicu to w porządku. Na ESP32 ten sam szkic używa 7% RAM. Wrócimy do pamięci i do rysowania przy mniejszym jej użyciu później w serii.

Nie masz jeszcze płytki? Uruchom to w symulatorze
Możesz zobaczyć swój ekran w działaniu bez żadnego sprzętu. Wokwi to darmowy symulator online, który kompiluje i uruchamia prawdziwy kod Arduino:
- Utwórz nowy projekt Arduino UNO.
- Dodaj wyświetlacz OLED SSD1306 i podłącz cztery przewody: GND do GND, VCC do 5V, SCL do A5 i SDA do A4.
- Dodaj bibliotekę U8g2 w karcie Library Manager.
- Wklej powyższy szkic do
sketch.ino, z kodem Lopaka w jego miejscu. - Naciśnij Play.
Wyświetlacz pokazuje to, co narysowałeś, działając jako prawdziwy kod Arduino. Wkleiliśmy kod z Lopaka bez zmiany ani jednego znaku, a symulowany wyświetlacz odpowiadał obszarowi rysowania Lopaka piksel w piksel.

Na prawdziwej płytce
Ponieważ jest to prawdziwy kod, ten sam szkic działa też na prawdziwej płytce. Podłącz wyświetlacz w ten sam sposób, zainstaluj U8g2 z Library Manager w Arduino IDE i wgraj. Dwie rzeczy do sprawdzenia na prawdziwym sprzęcie:
- Kontroler. Większość modułów 0,96 cala używa SSD1306. Wiele modułów 1,3 cala wygląda tak samo, ale używa SH1106; w ich przypadku zmień
SSD1306naSH1106w konstruktorze:U8G2_SH1106_128X64_NONAME_F_HW_I2C. - Zasilanie. Większość tych modułów akceptuje zarówno 3,3 V, jak i 5 V, ale niektóre gole płytki są tylko na 3,3 V. Sprawdź opis swojego modułu.
Późniejszy odcinek serii przeprowadza ten krok krok po kroku, łącznie z tym, co sprawdzić, gdy ekran pozostaje czarny.
Podsumowanie
Przepływ pracy pozostaje taki sam dla każdego tworzonego ekranu:
- Wybierz swoją bibliotekę: platforma wybrana przy tworzeniu projektu decyduje, jaki kod otrzymasz. W przypadku monochromatycznego OLED zacznij od U8g2.
- Narysuj swój ekran: każdy kształt jest warstwą, każda warstwa jest linią kodu, a inspektor pokazuje dokładne liczby.
- Skopiuj kod: wywołaj funkcję między
clearBuffer()asendBuffer()i uruchom ją w symulatorze lub na prawdziwej płytce.
Następny odcinek: Tekst, czcionki i ikony. Budujemy mini stację pogodową i dowiadujemy się, dlaczego każda czcionka kosztuje pamięć. Przeczytaj odcinek 2 lub obejrzyj go na YouTube.
Gotowy, aby spróbować? Otwórz Lopaka i narysuj swój pierwszy ekran.