Przejdź do treści

Lopaka Basics 05: Z przeglądarki na płytkę ​

Moduł OLED SSD1306 podłączony przewodami GND, VCC, SCL i SDA, pokazujący poranny pulpit z FRI 24 OCT, 07:45 i Sunny 23C

Narysowałeś ekran, wgrałeś kod, a wyświetlacz pozostaje czarny. Wyświetlacz rzadko jest zepsuty. Zazwyczaj chodzi o jedną z pięciu rzeczy, a gdy naprawisz właściwą, ekran się zapala.

W tym odcinku przeniesiesz poranny pulpit z odcinka 2 z przeglądarki na płytkę: zainstalujesz bibliotekę w Arduino IDE, zbudujesz szkic wokół kodu Lopaka i sprawdzisz, ile pamięci używa. Następnie przejdziesz przez pięć powodów, dla których nowy wyświetlacz pozostaje czarny, oraz poprawkę dla każdego z nich.

Co zbudujesz: szkic Arduino pokazujący ekrany Morning i Night z odcinka 2 na OLED SSD1306 128×64 oraz listę kontrolną dla czarnego ekranu. Czego potrzebujesz: przeglądarki, darmowego Arduino IDE i projektu Morning Dashboard z odcinka 2. Arduino UNO i moduł OLED są opcjonalne; uruchamiamy szkic w symulatorze z odcinka 1.

Jak płytka komunikuje się z ekranem ​

Cztery przewody: zasilanie, zegar i dane ​

Mały OLED taki jak nasz potrzebuje czterech przewodów. Dwa to zasilanie: VCC i GND. Pozostałe dwa to magistrala zwana I2C:

  • SCL to zegar. Płytka wysyła na nim stałe tykanie.
  • SDA przenosi dane, jeden bit na tyknięcie.

Magistrala I2C między Arduino UNO a OLED: zegar SCL tyka nad bitami danych SDA, które układają się w adres 0x3C; czujnik na 0x76 i zegar na 0x68 współdzielą te same dwa przewody, a odpowiada tylko wyświetlacz na 0x3C

Każda wiadomość zaczyna się od adresu ​

Inne części mogą współdzielić te same dwa przewody: czujnik temperatury, zegar czasu rzeczywistego i wyświetlacz mogą wisieć na SCL i SDA. Dlatego każda wiadomość zaczyna się od adresu, a odpowiada tylko część o tym adresie.

Większość tych wyświetlaczy odpowiada na 0x3C. Niektóre odpowiadają na 0x3D. Na wielu modułach malutki rezystor z tyłu ustawia adres, obok etykiety takiej jak „IIC ADDRESS SELECT 0x78 / 0x7A”. Te dwie liczby to te same adresy podwojone: 0x3C × 2 = 0x78 i 0x3D × 2 = 0x7A. Miej to na uwadze przy powodzie 2 poniżej.

Tył modułu OLED: etykieta IIC ADDRESS SELECT z rezystorem po stronie 0x78 oraz notatka 0x78 = 0x3C × 2

Większe kolorowe ekrany używają SPI ​

Kolorowe ekrany, takie jak TFT z odcinka 4, zazwyczaj używają zamiast tego SPI: więcej przewodów (MOSI, SCK, CS, DC i RST), znacznie szybciej, oraz przewód wyboru CS zamiast adresu.

Arduino UNO obok kolorowego TFT z odcinka 4, z przewodami SPI MOSI, SCK, CS, DC i RST; więcej przewodów, znacznie szybciej

Krok 1: skopiuj kod z Lopaka ​

Otwórz Morning Dashboard z odcinka 2: OLED 128×64 z biblioteką U8g2 i dwoma ekranami, Morning i Night.

Lopaka pisze funkcje rysowania, po jednej na ekran: drawMorning() i drawNight(). Szkic wokół nich, z konfiguracją wyświetlacza i loop(), piszesz raz w Arduino IDE.

Kliknij Kopiuj na karcie Morning panelu kodu, a następnie przełącz się na kartę Night i skopiuj ją też. Kopiuj pobiera kod otwartej karty. Wygenerowany kod jest taki sam jak w odcinku 2.

Morning Dashboard w Lopaka z ekranami Morning i Night na obszarze rysowania; panel kodu pokazuje kartę Morning z funkcją drawMorning, przyciskiem Kopiuj i włączoną opcją Deklaruj jako PROGMEM

Krok 2: zainstaluj U8g2 ​

W Arduino IDE otwórz Library Manager (ikona książek po lewej), wyszukaj U8g2 i kliknij INSTALL przy bibliotece U8g2 autorstwa oliver. Odcinek używał wersji 2.36.19.

Krok 3: wybierz płytkę ​

Kliknij Select Board u góry, wybierz Select other board and port, wpisz uno i wybierz Arduino UNO. Bez podłączonej płytki IDE nadal może skompilować szkic; port jest potrzebny tylko do wgrania.

Krok 4: zbuduj szkic ​

Nowy szkic ma już setup() i loop(). Wklej kod Lopaka na górze, a następnie dodaj trzy linie: dołącz bibliotekę, utwórz wyświetlacz i uruchom go w setup(). W loop() wyczyść bufor, narysuj i wyślij bufor na ekran:

cpp
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

// Paste the Lopaka code here: drawMorning() and drawNight()

void setup() {
  // put your setup code here, to run once:
  u8g2.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  u8g2.clearBuffer();
  if (millis() / 3000 % 2) drawNight(); else drawMorning();
  u8g2.sendBuffer();
}

setup() uruchamia się raz, gdy płytka startuje. loop() uruchamia się w kółko. Linia if pokazuje każdy ekran przez trzy sekundy, jak w odcinku 2, a kolejność wyczyść, narysuj, wyślij to bufor ramki z odcinka 1.

IDE z gotowym szkicem: koniec drawNight, a następnie setup z u8g2.begin() i loop z clearBuffer, linią millis i sendBuffer

Linia konstruktora opisuje twój wyświetlacz ​

Długa linia pod #include to konstruktor. Opisuje twój wyświetlacz, a każda część jego nazwy coś znaczy:

  • SSD1306: chip kontrolera na module.
  • 128X64: rozmiar w pikselach.
  • NONAME: moduł generyczny, a nie konkretna marka.
  • F: tryb bufora. F to pełny bufor ramki, 1024 bajty RAM. 1 rysuje ekran w stronach i potrzebuje tylko 128 bajtów.
  • HW_I2C: okablowanie, sprzętowe I2C na pinach SDA i SCL płytki.

U8G2_R0 oznacza brak rotacji, a U8X8_PIN_NONE mówi, że żaden pin reset nie jest podłączony. Biblioteka U8g2 ma konstruktor dla każdej kombinacji chipa, rozmiaru, bufora i okablowania. Wybierz niewłaściwy, a ekran pozostanie czarny.

Konstruktor U8G2_SSD1306_128X64_NONAME_F_HW_I2C podzielony na karty: chip kontrolera, rozmiar, F dla pełnego bufora 1 KB oraz sprzętowe I2C; jedna linia to twój wyświetlacz, a zła linia oznacza czarny ekran

Krok 5: zweryfikuj i uruchom ​

Zweryfikuj ​

Kliknij Verify, znacznik wyboru w lewym górnym rogu. IDE kompiluje szkic i raportuje:

Sketch uses 15394 bytes (47%) of program storage space. Maximum is 32256 bytes.
Global variables use 1600 bytes (78%) of dynamic memory, leaving 448 bytes for local variables. Maximum is 2048 bytes.

Szkic zajmuje mniej niż połowę flash i ponad trzy czwarte RAM. Sam bufor ramki to 1024 z 2048 bajtów UNO; wszystko inne zajmuje 576. Miej oko na te 78%: wróci to przy powodzie 5.

Wynik Verify: 15394 bajty (47%) flash i 1600 bajtów (78%) pamięci dynamicznej oraz pasek 2048 bajtów RAM UNO z buforem ramki 1024 bajtów zajmującym połowę

Wgraj albo uruchom w symulatorze ​

Przy podłączonej płytce wybierz jej port w tym samym oknie Select Board i kliknij Upload, strzałkę obok Verify.

Nie masz płytki? Otwórz projekt symulatora z odcinka 1: Arduino UNO z wyświetlaczem SSD1306 podłączonym GND do GND, VCC do 5V, SDA do A4 i SCL do A5 oraz biblioteką U8g2. Wklej szkic i naciśnij Play. Wyświetlacz pokazuje ekran Morning i co trzy sekundy przełącza się na Night.

Symulator uruchamiający szkic: Arduino UNO podłączone do OLED z SDA do A4 i SCL do A5, a wyświetlacz pokazuje 07:45 i Sunny 23C

Pięć powodów, dla których ekran pozostaje czarny ​

Sprawdzenia idą od zewnątrz do wewnątrz: przewody, adres, chip, kod i pamięć. W każdym z nich psujemy działającą konfigurację w symulatorze, obserwujemy, jak ekran staje się czarny, i naprawiamy to.

1. Przewody ​

Na UNO SDA trafia do A4, a SCL do A5. Zamień je, a płytka rozmawia z nikim: ekran pozostaje czarny.

Sprawdź też zasilanie i masę. Inne płytki używają innych pinów: na większości płytek ESP32 SDA to pin 21, a SCL to pin 22.

Powód 1, przewody: przewody SDA i SCL zamienione na A4 i A5, oznaczone jako zamienione, rozmowa z nikim, a OLED pozostaje czarny

2. Adres ​

Większość modułów odpowiada na 0x3C, niektóre na 0x3D. U8g2 rozmawia z 0x3C, chyba że powiesz mu inaczej. Jeśli moduł jest ustawiony na 0x3D, nic nie odpowiada, a ekran pozostaje czarny.

Aby dowiedzieć się, który masz, uruchom szkic skanera I2C. Pyta każdy adres na magistrali i wypisuje te, które odpowiadają:

