[118] Arduino i telewizor cz. 1

[118] Arduino i telewizor cz. 1

Od dawna chciałem zgłębić ten temat: Arduino jako karta graficzna, a konkretnie generator obrazu telewizyjnego. Prawdę powiedziawszy, to kolejna odsłona, jak by nie było, ośmiobitowego komputerka, która mnie zaskoczyła: z pomocą tylko dwóch rezystorów powstał komputer meritumopodobny. Owszem, bardzo skromna jest ta grafika, ale do jej generacji wykorzystujemy tutaj wyłącznie to, co znajduje się w układzie ATMega328 i skromniutkie 2 kB RAM-u, a oprócz literek możemy wyświetlać także grafiki i to wcale skomplikowane, korzystające z pełnej rozdzielczości. Cały proces, mimo programowej realizacji, jest niezwykle szybki, pozostawiając moce na własne działania.


Jednak dwa kilobajty to bardziej niż mało, więc rozdzielczość wynosi skromne 128x96 pikseli i nie mamy tutaj koloru. Czy to ma sens? Historycznie – pierwsze komputery tyle oferowały i marzono o nich, a kosztowały niejedną pensję – zachodnią, dodajmy. Jednak i dziś, w określonych warunkach może być to przydatne, głównie do emulacji retro obrazów. Wyświetlaczy z wejściem wizyjnym wciąż na rynku jest sporo i można sobie wyobrazić sytuacje, w których coś takiego uatrakcyjni przekaz. Nie do mnie jednak należy wymyślanie zastosowań takiej aplikacji, przedstawię ją po prostu, krok po kroku.

Pierwszym będzie zdobycie dwóch rezystorów, kabelka i samego monitora. Jeden z nich będzie mieć wartość kilooma, drugi – połowę. Posłużę się płytką edukacyjną TME, więc wszystko będzie proste i przejrzyste. Mam tutaj oczywiście Arduino Uno, lecz biblioteka wspiera wiele innych ośmiobitowych mikrokontrolerów. Szczegóły można znaleźć w dokumentacji.

Kiloomowy rezystor podłączymy do pinu dziewiątego, ten o wartości 470 omów – do siódmego. Z drugiej strony oba oporniki łączymy razem i podłączamy do wejścia wideo, tak zwanego kompozytowego. Sporo monitorów posiada go jako jedyne wejście, siedzi także na jednym z pinów w eurozłączu. W przypadku monitorów komputerowych potrzebny będzie układ konwertujący, jakiego używa się, chcąc podłączyć stare komputery do HDMI czy wejść VGA. Oczywiście łączymy ze sobą także masy urządzeń.

I to już wszystko, jeśli chodzi o sprzęt. Oprogramowanie będzie wykorzystywać bibliotekę – jak zwykle i tym razem napisanie jej na piechotę byłoby zadaniem skomplikowanym ze względu na wymagania sygnału zgodnego ze standardami telewizyjnymi ustalonymi ponad 70 lat temu. Bibliotekę TVout można po prostu ściągnąć z zasobów bibliotek, ale tak prosto to nie zadziała. W pakiecie znajdziemy katalog TVoutfonts, który trzeba przenieść ręcznie folder wyżej – czyli do katalogu ze wszystkimi bibliotekami. Jeśli tego nie zrobimy, otrzymamy komunikat błędu bez wyjaśnienia jego przyczyny.

Zacznę od dema, które dostarczył autor biblioteki, a które obrazuje możliwości graficzne. Po prostu skompilujmy je i przypatrzmy się temu, co pojawi się na wyświetlaczu. Jeśli połączenia są wykonane prawidłowo, a monitor sprawny, ujrzymy kolejno: przesuwający się obrazek, kilka napisów, kolejny obrazek, zestaw skalowanych napisów, demo rysowanych grafik: kół, prostokątów i odcinków oraz proste, acz efektowne demo 3D. To wszystko wygląda ładnie, ale użyteczne będzie dopiero, gdy nad tym zapanujemy. Czas więc rozłożyć program na czynniki pierwsze, co nie będzie takie proste z braku jakichkolwiek komentarzy czy dokumentacji. Ale od tego ja tu jestem. Zaczniemy więc od napisów.

#include <TVout.h>   // Biblioteka tworząca obraz telewizyjny.
#include <fontALL.h> // Biblioteka dołączająca zestawy czcionek.
TVout telewizor;      // Definicja obiektu.

