Obsługa komunikacji komputer - wyświetlacz LCD poprzez USB UART

Wyświetlanie tekstu na wyświetlaczach LCD podłączony do komputera poprzez port USB i szeregowy moduł komunikacji UART

Komunikacja pomiędzy dwoma układami UART (Universal Asynchronous Receiver and Transmitter) wygląda prosto. Jeden układ coś nadaje, drugi odbiera to na swoim odbiorniku, wykonuje jakąś czynność i np. odsyła odpowiedź na odbiornik pierwszego układu. Układy UART są dość powszechnie używane. Popularność Arduino dostarczyła masę układów UART z adapterem USB, co pozwala podłączyć je do zwykłego PCta bez konieczności stosowania płytek z mikrokontrolerami. Taki wyświetlacz można wykorzystać do wyświetlania np. temperatury komputera, obciążenia procesora, wykorzystania pamięci, grafiki, czy do własnych powiadomień itp. Wraz z przyciskami może pełnić też rolę menu i konfigurować jakieś urządzenie, czy aplikację.

Do wyświetlaczy LCD istnieją adaptery pozwalające komunikować się z nimi poprzez UART - taki adapter to płytka z zaprogramowanym mikrokontrolerem, który obsługuje odbieranie danych jak i natywną komunikację z danym wyświetlaczem. Dzięki takiemu adapterowi odpada nam konieczność obsługi, implementacji bardziej złożonego API wyświetlacza. Jeżeli biblioteka do komunikacji szeregowej (jak pyserial) jest przenośna między systemami operacyjnymi, komputerami to wtedy i kod komunikujący się poprzez UART będzie przenośny. Nie jest to rozwiązanie przywiązane do jednego konkretnej platformy.

W tym artykule zaprezentuję komunikację szeregową wyświetlacza LCD wyposażonego w adapter hobbytronics z PCtem, mikrokomputerami i mikrokontrolerami. A wszystko w Pythonie.

Wstęp

Z adapterów dla wyświetlaczy LCD jeden oferuje hobbytronics, a drugi sparkfun. Dostępne są też gotowe z wyświetlaczem, lub też wyświetlacze z adapterem innych producentów. Przed zakupem trzeba sprawdzić czy dostępna jest jakaś dokumentacja, opis komunikacji szeregowej z wyświetlaczem.

Dostępne są też wyświetlacze TFT z wyjściem szeregowym, jak i inne różne kombinacje wyświetlania czegoś na czymś poprzez UART, np. adapter VGA, który potrafi wyświetlać proste okna i tekst na monitorach z wyjściem D-SUB.

Obsługa wyświetlacza LCD 2x16 poprzez UART

Adapter hobbytronics współpracuje z 16-pinowymi wyświetlaczami ciekłokrystalicznymi - 2x16 czy nawet 4x16 listowane na stronie produktu. Adapter trzeba przylutować do pinów wyświetlacza, lub też jeżeli nie chcemy go na stałe łączyć z jednym wyświetlaczem - przylutować mu goldpiny by móc łączyć z wyświetlaczem za pomocą np. płytki stykowej (breadboard). Do pełni szczęścia potrzebny będzie nam jeszcze adapter/moduł USB-UART 5V. Taki dostaniemy w chyba każdym sklepie z elektroniką (typu Arduino, Raspberry Pi itd.). Trzeba aby uważać by wziąć model 5V a nie 3.3V przeznaczony dla np. Raspberry Pi. Przydać może się też kilka kabli połączeniowych.

W przypadku MS Windows potrzebne będą sterowniki. Przed zakupem sprawdź czy są dołączone/dostępne w sieci sterowniki do używanej przez ciebie wersji MS Windows dla danego chipsetu UART.

Moduł USB-UART

moduł USB UART

Adapter hobbytronics przylutowany do wyświetlacza

Adapter hobbytronics przylutowany do wyświetlacza

Adapter hobbytronics połączony z LCD poprzez płytkę stykową

Adapter hobbytronics połączony z LCD poprzez płytkę stykową