cpp
#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Scanning I2C...");
  for (byte a = 1; a < 127; a++) {
    Wire.beginTransmission(a);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found a device at 0x");
      Serial.println(a, HEX);
    }
  }
  Serial.println("Done.");
}

void loop() {}

Wgraj go i otwórz Serial Monitor na 9600 baud.

Powód 2, adres: szkic skanera I2C działający, z Found a device at 0x3D w Serial Monitor

Następnie ustaw adres w swoim szkicu pulpitu, przed begin():

cpp
void setup() {
  u8g2.setI2CAddress(0x3D * 2);
  u8g2.begin();
}

U8g2 chce adresu podwojonego, więc 0x3D staje się 0x3D * 2, 0x7A: tej samej liczby wydrukowanej z tyłu modułu.

Poprawka w setup: u8g2.setI2CAddress(0x3D * 2) przed u8g2.begin(), U8g2 chce go podwojonego: 0x7A, a OLED ponownie pokazuje pulpit

3. Chip ​

Dwa moduły mogą wyglądać identycznie, a używać różnych kontrolerów. Większość małych ekranów 0,96 cala używa SSD1306. Wiele ekranów 1,3 cala używa SH1106. Uruchom kod SSD1306 na SH1106, a otrzymasz pusty ekran lub pasek szumu wzdłuż krawędzi.

Poprawką jest nazwa chipa w konstruktorze:

cpp
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

Powód 3, chip: moduł SSD1306 0,96 cala z czystym obrazem obok modułu SH1106 1,3 cala z kodem SSD1306 i paskiem szumu wzdłuż prawej krawędzi

4. Kod ​

U8g2 rysuje do bufora w pamięci, a tylko sendBuffer() przenosi obraz na ekran. Zapomnij tej linii albo zapomnij u8g2.begin() w setup(), a ekran pozostanie ciemny. Szkic nadal kompiluje się bez błędu, więc najpierw sprawdź te linie:

cpp
u8g2.begin();          // in setup()
u8g2.clearBuffer();    // in loop()
drawMorning();
u8g2.sendBuffer();

Powód 4, kod: ramka jest rysowana do bufora ramki w RAM, ale przy przekreślonych begin i sendBuffer nigdy nie dociera na ekran, który pozostaje czarny; kompilacja zakończona, bez błędów

5. Pamięć ​

Pamiętasz te 78%? UNO ma 2048 bajtów RAM, a bufor ramki zajmuje połowę.

Lopaka przechowuje obrazy we flash za pomocą PROGMEM: przełącznik Deklaruj jako PROGMEM obok kodu jest domyślnie włączony, a tablice otrzymują U8X8_PROGMEM. Wyłącz go, a obrazy przeniosą się do RAM. Sam księżyc to 48 × 48 / 8 = 288 bajtów, a cztery obrazy pulpitu zajmują 416. Teraz szkic używa 2016 bajtów, 98% RAM, przy 32 bajtach wolnych na wszystko, co program robi podczas działania. Nadal się kompiluje, ale ekran się rozpada: w symulatorze tekst znika, a obrazki się psują.

Powód 5, pamięć: RAM UNO na 98%, bufor ramki 1024, wszystko inne 576 i obrazy 416, łącznie 2016 bajtów; wynik Verify raportuje 2016 bajtów (98%), a OLED pokazuje zepsuty pulpit

Pozostaw PROGMEM włączony. Jeśli nadal brakuje ci RAM, przełącz się na tryb stron: umieść 1 zamiast F w konstruktorze, a bufor skurczy się z 1024 bajtów do 128.

cpp
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

W trybie stron biblioteka rysuje ekran w ośmiu paskach, jeden po drugim, więc loop() też się zmienia. Zamiast clearBuffer() i sendBuffer() rysowanie odbywa się wewnątrz pętli firstPage() / nextPage():

cpp
void loop() {
  u8g2.firstPage();
  do {
    if (millis() / 3000 % 2) drawNight(); else drawMorning();
  } while (u8g2.nextPage());
}

W trybie stron ten sam pulpit używa 704 bajtów, 34% RAM.

Tryb stron: RAM UNO na 34%; konstruktory U8G2_SSD1306_128X64_NONAME_F_HW_I2C dla pełnego bufora i U8G2_SSD1306_128X64_NONAME_1_HW_I2C dla trybu stron, bufor z 1024 do 128 bajtów

Podsumowanie ​

  1. Lopaka rysuje ekran, IDE buduje szkic wokół niego: zainstaluj U8g2, wybierz płytkę, wklej funkcje rysowania i dodaj dyrektywę include, konstruktor, begin() oraz pętlę wyczyść, narysuj, wyślij.
  2. Jedna linia konstruktora opisuje twój wyświetlacz: chip, rozmiar, bufor i okablowanie.
  3. Czarny ekran? Sprawdź pięć rzeczy: przewody, adres, chip, kod i pamięć.

Następny odcinek: Ekrany i menu. Więcej niż jeden ekran, z menu i przyciskiem. Przeczytaj odcinek 6 lub obejrzyj go na YouTube.

Gotowy, aby spróbować? Otwórz Lopaka i umieść swój ekran na prawdziwej płytce.