void setup() {
  telewizor.begin(PAL, 120, 96);   // Szerokość i wysokość obrazu.
  telewizor.select_font(font6x8);  // Dołącz bibliotekę czcionek.

  telewizor.print("ABCDEFGHIJKLMNOPQRST");  // Drukuj napis.
  telewizor.print("abcdefghijklmnopqrst");
  telewizor.print("1234567890!@#$%^&amp;*()");
  telewizor.print("ABCDEFGHIJKLMNOPQRST");
  telewizor.print("abcdefghijklmnopqrst");
  telewizor.print("1234567890!@#$%^&amp;*()");
  telewizor.print("ABCDEFGHIJKLMNOPQRST");
  telewizor.print("abcdefghijklmnopqrst");
  telewizor.print("1234567890!@#$%^&amp;*()");
  telewizor.print("ABCDEFGHIJKLMNOPQRST");
  telewizor.print("abcdefghijklmnopqrst");
}
void loop() {
}

Jak zwykle, szkic będzie się zaczynał od zaciągnięcia bibliotek – sterującej monitorem i obsługującej czcionki. Ta druga będzie potrzebna tylko, gdy będziemy korzystać z możliwości umieszczania napisów. Należy także zdefiniować obiekt, czyli nazwę dla naszych nowych funkcji.

Inicjacja niesie ze sobą także zdefiniowanie rozdzielczości. Tutaj niby sprawa jest oczywista: 120x96 pikseli, ale nie do końca. Te parametry gwarantują poprawną pracę układu w każdych warunkach. Potencjał jednak jest większy i wszystko zależy… trudno powiedzieć do końca od czego. Metodą prób i błędów udało mi się uzyskać dodatkowych piętnaście pikseli w poziomie i cztery w pionie. Załóżmy jednak, że nie jest to metoda uniwersalna, a taki obraz kaprysi w zależności od treści.

Rysowanie napisów jest realizowane komendą telewizor.print() Przy rozdzielczości domyślnej, w przypadku użycia czcionki 6x8 pikseli możemy otrzymać 11 wierszy po 20 znaków w każdym, czyli 220 liter.

Zwiększenie rozdzielczości do 128x98 pikseli pozwala dołożyć jedną literkę w każdej kolumnie i dodatkowy wiersz – zysk oznaczyłem literami X Obejrzyjmy sobie inne czcionki.

Font 8x8 jest typowy dla ośmiobitowców, ale zarazem za duży dla tej niewielkiej rozdzielczości. Mamy go, więc możemy wykorzystać w razie potrzeby. Jak w poprzednim przypadku, wychodząc ponad standard rozdzielczości, możemy uzyskać 12 wierszy po 16 liter w każdym.

Istnieje też alternatywny krój o tym wymiarze, chyba ładniejszy.

W końcu ostatni dostępny font jest najmniejszym i bazuje na siatce 4x6 pikseli. Liter zmieści się dużo: 16 wierszy i trzydzieści kolumn, ale czytelność jest marna. Ten krój można wykorzystać jako uzupełniający, bo czcionki możemy mieszać. W jaki sposób? A to już zobaczymy w kolejnym szkicu.

#include <TVout.h>    // Biblioteka tworząca obraz telewizyjny.
#include <fontALL.h>  // Biblioteka dołączająca zestawy czcionek.
TVout telewizor;      // Definicja obiektu.

void setup() {
  telewizor.begin(PAL, 120, 96);   // Szerokość i wysokość obrazu.
  telewizor.select_font(font4x6);  // Dołącz bibliotekę czcionek.

  telewizor.select_font(font4x6);       // Wybór aktywnego kroju.
  telewizor.println("Rozmiar maly\n");  // ln oraz \n dodają znak przeniesienia wiersza.
  telewizor.select_font(font6x8);
  telewizor.println("Rozmiar domyslny\n");
  telewizor.select_font(font8x8);
  telewizor.println("Rozmiar duzy,  I zestaw\n");
  telewizor.select_font(font8x8ext);
  telewizor.println("Rozmiar duzy,  II zestaw\n");
}
void loop() {
}

Komenta selcect_font pozwoli wybrać aktywny krój, natomiast zarówno println jak \n wymuszają złamanie wiersza. Wstawienie obu tych elementów jednocześnie dodaje także pusty wiersz.

No dobrze, ale nie mamy tutaj polskich znaków. Jak je uzyskać? Niestety trzeba będzie pogrzebać w plikach z krojami. Nie jest to szczególnie trudne, o ile chodzi o mniejsze fonty, gdyż zakodowano je w postaci binarnej, więc wszystko widać.

Wystarczy zastąpić jakieś nieużywane znaki, choć lepiej byłoby poszerzyć zestaw ponad 96 znaków. Przy okazji można byłoby poprawić krój podstawowy, bo nie wygląda najlepiej. Można też próbować importować kroje z innych projektów, jak choćby z bibliotek obsługujących elektroniczny papier czy wyświetlacze z telefonów, o których kiedyś już pisałem. W kolejnym artykule zajmiemy się rysowaniem grafik.

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2025 arduino.pl