Komunikacja pomiędzy modułami UART przebiega między nadajnikiem a odbiornikiem. Nadajnik pierwszego układu (TX lub RXD) łączymy z odbiornikiem drugiego (RX, TXD) i vice versa. Jeżeli drugi moduł (wyświetlacz) nie odpowiada niczym to wtedy można zrezygnować z połączenie jego nadajnika z odbiornikiem pierwszego układu. Tak więc łączymy nasz moduł USB-UART z modułem wyświetlacza następująco:

  • 5V z 5V
  • GND z GND
  • TX z RX wyświetlacza

W przypadku modułu USB-UART firmy 4D Systems mam oznaczenia TX i RX, natomiast w przypadku drugiego modułu - Baite zamiast TX i RX mam odpowiednio RXD i TXD - wtedy RXD łączy się z RX na wyświetlaczu. Połączenie nie tych pinów co trzeba spowoduje to że nic się na wyświetlaczu nie wyświetli :)

Oznaczenia TX RX na module USB UART

Oznaczenia TX RX na module USB UART

Na stronie producenta znajdziemy dokumentację (PDF), jak i przykłady dla Arduino i jeden z pyserial. Wysyłanie określonych znaków poprzez UART wywołuje określone akcje wyświetlacza.

PySerial i wyświetlacz LCD

W dokumentacji, na stronie 5 znajdziemy tabelkę ze znakami wywołującymi określone akcje na wyświetlaczu. Na stronie 14 znajdziemy taki oto przykład wykorzystania pyserial do wyświetlenia tekstu na wyświetlaczu (poprzez UART Raspberry Pi):

import serial
import time
serialport = serial.Serial("/dev/ttyAMA0", 9600, timeout=5)
time.sleep(1)
serialport.write(chr(5)+chr(2)+chr(16)+chr(0xFF))
serialport.write(chr(4)+chr(0xFF))
serialport.write(chr(7)+chr(250)+chr(0xFF))
serialport.write(chr(2)+chr(1)+chr(1)+chr(0xFF))
serialport.write(chr(1)+"Welcome to"+chr(0xFF))
serialport.write(chr(2)+chr(2)+chr(1)+chr(0xFF))
serialport.write(chr(1)+"Hobbytronics"+chr(0xFF))
count = 0
while 1 :
    serialport.write(chr(2)+chr(1)+chr(13)+chr(0xFF))
    serialport.write(chr(1)+str(count)+chr(0xFF))
    time.sleep(1)
    count = count + 1
serialport.close()

Bardzo dużo magicznych liczb. Funkcja chr zamienia podaną liczbę na odpowiadającemu jej znakowi (literze) ASCII. Tabelka w dokumentacji podaje te liczby i ich znaczenie (choć wyświetlacz tak naprawdę dostaje literę). 0xFF (czyli 255 zapisane szesnastkowo) służy jako terminator każdej z operacji dla tego adaptera.

Całość zaczyna się jednak od nawiązania szeregowego połączenia z wyświetlaczem. Wywołanie wygląda tak:

serial.Serial("/dev/ttyAMA0", 9600, timeout=5)

Pierwszy argument to nazwa urządzenia szeregowego. /dev/ttyAMA0 to wbudowany port szeregowy w Raspberry Pi. Po podłączeniu modułu USB-UART dostaniemy pod Linuksem /dev/ttyUSB0 i ew. kolejne (widać to w dmesg). Pod Windowsem będą to wirtualne porty COM. Drugi argument to tzw. baud rate, czyli szybkość transmisji. Wartość 9600 jest dość typowa dla modułów UART. Czasami mogą być podane inne wartości jakie dany moduł obsługuje. Pod Linuksem o ile nie nadamy uprawnień na dane urządzenie (np. na /dev/ttyUSB0 w konfiguracji udev) to połączyć będziemy mogli się tylko jako superużytkownik (sudo albo root).

Klasa do obsługi wyświetlaczy poprzez adapter Hobbytronics

Przykład z dokumentacji nie jest zbyt fajny i nie nadaje się do praktycznej pracy z wyświetlaczem. Dlatego napisałem taką oto prostą klasę:

import time

import serial


class LCD(object):
    END = chr(0xFF)

    def __init__(self, device, rows, columns):
        self.commands = {
            'display_string': chr(1),
            'set_cursor_position': chr(2),
            'clear_line': chr(3),
            'clear': chr(4),
            'set_lcd_type': chr(5),
            'backlight': chr(7)
        }
        self.device = device
        self.rows = rows
        self.columns = columns
        self.connection = None

    def configure(self):
        self.connection = serial.Serial(self.device, 9600, timeout=5)
        time.sleep(1)
        self.execute_command('set_lcd_type', chr(self.rows) + chr(self.columns))
        self.clear()

    def clear(self):
        self.execute_command('clear', '')

    def clear_line(self, line):
        self.execute_command('clear_line', chr(line))

    def set_backlight(self, brightness):
        self.execute_command('backlight', chr(brightness))

    def set_cursor_position(self, row, column):
        self.execute_command('set_cursor_position', chr(row) + chr(column))

    def display_string(self, string):
        self.execute_command('display_string', string)

    def close(self):
        self.connection.close()

    def execute_command(self, command, payload):
        self.connection.write(self.commands[command] + payload + self.END)
Dzięki niej implementacja zegara może wyglądać tak:
from datetime import datetime

lcd = LCD("/dev/ttyUSB0", rows=2, columns=16)
lcd.configure()
lcd.set_backlight(25)

while True:
    day = datetime.now().strftime('%d, %b %Y')
    current_time = datetime.now().strftime('%H:%M:%S')

    lcd.set_cursor_position(1, 1)
    lcd.display_string(day)
    lcd.set_cursor_position(2, 1)
    lcd.display_string(current_time)
    time.sleep(1)
PcDuino wyświetla datę i czas

PcDuino wyświetla datę i czas

Kod ten zadziała na dowolnym komputerze, do którego możemy podłączyć moduł USB-UART i na którym da się zainstalować pyserial (czyli praktycznie dowolnie) - PCty, laptopy, mini-komputery jak Raspberry Pi, PcDuino czy inne. W przypadku Raspberry użycie modułu USB-UART wymagać będzie podłączenia go przez zasilany HUB USB, gdyż porty USB Raspberry Pi mają narzucony limit 0,1A zamiast standardowego 0,5A.

Raspberry Pi obsłuży USB-UART przez zewnętrzny zasilany port USB

Raspberry Pi obsłuży USB-UART przez zewnętrzny zasilany port USB

Raspberry Pi jak i niektóre inne mini komputery, czy bardziej przemysłowe płyty główne PCtów mogą mieć wbudowane moduły, funkcjonalności układu UART. Wtedy odpada konieczność stosowania adaptera. W przypadku Raspberry mamy TXD na czwartym zewnętrznym pinie, tuż obok GND i 5V potrzebny do zasilenie wyświetlacza. Po podłączeniu w powyższym przykładzie z zegarem wystarczy zmienić /dev/ttyUSB0 na /dev/ttyAMA0.

Obsługa wyświetlacza przez wbudowany UART Raspberry Pi

Obsługa wyświetlacza przez wbudowany UART Raspberry Pi

Inne wyświetlacze

Jak dobrze poszukasz to znajdziesz różne wyświetlacze LCD/TFT z modułem UART. Nie wszystkie będą miały jednak tak proste API. Wtedy przydają się gotowe biblioteki albo duże chęci by takie napisać. Np. wspomniana wcześniej firma 4D Systems oferuje dotykowe wyświetlacze LCD, które mają spore możliwości programowania. Producent oferuje całe IDE do tworzenia interfejsów (jak dotykowe przełączniki, wskaźniki, wykresy itp.). Oprócz tego prostsze operacje można wykonywać poprzez komunikację UART. Dostępne są nawet startowe zestawy dla Arduino, Raspberry, czy Beaglebone.

Dla Pythona dostępna jest biblioteka python-picaso-lcd, którą można wykorzystać do prostego oskryptowania wyświetlacza, np:

import time

from picaso_lcd import display

disp = display.Display('/dev/ttyUSB0', 9600)
time.sleep(3)
disp.cls()
LANDSCAPE = 1
disp.set_orientation(LANDSCAPE)

texter = display.DisplayText(disp)
texter.put_string("I'm an LCD display!\n")
texter.put_string("I can display:\n-text\n-basic graphics\n-and do touch events")
time.sleep(15)
Wyświetlacz 4D Systems wyświetlający tekst

Wyświetlacz 4D Systems wyświetlający tekst

blog comments powered by Disqus

Kategorie

Strony