[HD44780]Moduły LCD

Pozostałe układy mikrokontrolerów, układy peryferyjne i inne, nie mieszczące się w powyższych kategoriach.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

[HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 20:29

Moduły wyświetlaczy alfanumerycznych LCD w systemach z mikrokontrolerami AVR

LCD1_ilu00.jpg


Bardzo popularnym sposobem prezentacji informacji wynikowej w systemach z użyciem mikrokontrolerów jest użycie gotowych modułów wyświetlaczy alfanumerycznych LCD. Jest to gotowy do użycia, zawierający własny sterownik i nie wymagający dodatkowych elementów, podzespół elektroniczny do zastosowania w systemach mikroprocesorowych. Najbardziej rozpowszechnionym rozwiązaniem tych sterowników jest sterownik zgodny z układem HITACHI HD44780. Elastyczność sterownika pozwala on na obsługę wyświetlaczy jedno lub dwuwierszowych z maksymalnie do 40 znaków w jednym wierszu.
LCD1_ilu01.jpg
Oba pokazane na fotografii układy wyświetlaczy wymagają identycznej obsługi, która jest realizowana za pośrednictwem 8-bitowej szyny danych (do przesyłania kodów poleceń oraz wyświetlanych danych) oraz trzech sygnałów sterujących. Każdy wyświetlacz (zgodny z HD44780) zawiera złącze 14-pinowe lub 16-pinowe w zależności, czy wyświetlacz jest podświetlany (dwa dodatkowe piny służą do zasilania LED-owego podświetlenia). Jak widać na ilustracji 1, spotykane są dwa rozwiązania złącza: jako jednorzędowe lub dwurzędowe. Wyprowadzenia o identycznych numerach spełniają identyczną funkcję (różnica pomiędzy złączami sprowadza się do “geometrii”). Wyprowadzenia wyświetlacza ze złączem jednorzędowym jest pokazane na ilustracji 2.
LCD1_ilu02.jpg
i jako moduł:
LCD1_ilu03.jpg
Wyprowadzenia wyświetlacza ze złączem dwurzędowym jest pokazane na ilustracji 4.
LCD1_ilu04.jpg
i jako moduł:
LCD1_ilu05.jpg
Znaczenie poszczególnych wyprowadzeń jest następujące:
  • Pin Symbol Znaczenie
  • 1 GND Masa zasilania (0V)
  • 2 VDD Zasilanie wyświetlacza (+5V)
  • 3 V5 Napięcie kontrastu dla LCD, napięcie analogowe do regulacji kontrastu, najczęściej stosowanym rozwiązaniem jest to napięcie z suwaka potencjometru włączonego między 0V i +5V.
  • 4 RS Sygnał sterujący wyborem rejestru (Register Select):
    RS=1 – operacja dotycząca rejestru danych
    RS=0 – operacja dotycząca rejestru poleceń
  • 5 R/W Sygnał informujący moduł, czy operacja dotyczy zapisu do modułu czy odczytu z modułu:
    R/W = 0 – operacja zapisu
    R/W = 1 – operacja odczytu
  • 6 E Sygnał wyboru (Enable), aktywny dla E=1
  • 7 DB0 Bit 0 szyny danych do modułu
  • 8 DB1 Bit 1 szyny danych do modułu
  • 9 DB2 Bit 2 szyny danych do modułu
  • 10 DB3 Bit 3 szyny danych do modułu
  • 11 DB4 Bit 4 szyny danych do modułu
  • 12 DB5 Bit 5 szyny danych do modułu
  • 13 DB6 Bit 6 szyny danych do modułu
  • 14 DB7 Bit 7 szyny danych do modułu
  • 15 A 15 A Anoda diody LED podświetlenia
  • 16 K 16 K Katoda diody LED podświetlenia

Wyświetlacz może być przyłączony do mikrokontrolera w jednym z dwóch możliwych trybach:
  • z 4-bitowym interfejsem szyny danych do wyświetlacza (w tym wypadku jako szyna danych używane są DB4 do DB7, pozostałe bity szyny danych nie mają znaczenia),
  • z 8-bitowym interfejsem szyny danych do wyświetlacza.
Do sterowania wyświetlaczem używanych są trzy sygnały: RS, R/W i E. Istnieje możliwość wysterowania sygnału R/W na stałe (poprzez podanie na te wyprowadzenie stanu logicznego zera, czyli przyłączyć sygnał R/W do masy GND), co jednocześnie oznacza, że wszelkie operacje dotyczące wyświetlacza LCD są operacjami zapisu informacji do modułu wyświetlacza, brak jest możliwości odczytu informacji z modułu wyświetlacza. Implikacją takiego rozwiązania jest konieczność odczekania przez mikrokontroler określonego czasu (w zależności od realizowanej operacji) przed zapisem kolejnych danych. Wykonanie niektórych rozkazów wymaga pewnego czasu i każde polecenie wysłane do wyświetlacza w trakcie realizacji poprzedniego zostanie zignorowane. W przypadku, gdy istnieje możliwość odczytu informacji z modułu LCD (sygnał R/W jest przyłączony do mikrokontrolera i program może nim sterować), gotowość modułu LCD do przyjęcia kolejnego rozkazu jest sygnalizowana w jego statusie po odczytaniu odpowiedniego rejestru. Rozpatrując różne warianty przyłączenia modułu do mikrokontrolera, można zauważyć, że konieczne jest użycie od 6 linii (w wariancie maksymalnie uproszczonym) do 11 linii (przy wykorzystaniu wszystkich sygnałów sterujących).
Polecenia sterujące wyświetlaczem HD44780 (w operacjach zapisu do rejestru instrukcji RS=0 i R/W=0).
  • DB7 .. DB0 Czas wykonania Opis
  • 0 0 0 0 0 0 0 1 1,52 ms Polecenie czyszczenia wyświetlacza i ustawienia pozycji kursora na adresie 0.
  • 0 0 0 0 0 0 1 - 1,52 ms Polecenie przestawienia kursora na adres 0.
  • 0 0 0 0 0 1 I S - 37 µs Polecenie określenia trybu przestawiania kursora w czasie pracy:
    I=0 – zmniejszanie pozycji kursora,
    I=1 – zwiększanie pozycji kursora,
    S=1 – włącza (S=1) lub wyłącza (S=0)
    autonomiczne przewijanie wyświetlonych informacji.
  • 0 0 0 0 1 D C B - 37 µs Polecenia sterujące wyświetlaczem:
    D=0 – wyłącza wyświetlacz,
    D=1 – włącza wyświetlacz,
    C=0 – wyłącza kursor,
    C=1 – włącza kursor,
    B=0 – wyłącza pulsowanie kursora,
    B=1 – włącza pulsowanie kursora.
  • 0 0 0 1 S R - - 37 µs Polecenia sterujące kursorem:
    S=0 – oznacza, że zapisy znaków powodują przestawienie pozycji kursora,
    S=1 – oznacza, że zapisy znaków powodują przewijanie wyświetlonej informacji,
    R=0 – przesuwanie w prawą stronę,
    R=1 – przesuwanie w lewą stronę.
  • 0 0 1 L N F - - 37 µs Polecenie ustawienia funkcji:
    L=0 – określa 4-bitowy interfejs do modułu,
    L=1 – określa 8-bitowy interfejs do modułu,
    N=0 – określa, że wyświetlacz jest jednowierszowy,
    N=1 – określa, że wyświetlacz jest dwuwierszowy,
    F=0 – określa użycie znaków w matrycy 5 x 8 punktów,
    F=1 – określa użycie znaków w matrycy 5 x 10 punktów.
  • 01AAAAAA 37 µs Polecenie ustawienia adresu pamięci generatora znaków (adres jest reprezentowany przez 6-bitową liczbą AAAAAA).
  • 1AAAAAAA 37 µs Polecenie ustawienia adresu pamięci wyświetlanych danych (adres jest reprezentowany przez 7-bitową liczbą AAAAAAA).

Polecenia odczytu rejestru statusu wyświetlacza HD44780 (w operacjach odczytu z rejestru instrukcji RS=0 i R/W=1).
  • DB7 .. DB0 Opis
  • BAAAAAAA Polecenie odczytu statusu sterownika,
    B=0 – oznacza gotowość sterownika do przyjęcia kolejnego polecenia,
    B=1 – oznacza, że sterownik jest zajęty realizacją wydanego polecenia.
    AAAAAAA - adres w pamięci wyświetlanych danych (adres jest reprezentowany przez 7-bitową liczbą).

Zapis danych (znaków) na ekran wyświetlacza następuje dla RS=1 i R/W=0. Wykonanie operacji wymaga 37 µs.
Rozpatrując różne rozwiązania modłów LCD można zauważyć, że istnieją wyświetlacze posiadające (1 wiersz, 16 znaków w wierszu), które w rzeczywistości są dwuwierszowe po 8 znaków w wierszu, to znaczy, że należy je traktować w ten sposób. Oba wiersze fizycznie na ekranie znajdują się obok siebie tworząc jeden 16-znakowy wiersz. Aby uzyskać poprawną postać informacji na ekranie, po wyświetleniu 8 znaków należy przejść do następnego wiersza. Zaprogramowanie takiego wyświetlacza jako jednowierszowego spowoduje, że na ekranie będzie widoczna jedynie połowa wiersza.
Posiłkując się pojęciem zaczerpniętym z muzyki, oto kilka “wariacji na druty i bajty z prockiem AVR i modułem LCD w tle”.
Wariant sprzętowo najprostszy sprowadza się do 4-bitowego interfejsu szyny danych oraz dwóch sygnałów sterujących. Przykład użycia prezentuje poniższy rysunek.
LCD1_ilu06.png
Użyte są w module LCD:
  • 4 sygnały szyny danych: DB4 .. DB7 przyłączone odpowiednio do PORTB0 do PORTB3,
  • sygnał RS przyłączony do PORTD5,
  • sygnał R/W przyłączony na stałe do masy (wszelkie operacje dotyczące modułu LCD będą operacjami zapisu),
  • sygnał E przyłączony do PORTD6.
Poniższy program dotyczy przypadku użycia wyświetlacza 1 wiersz 16 znaków będącego wyświetlaczem dwuwierszowym po 8 znaków w wierszu. Implikacją tego jest konieczność zliczania wyświetlanych znaków (zmienna CharPos), by po wyświetleniu 8 znaków automatycznie przejść do następnego wiersza uzyskując poprawną postać informacji na ekranie. Ponieważ nie ma możliwości odczytu statusu modułu, po każdej operacji realizowane jest odczekanie odpowiedniego czasu.
Używając modułów wyświetlaczy przyłączonych do mikrokontrolera poprzez 4-bitowy interfejs szyny danych należy mieć na uwadze, że wyświetlacz od momentu włączenia mu zasilania autonomicznie realizuje pewne czynności, po wykonaniu których ma on określony interfejs jako 8-bitowy. Oznacza to, że pierwsze polecenie wysłane do modułu powinno być poleceniem przełączenia na 4-bitowy interfejs i należy je wysłać jak w przypadku interfejsu 8-bitowego, to jest wystawić na szynie danych odpowiedni kod i wykonać jednorazową operację zapisu (jeden impuls strobu E). Każde kolejne powinno być wykonane w następujący sposób (wykonać “dwutakt”):
  • wystawić starszą część bajtu na szynie danych,
  • dokonać zapisu do modułu (wygenerować jeden impuls strobu E),
  • wystawić młodszą część bajtu na szynie danych,
  • dokonać zapisu do modułu (wygenerować jeden impuls strobu E).
W ogólnym przypadku algorytm obsługi modułu LCD jest taki sam. Można w pewnym sensie uzyskać rozwiązanie w dużej mierze niezależne od środowiska (sposobu przyłączenia samego modułu). W programie kolorem wyróżnione są te fragmenty, które dotyczą fizycznego przyłączenia modułu. Modyfikacja tekstu programu w ich zakresie pozwoli na inne rozwiązania sprzętowego przyłączenia modułu do mikrokontrolera (w końcu program musi odpowiadać schematowi). Również należy mieć na uwadze fakt, że niezbędne opóźnienia w programie są realizowane przez wykonanie określonej liczby instrukcji pustych. Czas zużyty przez procesor na ich realizację jest uzależniony od częstotliwości taktującej mikrokontroler. W przykładach stosowany jest zewnętrzny rezonator kwarcowy o częstotliwości 7,3728MHz. W przypadku stosowania innych należy odpowiednio zmodyfikować procedury opóźnień (w szczególności procedury Delay37ms i Delay1520ms).
Program znajduje się w zbiorze: EXAMPLE-A.ASM.
Wariant sprzętowy (ten sam model wyświetlacza): 8-bitowy interfejs szyny danych oraz dwa sygnały sterujące. Przykład użycia prezentuje poniższy rysunek.
LCD1_ilu07.png
W oprogramowaniu ulegają pewnym uproszczeniom same operacje zapisu danych do modułu LCD.
Program znajduje się w zbiorze: EXAMPLE-B.ASM.
Można pokusić się o “wyższy poziom abstrakcji” rozwiązania polegający na “maksymalizacji oderwania oprogramowania od rozwiązania sprzętowego”. Jednym z możliwych rozwiązań jest wprowadzenie własnych makroinstrukcji. Pozwala to określić w jednym miejscu istniejące zależności sprzętowe bez żadnych ingerencji w algorytm obsługi.
Środowisko sprzętowe jest identyczne jak w: EXAMPLE-A.ASM
Program znajduje się w zbiorze: EXAMPLE-C.ASM.
Dotychczasowe przykłady (EXAMPLE-A i EXAMPLE-C) miały pewne wady, to jest używały dość niefrasobliwie PORTB. Wpisując dane instrukcją out zmianie mogą ulegać piny nie używane przez wyświetlacz, do których mogą być przyłączone inne zespoły cyfrowe, wpływając niewłaściwie na ich pracę. Można pokusić się o jeszcze “wyższy poziom abstrakcji” i większą parametryzację.
Przykład prezentuje użycie modułu LCD w konfiguracji umożliwiającej odczyt statusu (moduł: 2 wiersze po 40 znaków, więc nie istnieje problem zliczania wyświetlonych znaków). Dotychczasowe operacje związane z odczekaniem wymaganego czasu są zastąpione przez operacje odczytu statusu, więc program uwalnia się od odmierzania czasu przez wykonywanie pustych instrukcji. Środowisko użycia modułu przedstawia poniższy rysunek.
Z punktu widzenia oprogramowania, w tym przypadku użycie portu jest zrealizowane “w delikatny” sposób bez zamieszania na sąsiednich wyprowadzeniach. Definicja stałych :
  • lcd_E_pin
  • lcd_RS_pin
  • lcd_RW_pin
  • lcd_D4_pin
  • lcd_D5_pin
  • lcd_D6_pin
  • lcd_D7_pin
pozwala na precyzyjne użycie tylko wymaganych wyprowadzeń. Dodatkową uzyskaną cechą jest to, że przyłączenie szyny danych modułu LCD do mikrokontrolera może być dowolnie rozłożone w obrębie portu (w przykładzie nie jest zachowana naturalna kolejność bitów szyny danych).
LCD1_ilu08.png

Program znajduje się w zbiorze: EXAMPLE-D.ASM.
Powyższy przykład rozwiązania programu nie wyczerpuje możliwości związanych z dalszą parametryzacją. Można pokusić się o definicję dodatkowych stałych pozwalających opisać samo przyłącze modułu LCD do mikrokontrolera i uzyskać w dużym stopniu uniwersalny zestaw procedur obsługi. Inny projekt urządzenia z użyciem wyświetlacza posiadający inaczej przyłączony moduł nie musi być kolejną rewolucją w programie.

Załącznik: prezentowane programy
avr_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 20:58

Sterowanie modułów wyświetlaczy alfanumerycznych LCD w systemach z mikrokontrolerami AVR
przykłady programów w języku C


Zastosowanie modułów w urządzeniach zawierających mikrokontrolery sprowadza się do rozwiązania problemów w dwóch aspektach: zagadnienia związane ze sprzętowym przyłączeniem modułu (temat sprzętowy) i zagadnienia związane z oprogramowaniem mikrokontrolera do obsługi modułu (temat oprogramowania).
W przypadku rozważań sprzętowych, to konstruktor nie ma zbyt wielkiego pola manewru. Gotowy moduł ma określone wymagania, które należy spełnić (inaczej moduł nie będzie działał właściwie). Opis złącza i znaczenie poszczególnych sygnałów w nim występujących zostało wystarczająco dokładnie przedstawione wyżej.
W przypadku rozważań związanych z oprogramowaniem, temat staje się bardzo szeroki. Pomijając kwestię samego algorytmu obsługi wyświetlacza, gdzie można zaproponować wiele rozwiązań (właściwie co autor, to inny pomysł na obsługę), pozostaje jeszcze kwestia zapisu tego algorytmu w określonym języku programowania. Poniżej przedstawiona jest moja “wizja” rozwiązania, która składa się z zestawu funkcji napisanych w języku programowania C. Istotnym ich elementem jest uzyskanie wystarczająco wysokiego poziomu elastyczności pozwalającej na użycie ich w wielu wariantach. Koncepcję rozwiązania przedstawia schematyczna ilustracja 1.
LCD2_ilu01.PNG

Do programu dołączona jest para plików (nagłówek “lcdlib.h” i implementacja “lcdlib.c”) zawierające algorytm obsługi modułów wyświetlaczy LCD ze sterownikiem HD44780 (sposób obsługi z odczytem statusu wykonania polecenia, co implikuje użycie wszystkich trzech sygnałów sterujących E, RS i R/W). Moduły te posiłkują się zawartością pliku opisującego “wymagania” (plik lcdequip.h) wynikające ze sposobu przyłączenia modułu LCD oraz określające jego istotne cechy (jak liczba wierszy, liczba bitów szyny danych itp). W zależności od rzeczywistego rozwiązania przyłącza modułu do mikrokontrolera AVR należy zmodyfikować jedynie plik lcdequip.h (i nic więcej).
Zawarte tam parametry mają następujące znaczenie:
  • Symbol parametru Znaczenie
  • v1x16_as_2x8 określa, czy użyty jest moduł wyświetlający jeden wiersz z 16-oma znakami, który należy obsługiwać jako wyświetlacz dwuwierszowy po 8 znaków w wierszu (istotny jest fakt definicji parametru)
  • lcd_Interf4b określa przyłączenie modułu poprzez 4-bitowy interfejs szyny danych LCD (istotny jest fakt definicji parametru), brak definicji parametru oznacza interfejs 8-bitowy
  • lcd_as1line określa użycie wyświetlacza jednowierszowego (istotny jest fakt definicji parametru, parametr V1x16_as_2x8 jest “silniejszy” od parametru lcd_as1line)
  • lcd_E_port, lcd_E_pin określają szczegóły związane z przyłączeniem do mikrokontrolera sygnału E z modułu
  • lcd_RW_port, lcd_RW_pin określają szczegóły związane z przyłączeniem do mikrokontrolera sygnału R/W z modułu
  • lcd_RS_port, lcd_RS_pin określają szczegóły związane z przyłączeniem do mikrokontrolera sygnału RS z modułu
  • lcd_Data_port określa port, do którego przyłączona jest szyna danych modułu LCD (zakłada się, że wszystkie bity szyny danych znajdują się w obrębie jednego portu i w przypadku interfejsu 8-bitowego kolejne wyprowadzenia bitów szyny danych są dołączone do odpowiednio kolejnych wyprowadzeń bitów portu, w przypadku interfejsy 4-bitowego istnieje dowolność przyłączenia ale w obrębie jednego portu)
  • lcdD0, lcdD1, lcdD2, lcdD3 określają numery bitów wyprowadzeń w porcie szyny danych w przypadku zastosowania 4-bitowego interfejsu (dla interfejsu 8-bitowego powyższe parametry nie są istotne)
  • lcd_DataDir_port, lcd_DataPin_port, lcd_E_Dir_port, lcd_RS_Dir_port, lcd_RW_Dir_port pomocnicze parametry mające znaczenie we właściwym skonfigurowaniu środowiska
Zestaw funkcji modułu lcdlib zawiera zastępujące funkcje:
  • void InitLCDEnvir ( void ) - funkcja wykonywana jednorazowo do odpowiedniego skonfigurowania wyprowadzeń portów mikrokontrolera określonego w zbiorze lcdequip.h,
  • InitialiseLCD ( void ) - funkcja do zaprogramowania modułu LCD do pracy w konfiguracji określonej przez lcdequip.h,
  • void ClrScrLCD ( void ) - funkcja do czyszczenia ekranu wyświetlacza,
  • void HomeLCD ( void ) - funkcja do przestawienia kursora na początek ekranu,
  • void SetCursonOn ( uint8_t BlinkMode ) - funkcja włączająca wyświetlanie na ekranie kursora (pozwala określić, czy kursor ma być pulsujący),
  • void SetCursonOff ( void ) - funkcja wyłączająca na ekranie kursor,
  • void NewLineLCD ( void ) - funkcja przestawiająca kursor na początek drugiego wiersza,
  • void WriteChLCD ( unsigned char Ch ) - funkcja do wyświetlenia pojedynczego znaku na ekranie,
  • void WriteTextLCD ( unsigned char * Text ) - funkcja do wyświetlenia ciągu znaków (zapisanych z zmiennej w pamięci RAM),
  • void WriteTextLCDFlash ( const unsigned char * String ) - funkcja do wyświetlenia ciągu znaków zapisanych jako stała w segmencie kodu,
  • void SetCursorPos ( uint8_t Col ) lub
  • void SetCursorPos ( uint8_t Col , uint8_t Row ) - funkcja do ustawienia kursora w określonym miejscu ekranu (dla wyświetlaczy dwuwierszowych ma dwa parametry).
Implementacja funkcji modułu jest następująca (zawiera różne realizacje sterowania w zależności od zdefiniowanych parametrów → w oparciu o kompilację warunkową [w tekście przykładowo wyróżniono warianty dla realizacji 4-bitowej oraz 8-bitowej]):
Następujący fragment programu:

Kod: Zaznacz cały

void SetOutputDataBus ( void )
  {
#ifdef lcd_Interf4b
    lcd_DataDir_port |= 1 << lcdD0 ;      // [lcd_DataDir_port . lcdD0 ] - [output]
    lcd_DataDir_port |= 1 << lcdD1 ;      // [lcd_DataDir_port . lcdD1 ] - [output]
    lcd_DataDir_port |= 1 << lcdD2 ;      // [lcd_DataDir_port . lcdD2 ] - [output]
    lcd_DataDir_port |= 1 << lcdD3 ;      // [lcd_DataDir_port . lcdD3 ] - [output]
#else
    lcd_DataDir_port = 0xFF ;         // [lcd_DataDir_port] - [output]
#endif
  } /* SetOutputDataBus */


void SetInputDataBus ( void )
  {
#ifdef lcd_Interf4b
    lcd_DataDir_port &= ~ ( 1 << lcdD0 ) ;   // [lcd_DataDir_port . lcdD0 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD1 ) ;   // [lcd_DataDir_port . lcdD1 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD2 ) ;   // [lcd_DataDir_port . lcdD2 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD3 ) ;   // [lcd_DataDir_port . lcdD3 ] - [input]
#else
    lcd_DataDir_port = 0 ;            // [lcd_DataDir_port] - [input]
#endif
  } /* SetInputDataBus */

w zależności od parametru lcd_Interf4b (w sensie czy został zdefiniowany czy nie został) zostanie skompilowany jako:

Kod: Zaznacz cały

void SetOutputDataBus ( void )
  {
    lcd_DataDir_port |= 1 << lcdD0 ;      // [lcd_DataDir_port . lcdD0 ] - [output]
    lcd_DataDir_port |= 1 << lcdD1 ;      // [lcd_DataDir_port . lcdD1 ] - [output]
    lcd_DataDir_port |= 1 << lcdD2 ;      // [lcd_DataDir_port . lcdD2 ] - [output]
    lcd_DataDir_port |= 1 << lcdD3 ;      // [lcd_DataDir_port . lcdD3 ] - [output]
  } /* SetOutputDataBus */


void SetInputDataBus ( void )
  {
    lcd_DataDir_port &= ~ ( 1 << lcdD0 ) ;   // [lcd_DataDir_port . lcdD0 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD1 ) ;   // [lcd_DataDir_port . lcdD1 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD2 ) ;   // [lcd_DataDir_port . lcdD2 ] - [input]
    lcd_DataDir_port &= ~ ( 1 << lcdD3 ) ;   // [lcd_DataDir_port . lcdD3 ] - [input]
  } /* SetInputDataBus */

lub

Kod: Zaznacz cały

void SetOutputDataBus ( void )
  {
    lcd_DataDir_port = 0xFF ;         // [lcd_DataDir_port] - [output]
  } /* SetOutputDataBus */


void SetInputDataBus ( void )
  {
    lcd_DataDir_port = 0 ;            // [lcd_DataDir_port] - [input]
  } /* SetInputDataBus */
Do zaprezentowania działania powyższych funkcji posłuży następujący program (dla mikrokontrolera ATmega 8515), który będzie obsługiwał wyświetlacz dwuwierszowy LCD po 40 znaków w wierszu. Program jest następujący:

Kod: Zaznacz cały

(…)
#include <inttypes.h>
#include <avr/io.h>
#include <avr/iom8515.h>
#include <avr/pgmspace.h>
#include "lcdlib.h"

#define nop() __asm__ __volatile__ ("nop")

void LongDelay ( void )
  {
    uint16_t Loop ;
    /*---------------------------------*/
    for ( Loop = 0 ; Loop < 0xF000 ; Loop ++ )
    {
      nop ( ) ;
      nop ( ) ;
      nop ( ) ;
      nop ( ) ;
    } /* for */ ;
  } /* LongDelay */


const unsigned char HelloText1 [ ] PROGMEM = "Czesc, tu Twoj procek ATM8515" ;
const unsigned char HelloText2 [ ] PROGMEM = "z modulem LCD 2*40 znakow." ;


void DemoPause ( void )
  {
    uint8_t Loop ;
    /*---------------------------------*/
    for ( Loop = 0 ; Loop < 20 ; Loop ++ )
      LongDelay ( ) ;
  } /* DemoPause */


int main ( void )
  {
    LongDelay ( ) ;
    LongDelay ( ) ;
    LongDelay ( ) ;
    LongDelay ( ) ;
    InitLCDEnvir ( ) ;
    InitialiseLCD ( ) ;
    ClrScrLCD ( ) ;
    for ( ; ; )
    {
      WriteTextLCDFlash ( HelloText1 ) ;
      DemoPause ( ) ;
      NewLineLCD ( ) ;
      WriteTextLCDFlash ( HelloText2 ) ;
      DemoPause ( ) ;
      ClrScrLCD ( ) ;
      DemoPause ( ) ;
    } /* for */ ;
    return ( 0 ) ;
  } /* main */
Do skompilowania powyższego programu niezbędny jest plik nagłówkowy (lcdequip.h) zawierający szczegóły związane z samym wyświetlaczem i jego przyłączeniem. Przykładowo:

Kod: Zaznacz cały

#ifndef _lcdequip_
#define _lcdequip_

#include <avr/io.h>
#include <avr/iom8515.h>

#define lcd_Interf4b

#define lcd_E_port      PORTA
#define lcd_RW_port      PORTA
#define lcd_RS_port      PORTA
#define lcd_Data_port      PORTA
#define lcd_DataDir_port   DDRA
#define lcd_DataPin_port   PINA
#define lcd_E_Dir_port      DDRA
#define lcd_RS_Dir_port      DDRA
#define lcd_RW_Dir_port      DDRA

#define lcd_E_pin         6
#define lcd_RW_pin      5
#define lcd_RS_pin      4

#define lcdD0         0
#define lcdD1         1
#define lcdD2         2
#define lcdD3         3

#endif
W tym przypadku dwuwierszowy moduł (brak parametru lcd_as1line) jest przyłączony poprzez 4-bitowy interfejs szyny danych (obecność parametru lcd_Interf4b) do portu PORTA (patrz: lcd_Data_port, lcd_DataDir_port i lcd_DataPin_port) do wyprowadzeń PORTA.0, PORTA.1, PORTA.2, PORTA.3 (patrz: lcdD0, lcdD1, lcdD2 i lcdD3). Sygnały sterujące są podłączone następująco: sygnał E do PORTA.6 (patrz: lcd_E_port, lcd_E_Dir_port i lcd_E_pin), sygnał R/W do PORTA.5 (patrz: lcd_RW_port, lcd_RW_Dir_port i lcd_RW_pin) oraz sygnał RS do PORTA.4 (patrz: lcd_RS_port, lcd_RS_Dir_port i lcd_RS_pin).
Efekt działania programu pokazuje poniższa ilustracja.
LCD2_ilu02.jpg
Zmieniając zawartość pliku lcdequip.h do następującej (poniżej), zmianie ulega sposób przyłączenia. Ponownie skompilowany ten sam program (z nową zawartością lcdequip.h) zmienia sposób przyłączenia modułu LCD.
Nowa zawartość pliku opisującego jest następująca:

Kod: Zaznacz cały

#ifndef _lcdequip_
#define _lcdequip_

#include <avr/io.h>
#include <avr/iom8515.h>

#define lcd_E_port      PORTB
#define lcd_RW_port      PORTB
#define lcd_RS_port      PORTB
#define lcd_Data_port      PORTA
#define lcd_DataDir_port   DDRA
#define lcd_DataPin_port   PINA
#define lcd_E_Dir_port      DDRB
#define lcd_RS_Dir_port      DDRB
#define lcd_RW_Dir_port      DDRB

#define lcd_E_pin         0
#define lcd_RW_pin      1
#define lcd_RS_pin      2

#endif
Oznacza to, że moduł LCD jest przyłączony z interfejsem 8-bitowym do PORTA (cały port), oraz sygnały sterujące są przyłączone do:
  • sygnał E – PORTB.0 (lcd_E_port, lcd_E_Dir_port i lcd_E_pin),
  • sygnał R/W – PORTB.1 (lcd_RW_port, lcd_RW_Dir_port i lcd_RW_pin),
  • sygnał RS – PORTB.2 (lcd_RS_port , lcd_RS_Dir_port i lcd_RS_pin).
Efekt działania programu jest identyczny.

Załącznik: przykładowy program w języku C
avrc_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 21:10

Sterowanie modułów wyświetlaczy alfanumerycznych LCD w systemach z mikrokontrolerami ARM

przykład programu w języku C dla mikrokontrolera LPC2378

LCD3_ilu00.jpg


w każdym systemie zawierającym jakikolwiek mikroprocesor lub mikrokontroler użycie modułów wyświetlaczy LCD sprowadza się do odpowiedniego przyłączenia modułu (temat o charakterze hardware'owym) oraz do właściwego oprogramowania mikrokontrolera (temat o charakterze software'owym). Jak wiadomo moduł (zawierający sterownik HD44780) wymaga przyłączenia i odpowiedniego sterowania kilku sygnałów sterujących i szyny danych, po której mikrokontroler będzie przesyłał do modułu odpowiednie polecenia i dane do wyświetlenia. Poniższe rozważania dotyczą użycia 32-bitowego mikrokontrolera z rodziny ARM (dokładnie układ o symbolu LPC2378 produkowany przez firmę NXP wywodzącą się z firmy Philips).
LCD3_ilu01.jpg
Samo przyłączenie (z elektronicznego punktu widzenia) nie jest zagadnieniem niezwykłym. Jak w większości przypadków, tu również, odpowiednie sygnały modułu wyświetlacza LCD zostały przyłączone do wyprowadzeń jednego portu mikrokontrolera (portu P1). Moduł pracuje z 4-bitowym interfejsem szyny danych i z możliwością odczytu statusu (sygnał R/W jest aktywnie sterowany z mikrokontrolera). Szczegóły są następujące:
  • sygnał E – wyprowadzenie portu P1.31 (port P1 bit 31),
  • sygnał R/W – wyprowadzenie portu P1.29 (port P1 bit 29),
  • sygnał RS – wyprowadzenie portu P1.28 (port P1 bit 28),
  • sygnał DB4 – wyprowadzenie portu P1.24 (port P1 bit 24),
  • sygnał DB5 – wyprowadzenie portu P1.25 (port P1 bit 25),
  • sygnał DB6 – wyprowadzenie portu P1.26 (port P1 bit 26),
  • sygnał DB7 – wyprowadzenie portu P1.27 (port P1 bit 27).
Algorytm sterowania modułu LCD jest cechą modułu i jest niezależny od użytego mikrokontrolera. Rozpatrując zapis instrukcji programu w języku C można zauważyć podobieństwa rozwiązań użytych dla mikrokontrolerów o innej architekturze. Nie ma w tym nic niezwykłego, gdyż cel programu, jakim jest wyświetlanie informacji na ekranie jest ten sam a to prowadzi do identycznego algorytmu. Dopiero “styk elektroniki i programowania” nabiera znaczenia w różnych rozwiązaniach (zarówno w różnych typach [architekturach] mikrokontrolerów jak i różnych wariantach przyłączenia w obrębie jednego modelu [architektury]). Warto zauważyć, że mikrokontrolery z rodziny ARM mają ciekawe rozwiązania pozwalające na uelastycznienie w programie wynikające z elektronicznego rozwiązania. Sam algorytm sterowania wyświetlaczem (czyli co i w jakiej kolejności wysłać do LCD'ka) nie jest tak interesujący jak “programowe” nadążanie za “elektroniką”. Obsługa wyświetlacza (szczególnie po kilku różnych implementacjach) sprowadza się w sumie do elastycznego oprogramowania samego styku z elektroniką. Warto sobie opracować taki wariant oprogramowania, który w łatwy sposób da się adaptować do innych sprzętowych rozwiązań i nie będzie to wymagało “rewolucji” w oprogramowaniu. Poniższy przykład stanowi wystarczające uelastycznienie w programie pozwalające oprogramować dowolny sprzętowy wariant spełniający wcześniej określone wymagania (dowolne przyłączenie do portu P1 z 4-bitowym interfejsem szyny danych i możliwością odczytu statusu z modułu LCD). Poniższy fragment programu określa szczegóły przyłączenia modułu wyświetlacza:

Kod: Zaznacz cały

(…)
             
#include <LPC23xx.H>

/*****************************************************
 *        Specyfikacja sprzetowa                     *
 *****************************************************/

/* PINS:
   - DB4 = P1.24
   - DB5 = P1.25
   - DB6 = P1.26
   - DB7 = P1.27
   - E   = P1.31
   - RW  = P1.29
   - RS  = P1.28
*/

#define lcd_E_pin     31
#define lcd_RW_pin    29
#define lcd_RS_pin     28
#define lcd_DB0_pin   24
#define lcd_DB1_pin   25
#define lcd_DB2_pin   26
#define lcd_DB3_pin   27


#define PIN_E     ( ( unsigned int ) 1 << lcd_E_pin )
#define PIN_RW    ( ( unsigned int ) 1 << lcd_RW_pin )
#define PIN_RS    ( ( unsigned int ) 1 << lcd_RS_pin )
#define PINS_CTRL PIN_E | PIN_RW | PIN_RS
#define PINS_DATA ((unsigned int)1<<lcd_DB0_pin|(unsigned int)1<<lcd_DB1_pin|(unsigned int)1<<lcd_DB2_pin|(unsigned int)1<<lcd_DB3_pin)

#define lcdEstrobeh           IOSET1 = PIN_E
#define lcdEstrobel           IOCLR1 = PIN_E
#define lcdRWstrobeh          IOSET1 = PIN_RW
#define lcdRWstrobel          IOCLR1 = PIN_RW
#define lcdRSstrobeh          IOSET1 = PIN_RS
#define lcdRSstrobel          IOCLR1 = PIN_RS
#define lcdOutputControlBus   IODIR1 |= PINS_CTRL
#define lcdInputDataBus       IODIR1 &= ~ PINS_DATA
#define lcdOutputDataBus      IODIR1 |= PINS_DATA

Powyższe definicja stałych "rozchodzą się po trzewiach programu" wpływając na sterowanie modułem LCD. Przykładowo:

Kod: Zaznacz cały

void LCDOut4bit ( unsigned char Data )
{
  unsigned int PortPins = 0 ;
  /*-------------------------------------------*/
  lcdRWstrobel ;
  IOCLR1 = PINS_DATA ;
  if ( Data & 0x08 )
    PortPins |= ( unsigned int ) 1 << lcd_DB3_pin ;
  if ( Data & 0x04 )
    PortPins |= ( unsigned int ) 1 << lcd_DB2_pin ;
  if ( Data & 0x02 )
    PortPins |= ( unsigned int ) 1 << lcd_DB1_pin ;
  if ( Data & 0x01 )
    PortPins |= ( unsigned int ) 1 << lcd_DB0_pin ;
  IOSET1 = PortPins ;
  lcdEstrobeh ;
  delay ( 10 ) ;
  lcdEstrobel ;
  delay ( 10 ) ;
} /* LCDOut4bit */

Program prezentujący obsługę wyświetlacza jest następujący:

Kod: Zaznacz cały

unsigned char HelloMessage [ ] = ">>> Prezentacja obslugi modulu LCD dla procesorow ARM (LPC2378) <<<<         " ;
unsigned short MessageBase ;

#define LineWidth     16

void DispMessage ( void )
{
  int Loop ;
  unsigned char * CurrCh ;
  /*-------------------------------------------*/
  HomeLCD ( ) ;
  CurrCh = HelloMessage + MessageBase ;
  if ( ! ( * CurrCh ) )
  {
    MessageBase = 0 ;
    CurrCh = HelloMessage ;
  } /* if */ ;
  for ( Loop = 0 ; Loop < LineWidth ; Loop ++ )
  {
    WriteChLCD ( * CurrCh ) ;
   CurrCh ++ ;
   if ( ! ( * CurrCh ) )
      CurrCh = HelloMessage ;
  } /* for */ ;
  MessageBase ++ ;
} /* DispMessage */


int main (void)
{
  HardwareInit ( ) ;
  EnvirInit ( ) ;
  SoftInit ( ) ;
  while ( ! TimeEvent )
  {
  } /* while */ ;
  TimeEvent = 0 ;
  InitialiseLCD ( ) ;
  ClrScrLCD ( ) ;
  SetCursorPos ( 0 , 1 ) ;
  WriteTextLCD ( "MCB2300->LPC2378" ) ;
  MessageBase = 0 ;
  for ( ; ; )
  {
    if ( TimeEvent )
   {
      TimeEvent = 0 ;
      DispMessage ( ) ;
    } /* if */ ;
  } /* loop */ ;
} /* main */
Efekt działania powyższego programu prezentuje fotografia (przewijający się w pierwszym wierszu długi napis).
LCD3_ilu02.jpg
Program został skompilowany w środowisku μVision3, który można pobrać jako wersję demo ze strony http://www.keil.com.

Załącznik: prezentowany program
arm_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 21:19

Użycie modułu LCD w systemie z mikrokontrolerem z rodziny C51

lcd51_f00.jpg


Większość istniejących mikrokontrolerów posiada wystarczające zasoby do przyłączenia typowego modułu LCD, co sprowadza się do tego, by mikrokontroler zawierał pewną liczbę wyprowadzeń indywidualnie sterowanych. Najpopularniejszym sterownikiem, czyli układem pośredniczącym pomiędzy mikrokontrolerem a samą matrycą wyświetlacza, jest układ HD44780. Moduł wyświetlacza LCD (ze sterownikiem HD44780) może być przyłączony do mikrokontrolera na kilka sposobów. Poniższy przykład prezentuje wariant z użyciem 4-bitowej szyny danych do modułu. Schemat połączeń przedstawia ilustracja 1.
Lcd51_f01.png
Z rysunku wynika, że:
  • sygnał RS modułu LCD jest przyłączony do wyprowadzenia P1.0 mikrokontrolera,
  • sygnał R/W modułu LCD jest przyłączony do wyprowadzenia P1.1 mikrokontrolera,
  • sygnał E modułu LCD jest przyłączony do wyprowadzenia P1.2 mikrokontrolera,
  • szyna DB danych modułu LCD jest przyłączony do wyprowadzeń od P1.4 do P1.7 mikrokontrolera (jako przyłączenie poprzez 4-bitowy interfejs szyny).
Łatwo zauważyć, że powyższy przykład wymaga siedmiu sygnałów sterujących. Zbudowane w oparciu o ten schemat prototypowe urządzenie pokazane jest na ilustracji 2.
lcd51_r02.jpg
Istotnym elementem oprogramowania jest sposób parametryzacji samego przyłączenia modułu LCD (uzyskanie w programie możliwości prostej metody “zmiany sposobu przyłączenia”). Przykład programu jest następujący (we fragmentach):

Kod: Zaznacz cały

(…)
;
LCD_E           EQU     P1.2
LCD_RW          EQU     P1.1
LCD_RS          EQU     P1.0
;
LCD_DB7         EQU     P1.7
LCD_DB6         EQU     P1.6
LCD_DB5         EQU     P1.5
LCD_DB4         EQU     P1.4
;

Kod: Zaznacz cały

LCDInC:                                         ;PROCEDURE LCDInC ( VAR A : BYTE ) ;
;****************                               ;BEGIN (* LCDInC *)
                PUSH    B                       ;
                MOV     A , P1                  ;
                ORL     A , # 0F0H              ;
                MOV     P1 , A                  ;
                CLR     LCD_RS                  ; [RS=0]
                SETB    LCD_RW                  ; [R/W=1]
                SETB    LCD_E                   ; [E=1]
                MOV     C , LCD_DB7             ; A := [LCD] ;
                MOV     ACC.7 , C               ;
                MOV     C , LCD_DB6             ;
                MOV     ACC.6 , C               ;
                MOV     C , LCD_DB5             ;
                MOV     ACC.5 , C               ;
                MOV     C , LCD_DB4             ;
                MOV     ACC.4 , C               ;
                CLR     LCD_E                   ; [E=0]
                ANL     A , # 0F0H              ;
                MOV     B , A                   ;
                SETB    LCD_E                   ; [E=1]
                MOV     C , LCD_DB7             ; A := [LCD] ;
                MOV     ACC.7 , C               ;
                MOV     C , LCD_DB6             ;
                MOV     ACC.6 , C               ;
                MOV     C , LCD_DB5             ;
                MOV     ACC.5 , C               ;
                MOV     C , LCD_DB4             ;
                MOV     ACC.4 , C               ;
                CLR     LCD_E                   ; [E=0]
                ANL     A , # 0F0H              ;
                SWAP    A                       ;
                ORL     A , B                   ;
                POP     B                       ;
                RET                             ;END (* LCDInC *) ;
Po zaprogramowaniu mikrokontrolera 89C51 wygenerowanym przez kompilator kodem, uruchomienie systemu daje efekt pokazany na ilustracji 3 (efekt przewijania na ekranie wyświetlacza długiego napisu).
lcd51_r03.jpg


Załącznik: programw ASM dla mikrokontrolera C51
c51_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 21:27

Moduły czterowierszowych wyświetlaczy alfanumerycznych LCD w systemach z mikrokontrolerami AVR

lcd4l_f02.jpg


Są dwa różne rozwiązania modułów wyświetlaczy LCD pozwalających na wyświetlanie informacji w czterech wierszach, które bazują na rozwiązaniu sterowników kompatybilnych z układem HD44780. W jednym z rozwiązań każdy wiersz (będący buforem w układzie HD44780 przechowującym wyświetlany tekst: w przedziale 0x00 .. 0x27 – pierwszy wiersz oraz 0x40 .. 0x67 – drugi wiersz) jest podzielony i wyświetlany jako dwa wiersze. Drugi wariant zawiera dwa sygnały Enable (tak jakby to były dwa moduły w jednym). Mając na uwadze, że wymieniony standard pozwala na wyświetlanie informacji w maksymalnie dwóch wierszach po czterdzieści znaków w wierszu, można wysnuć wniosek, że powyższy “chwyt” zawęża możliwości modułu do wyświetlania informacji w czterech wierszach z maksymalnie dwudziestoma znakami w wierszu.
lcd4l_f01.jpg
W istocie, użyty do prezentacji moduł (pokazany na powyższej fotografii o symbolu EW20400) ma takie parametry techniczne. Z dokumentacji technicznej wynika, że sposób i znaczenie poszczególnych wyprowadzeń jest identyczny jak w popularnych wyświetlaczach dwuwierszowych. Opis złącza, sposób przyłączenia do mikrokontrolera oraz znaczenie poleceń sterujących jest opisane w wielu innych dokumentach (i nie będzie tu powielane).
Do implementacji programowej obsługi istotna jest jedynie informacja określająca sposób przyporządkowania adresów w pamięci danych kontrolera LCD poszczególnym wierszom na ekranie wyświetlacza. Kolejne wiersze (na ekranie) nie są przyporządkowane kolejnym (rosnącym) adresom w pamięci. Pierwszy wiersz na ekranie ma typowy adres w pamięci zaczynający się od wartości 0x00. Po wyświetleniu 20-u znaków w pierwszym wierszu, kolejne znaki są wyświetlane w wierszu trzecim. Ta trochę przykra niespodzianka wynika ze sposobu podziału pamięci danych w kontrolerze modułu LCD na poszczególne wiersze na ekranie.
Podział jest następujący:
  • wiersz numer 1 – obszar w pamięci w przedziale: 0x00 .. 0x13,
  • wiersz numer 2 – obszar w pamięci w przedziale: 0x40 .. 0x53,
  • wiersz numer 3 – obszar w pamięci w przedziale: 0x14 .. 0x27,
  • wiersz numer 3 – obszar w pamięci w przedziale: 0x54 .. 0x67.
Problemy wynikające z “przeplotu” wierszy można rozwiązać w sposób programowy. Jeżeli w programie powołać dwie zmienne, których zadaniem będzie przechowywanie aktualnej pozycji kursora, możliwe stanie się nieskomplikowane programowe przechodzenie do następnego wiersza. Przykładowa implementacja jest przedstawiona niżej (mikrokontroler ATMEGA8515). Moduł jest przyłączony poprzez 8-bitowy interfejs szyny danych do portu A oraz sygnały sterujące są przyłączone do:
  • sygnał E – port B, bit 4
  • sygnał R/W – port B, bit 2
  • sygnał RS – port B, bit 0
W programie sposób “elektronicznego przyłączenia” jest sparametryzowany i zmieniając odpowiednie stałe możliwe jest oprogramowanie innych wariantów sprzętowych.

Kod: Zaznacz cały

.equ    lcd_E_port      = PORTB
.equ    lcd_E_pin       = 4
.equ    lcd_RW_port     = PORTB
.equ    lcd_RW_pin      = 2
.equ    lcd_RS_port     = PORTB
.equ    lcd_RS_pin      = 0
.equ    lcd_Data_port   = PORTA
;-----------------------------------------------------------------------------
;       Obsluga wyswietlaczy LCD uzywa nastepujacych parametrow:
;
;       lcd_E_port      - okresla port, do ktorego przylaczony jest
;                         sygnal E modulu LCD
;       lcd_E_pin       - okresla pin w porcie okreslonym przez lcd_E_port
;                         do ktorego przylaczony jest sygnal E modulu LCD
;       lcd_RS_port     - okresla port, do ktorego przylaczony jest
;                         sygnal RS modulu LCD
;       lcd_RS_pin      - okresla pin w porcie okreslonym przez lcd_RS_port
;                         do ktorego przylaczony jest sygnal RS modulu LCD
;       lcd_RW_port     - okresla port, do ktorego przylaczony jest
;                         sygnal RW modulu LCD
;       lcd_RW_pin      - okresla pin w porcie okreslonym przez lcd_RW_port
;                         do ktorego przylaczony jest sygnal RW modulu LCD
;       lcd_Data_port   - okresla port, do ktorego przylaczona jest
;                         szyna danych modulu LCD; w przypadku interfejsu
;                         8-bitowego szyna danych modulu LCD jest szyna danych
;                         portu (odpowiadajace sobie bity maja te same numery);
;                         w przypadku interfejsu 4-bitowego istnieje możliwosc
;                         dowolnego okreslenia (w obrebie jednego portu)
;                         przyporzadkowania bitow szyny danych modulu LCD i
;                         portu danych,
;-----------------------------------------------------------------------------
.equ lcd_DataDir_port   = lcd_Data_port - 1
.equ lcd_DataPin_port   = lcd_Data_port - 2
.equ lcd_E_Dir_port     = lcd_E_port - 1
.equ lcd_RS_Dir_port    = lcd_RS_port - 1
.equ lcd_RW_Dir_port    = lcd_RW_port - 1
;-----------------------------------------------------------------------------

Efekt działania powyższego programu pokazuje ilustracja 2.
lcd4l_f00.jpg


Załącznik: prezentowany program:
lcd_4l_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [HD44780]Moduły LCD

Postautor: gaweł » sobota 27 sty 2018, 22:12

Użycie modułów wyświetlaczy alfanumerycznych LCD
w systemach z mikrokontrolerami AVR
w przestrzeni adresowej zewnętrznej pamięci RAM

przykłady programu w języku C


lcdxavr_f00.jpg


Jest to w pewnym sensie już jakaś ekstrawagancja, gdyż nie spotyka się tego typu rozwiązań. W pewnym sensie wnosi to drobne problemy techniczne, gdyż należy moduł LCD traktować jako bardzo powolną komórkę pamięci, więc do cykli sterujących należy dodawać wait state'y oraz nie bardzo nadaje się do mikrokontrolerów o dużej częstotliwości taktowania. Z drugiej strony nie należy się ograniczać jedynie do utartych ścieżek (wędrówka po bezdrożach jest równie ciekawa). Jak mówi pewne powiedzenie: Jak dadzą Ci papier w linie, to pisz w poprzek. Do odważnych świat należy, więc "może warto sprawdzić, co jest za tą górą".

Użycie modułu wyświetlacza LCD, który jest w typowy sposób przyłączony do mikrokontrolera w przestrzeni adresowej przeznaczonej dla zewnętrznej pamięci RAM może wiązać się z kłopotami (a z pewnością jest nietypowy, co nie znaczy niemożliwy). Wynikają one ze zbyt krótkiego czasu trwania impulsu strobu generowanego przez mikrokontroler. Czas trwania tego impulsu jest zależny od częstotliwości impulsów taktujących pracą mikrokontrolera. Przy odpowiednio małej częstotliwości można uzyskać wystarczającą długość czasu trwania tego impulsu, ale jednocześnie znacząco zwalnia to szybkość, z jaką pracuje mikrokontroler. Poniższe rozważania stanowią próbę pogodzenia ze sobą tych sprzecznych cech. Typowym rozwiązaniem przyłączenia modułu LCD do mikrokontrolera jest użycie jego portów równoległych. Odpowiednio sterując wyprowadzeniami portów przesyłane są do modułu informacje sterujące pracą samego wyświetlacza oraz dane jakie mają być tam wyświetlone. Wykonanie programu “może w pełni świadomości” wpływać na sposób generowania i czas trwania impulsów aktywujących moduł wyświetlacza LCD. Jeżeli tego rodzaju sterowanie modułem LCD nie stwarza problemów, to można pokusić się “przeniesienie” lokalizacji komórki (do której przyłączony jest moduł LCD) w przestrzeni adresowej pamięci RAM w takie miejsce, które odpowiada zewnętrznej pamięci RAM. Dysponując jedną komórką (rejestrem), moduł LCD zostaje przyłączony za pomocą 4-bitowego interfejsu szyny danych.
Ilustracja 1 (schemat przyłączenia) przedstawia ideę rozwiązania.
W przestrzeni zewnętrznej pamięci RAM zlokalizowany jest rejestr (U4 – 74HCT574) spełniający rolę “przeniesionego” portu. Do jego wyjść przyłączony jest moduł LCD w następujący sposób:
  • sygnał E – bit 6 rejestru,
  • sygnał R/W – bit 5 rejestru,
  • sygnał RS – bit 4 rejestru,
  • sygnały szyny danych – bity 0, 1, 2, 3 rejestru.
LCDX_ilu01.png
Analizując rozwiązanie dekodera adresowego (układ U5 – 74HCT138 i U6 – 74HCT00) można zauważyć, że rejestr (U4 – 74HCT574) jest aktywowany przy próbie odczytu lub zapisu komórki przykładowo o adresie 1000 hex w przestrzeni adresowej pamięci RAM (uproszczony dekoder adresowy aktywuje rejestr U4 dla wielu innych wartości adresu komórki w pamięci i wymieniony adres [1000 hex] należy uważać za jeden z wielu możliwych). Ograniczając się do użycia w przestrzeni RAM jedynie modułu LCD możliwe są znaczące uproszczenia sprzętowe. Zakładając wykonywanie tylko operacji zapisu do modułu LCD można pominąć bramkę NAND oraz rejestr młodszej części szyny adresowej (U2 – 74HCT573) a do dekodera adresowego doprowadzić linie adresowe należące do górnej części szyny adresowej (co jedynie zmieni położenie rejestru U4 w przestrzeni adresowej). W skrajnym przypadku do aktywacji rejestru U4 można użyć sygnału /WR (co będzie oznaczało, że rejestr modułu LCD [U4] będzie widziany pod każdym adresem przeznaczonym na zewnętrzną pamięć RAM).
Koncepcja rozwiązania programowego zagadnienia obsługi modułu LCD w środowisku sprzętowym opiera się o:
  • bibliotekę procedur obsługi (lcdxlib.h i lcdxlib.c),
  • nagłówek określający istotne cechy rozwiązania sprzętowego i użytego modułu (lcdxequip.h).
W zbiorze nagłówkowym lcdxequip.h należy określić następujące parametry:
  • V1x16_as_2x8 – określa, czy użyty jest moduł wyświetlający jeden wiersz z 16-oma znakami, który należy obsługiwać jako wyświetlacz dwuwierszowy po 8 znaków w wierszu (istotny jest fakt definicji parametru),
  • lcd_as1line – określa użycie wyświetlacza jednowierszowego,
  • LCDPortAddress – określa adres rejestru U4 w przestrzeni adresowej pamięci RAM.
Cały moduł wyświetlacza jest widziany przez mikrokontroler jako określona komórka pamięci zewnętrznej. Rzecz jasna, ta komórka jest identyfikowana przez jakiś adres, więc pierwszą informacją do sparametryzowania jest wartość adresu owej komórki. Kolejną kwestią jest parametryzacja dotycząca przyporządkowania poszczególnych bitów tej komórki do wyprowadzeń samego modułu LCD. Rzecz jasna, warto zadbać o elastyczność w każdym swoim działaniu, toteż (rozłożenie poszczególnych bitów w komórce pamięci będącej w rzeczywistości modułem LCD, czyli mówimy: pamięć RAM, a myślimy: moduł LCD; takie: gadał ślepy z głuchym o kolorach) funkcja poszczególnych bitów jest następująca):

Kod: Zaznacz cały

#define lcd_E_pin 6
#define lcd_RW_pin 5
#define lcd_RS_pin 4
#define lcdD0 0
#define lcdD1 1
#define lcdD2 2
#define lcdD3 3

Inna istotna parametryzacja (o czym wspomniałem wyżej):

Kod: Zaznacz cały

#define LCDPortAddress 0x1000
W sprzętowej obsłudze jest zaimplementowana jedynie operacja zapisu do "komórki LCD" (nie ma możliwości jej odczytu). "Machając" pinami sterującymi modułu LCD, by "nie zepsuć" szyny danych, potrzebna będzie "kopia" tej komórki w standardowej pamięci RAM.

Kod: Zaznacz cały

static uint8_t LCDXPortData ;
W tym układzie przykładowo operacja wygenerowania impulsu na linii E może wyglądać następująco:

Kod: Zaznacz cały

void EPulse ( void )
  {
    volatile uint8_t * XLCDPort ;
    /*---------------------------------*/
    XLCDPort = ( uint8_t * ) LCDPortAddress ;
    LCDXPortData |= 1 << lcd_E_pin ;      // [E=1]
    * XLCDPort = LCDXPortData ;
    LCDDelay ( ) ;
    LCDXPortData &= ~ ( 1 << lcd_E_pin ) ;   // [E=0]
    * XLCDPort = LCDXPortData ;
  } /* EPulse */

Przykładowy program używający powyższego zestawu procedur jest następujący:

Kod: Zaznacz cały

#include <inttypes.h>
#include <avr/io.h>
#include <avr/iom8515.h>
#include <avr/pgmspace.h>
#include "lcdxlib.h"

#define nop() __asm__ __volatile__ ("nop")

void LongDelay ( void )
  {
    uint16_t Loop ;
    /*---------------------------------*/
    for ( Loop = 0 ; Loop < 0xF000 ; Loop ++ )
    {
      nop ( ) ;
      nop ( ) ;
      nop ( ) ;
      nop ( ) ;
    } /* for */ ;
  } /* LongDelay */


const unsigned char HelloText1 [ ] PROGMEM = "Czesc, tu Twoj procek ATM8515 z modulem" ;
const unsigned char HelloText2 [ ] PROGMEM = "LCD 2*40 znakow (z portem w XRAM)." ;


void DemoPause ( void )
  {
    uint8_t Loop ;
    /*---------------------------------*/
    for ( Loop = 0 ; Loop < 20 ; Loop ++ )
      LongDelay ( ) ;
  } /* DemoPause */


int main ( void )
  {
    MCUCR = 0x80 ;   // SRE : External SRAM Enable
    LongDelay ( ) ;
    LongDelay ( ) ;
    LongDelay ( ) ;
    LongDelay ( ) ;
    InitLCDEnvir ( ) ;
    InitialiseLCD ( ) ;
    ClrScrLCD ( ) ;
    for ( ; ; )
    {
      WriteTextLCDFlash ( HelloText1 ) ;
      DemoPause ( ) ;
      NewLineLCD ( ) ;
      WriteTextLCDFlash ( HelloText2 ) ;
      DemoPause ( ) ;
      ClrScrLCD ( ) ;
      DemoPause ( ) ;
    } /* for */ ;
    return ( 0 ) ;
  } /* main */

Uruchomienie powyższego programu w opisanym środowisku sprzętowym daje następujący efekt:
lcdxavr_f03.jpg


Załącznik: prezentowany program w języku C
avrx_example.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „Inne mikroklocki, również peryferyjne”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości