W tym poście opiszę sposób obsługi wyświetlacza ze sterownikiem HD44780. Program został wykonany i przetestowany na płytce STM32 Discovery.
Wstęp
Wyświetlacz alfanumeryczny LCD ze sterownikiem Hitachi HD44780 pozwala na obsługę dwóch wielkości ekrany 2x16 albo 4x20. Każdy ze znaków jest w rozmiarze 5x8 pikseli.
Komunikacja może odbywać się w trybie 4 bądź 8 bitowym. Przeważnie wykorzystuje się komunikację 4 bitową, ponieważ oszczędza ona linie wejścia/wyjścia a pozwala na zrealizowanie tych samych funkcji.
Wyświetlacz posiada zapamiętane wartości znaków w kodzie ASCII w pamięci ROM. Dzięki temu w celu wyświetlenia konkretnego znaku wystarczy przesłać jego kod, a nie sam znak. Jeśli potrzebny jest znak z poza znaków ASCII, istnieje możliwość zdefiniowana własnego ciągu, maksymalnie ośmiu wzorców.
Wyświetlacz posiada zapamiętane wartości znaków w kodzie ASCII w pamięci ROM. Dzięki temu w celu wyświetlenia konkretnego znaku wystarczy przesłać jego kod, a nie sam znak. Jeśli potrzebny jest znak z poza znaków ASCII, istnieje możliwość zdefiniowana własnego ciągu, maksymalnie ośmiu wzorców.
Rys. 1. Wygląd zewnętrzny wyświetlacza
Podłączenie
Wyświetlacz należy podłączyć do następujących wyprowadzeń:
- VSS - GND
- VDD - 5V
- V0 - Kontrast do potencjometru
- RS - Liniar Register Select - GPIOB2
- RW - Read/Write - GND, wymuszenie cały czas stanu niskiego, wpisujemy tylko dane na wyświetlacz
- E - Enable - GPIOB7
- D0-D3 - linie danych nie podłączone
- D4 - linia danych - GPIOC12
- D5 - linia danych - GPIOC13
- D6 - linia danych - GPIOC14
- D7 - linia danych - GPIOC15
- A - podświetlenie wyświetlacza, można podłączyć do potencjometru, na stałe do 3V, bądź np. sterować wypełnieniem sygnału
- K - GND podświetlenia
Opis poszczególnych wyprowadzeń wyświetlacza:
Rys. 2. Pinout wyświetlacza [radzio.dxp.pl]
Poniżej przedstawię sposób inicjalizacji wyświetlacza oraz ustawienia wszystkich niezbędnych parametrów oraz funkcji.
Programowanie
Przed przystąpieniem do programowania należy zapoznać się z wartościami oraz funkcjami poszczególnych rejestrów sterownika wyświetlacza:
//Komendy
#define HD44780_CLEARDISPLAY 0x01
#define HD44780_RETURNHOME 0x02
#define HD44780_ENTRYMODESET 0x04
#define HD44780_DISPLAYCONTROL 0x08
#define HD44780_CURSORSHIFT 0x10
#define HD44780_FUNCTIONSET 0x20
#define HD44780_SETCGRAMADDR 0x40
#define HD44780_SETDDRAMADDR 0x80
//Flagi dla wyświetlania danych przychodzących
#define HD44780_ENTRYRIGHT 0x00
#define HD44780_ENTRYLEFT 0x02
#define HD44780_ENTRYSHIFTINCREMENT 0x01
#define HD44780_ENTRYSHIFTDECREMENT 0x00
//Flagi do wyświetlania włączenia/wyłączenia wyświetlacza
#define HD44780_DISPLAYON 0x04
#define HD44780_CURSORON 0x02
#define HD44780_BLINKON 0x01
//Flagi dla przesunięc kursora
#define HD44780_DISPLAYMOVE 0x08
#define HD44780_CURSORMOVE 0x00
#define HD44780_MOVERIGHT 0x04
#define HD44780_MOVELEFT 0x00
//Flagi dla ustawienia poszczegolnych trybów pracy wyświetlacza
#define HD44780_8BITMODE 0x10
#define HD44780_4BITMODE 0x00
#define HD44780_2LINE 0x08
#define HD44780_1LINE 0x00
#define HD44780_5x10DOTS 0x04
#define HD44780_5x8DOTS 0x00
Inicjalizacja
//Komendy #define HD44780_CLEARDISPLAY 0x01 #define HD44780_RETURNHOME 0x02 #define HD44780_ENTRYMODESET 0x04 #define HD44780_DISPLAYCONTROL 0x08 #define HD44780_CURSORSHIFT 0x10 #define HD44780_FUNCTIONSET 0x20 #define HD44780_SETCGRAMADDR 0x40 #define HD44780_SETDDRAMADDR 0x80 //Flagi dla wyświetlania danych przychodzących #define HD44780_ENTRYRIGHT 0x00 #define HD44780_ENTRYLEFT 0x02 #define HD44780_ENTRYSHIFTINCREMENT 0x01 #define HD44780_ENTRYSHIFTDECREMENT 0x00 //Flagi do wyświetlania włączenia/wyłączenia wyświetlacza #define HD44780_DISPLAYON 0x04 #define HD44780_CURSORON 0x02 #define HD44780_BLINKON 0x01 //Flagi dla przesunięc kursora #define HD44780_DISPLAYMOVE 0x08 #define HD44780_CURSORMOVE 0x00 #define HD44780_MOVERIGHT 0x04 #define HD44780_MOVELEFT 0x00 //Flagi dla ustawienia poszczegolnych trybów pracy wyświetlacza #define HD44780_8BITMODE 0x10 #define HD44780_4BITMODE 0x00 #define HD44780_2LINE 0x08 #define HD44780_1LINE 0x00 #define HD44780_5x10DOTS 0x04 #define HD44780_5x8DOTS 0x00
Rozpoczęcia programowania całego wyświetlacza należy rozpocząć od aktywacji jego pinów.
//Inicjalizacja pinów wyswietlacza void HD44780_InitPins(void) { GPIO_InitTypeDef GPIOINIT; //Wlaczenie zegarów dla poszczególnych pinów RCC_AHB1PeriphClockCmd(HD44780_RS_RCC | HD44780_E_RCC, ENABLE); RCC_AHB1PeriphClockCmd(HD44780_D4_RCC | HD44780_D5_RCC, ENABLE); RCC_AHB1PeriphClockCmd(HD44780_D6_RCC | HD44780_D7_RCC, ENABLE); //RS GPIOINIT.GPIO_Pin = HD44780_RS_PIN; //Pin jako wyjście GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; //Typ pushPull GPIOINIT.GPIO_OType = GPIO_OType_PP; //bez podciągnięcia GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; //100MHz taktowanie GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_RS_PORT, &GPIOINIT); //Po inicjalizacji stan niski na wszystkie linie w celu zresetowania układu GPIO_WriteBit(HD44780_RS_PORT, HD44780_RS_PIN, 0x00); //E GPIOINIT.GPIO_Pin = HD44780_E_PIN; GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; GPIOINIT.GPIO_OType = GPIO_OType_PP; GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_E_PORT, &GPIOINIT); GPIO_WriteBit(HD44780_E_PORT, HD44780_E_PIN, 0x00); //D4 GPIOINIT.GPIO_Pin = HD44780_D4_PIN; GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; GPIOINIT.GPIO_OType = GPIO_OType_PP; GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_D4_PORT, &GPIOINIT); GPIO_WriteBit(HD44780_D4_PORT, HD44780_D4_PIN, 0x00); //D5 GPIOINIT.GPIO_Pin = HD44780_D5_PIN; GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; GPIOINIT.GPIO_OType = GPIO_OType_PP; GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_D5_PORT, &GPIOINIT); GPIO_WriteBit(HD44780_D5_PORT, HD44780_D5_PIN, 0x00); //D6 GPIOINIT.GPIO_Pin = HD44780_D6_PIN; GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; GPIOINIT.GPIO_OType = GPIO_OType_PP; GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_D6_PORT, &GPIOINIT); GPIO_WriteBit(HD44780_D6_PORT, HD44780_D6_PIN, 0x00); //D7 GPIOINIT.GPIO_Pin = HD44780_D7_PIN; GPIOINIT.GPIO_Mode = GPIO_Mode_OUT; GPIOINIT.GPIO_OType = GPIO_OType_PP; GPIOINIT.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(HD44780_D7_PORT, &GPIOINIT); GPIO_WriteBit(HD44780_D7_PORT, HD44780_D7_PIN, 0x00); }
Kolejnym elementem jest włączenie wyświetlacza. Wykonuje się to w następujący sposób. Po inicjalizacji pinów należy podać stan 0 na wszystkie linie. Pin R/W jest na stałe ustawiony do masy, oznacza to, że do wyświetlacza można dokonywać tylko zapis. Stan 1 na tej linii pozwoli na odczytywanie danych przez mikrokontroler z jego sterownika.
Po skonfigurowaniu wszystkich linii należy odczekać co najmniej 40 ms zanim rozpocznie się wysyłanie danych do sterownika. Następnie należy wysłać komendę 0011 czyli 0x03, po jej wysłaniu trzeba odczekać co najmniej 4,1ms. Kolejnym krokiem jest wysłanie 0x03 i odczekanie 100us. Na samym końcu należy wysłać ostatni raz wartość 0x03. W dalszej części można się już komunikować ze sterownikiem. Wobec tego w kolejnym kroku wybiera się tryb transmisji, w moim przypadku 4 bitowy. Następnie wybiera się sposób wyświetlania, włącza się wyświetlacz, czyści się go, oraz ustawia parametry domyślne czcionek.
//Funkcja inicjalizacja wyswietlacza void HD44780_Init(uint8_t cols, uint8_t rows) { //Inicjalizacja opoznienia DELAY_Init(); //Inicjalizacja pinow, wyprowadzen mikrokontrolera HD44780_InitPins(); //Opóznienie minimum 40ms Delay(45000); //Przypisanie zmiennej HD44780_Opts.Rows zmiennej rows czyli rzedy HD44780_Opts.Rows = rows; //Przypisanie zmiennej HD44780_Opts.Cols zmiennej cols czyli kolumny HD44780_Opts.Cols = cols; //Przypisanie startowej pozycji x na 0 HD44780_Opts.currentX = 0; //Przypisanie startowej pozycji y na 0 HD44780_Opts.currentY = 0; //Ustawienie funkcji wyswietlacza //Tryb 4bitowy 0x00 | 5x8 0x00 | 1Line 0x00 HD44780_Opts.DisplayFunction = HD44780_4BITMODE | HD44780_5x8DOTS | HD44780_1LINE; if (rows > 1) { //Wybranie dwóch linii 0x08 HD44780_Opts.DisplayFunction |= HD44780_2LINE; } //Wyslanie komendy 0011, po niej nalezy odczekac przynajmniej 4,1 ms HD44780_Cmd4bit(0x03); Delay(4500); //Druga próba HD44780_Cmd4bit(0x03); Delay(200); //Trzecia próba HD44780_Cmd4bit(0x03); //Wybieramy 4 bitowy interfejs, wyslanie komendy 0010 //Ustawienie 4 bitowego interfejsu HD44780_Cmd4bit(0x02); Delay(100); //Ustawienie lini, sposobu wyswietlania HD44780_Cmd(HD44780_FUNCTIONSET | HD44780_Opts.DisplayFunction); //Wlacz wyswietlacz 0x04 HD44780_Opts.DisplayControl = HD44780_DISPLAYON; HD44780_DisplayOn(); //Czyszczenie wyswietlacza HD44780_Clear(); //Ustawienie domyslnej czcionki HD44780_Opts.DisplayMode = HD44780_ENTRYLEFT | HD44780_ENTRYSHIFTDECREMENT; HD44780_Cmd(HD44780_ENTRYMODESET | HD44780_Opts.DisplayMode); Delay(4500); }
Wykorzystywanie 4 bitowego trybu transmisji wymusza wysyłanie znaku w dwóch częściach. Najpierw wysyłana jest starsza połówka słowa danych, określana jako nibble, potem zaś wysyłana jest młodsza.
Wobec tego funkcja wysyłająca dane do wyświetlacza wygląda następująco:
//Wysyła komendy do wyświetlacza void HD44780_Cmd(uint8_t cmd) { //Sygnał niski na linię RS GPIO_WriteBit(HD44780_RS_PORT, HD44780_RS_PIN, 0x00); //Wysłanie starszej części danych HD44780_Cmd4bit(cmd >> 4); //Wysłanie młodszej części HD44780_Cmd4bit(cmd & 0x0F); } //Wysłanie danych do wyświetlacza void HD44780_Data(uint8_t data) { GPIO_WriteBit(HD44780_RS_PORT, HD44780_RS_PIN, Bit_SET); //Wysłanie starszej części danych HD44780_Cmd4bit(data >> 4); //Wysłanie młodszej części HD44780_Cmd4bit(data & 0x0F); } /* Wysyla 4 bitowe komendy do wyswietlacza */ void HD44780_Cmd4bit(uint8_t cmd) { //Wpisanie danych do wyświetlacza, jeśli wpisywane dane są różne od zera wtedy stan wysoki //Jeśli nie są wtedy stan niski GPIO_WriteBit(HD44780_D7_PORT, HD44780_D7_PIN, (cmd & 0x08) != 0 ? Bit_SET : Bit_RESET); GPIO_WriteBit(HD44780_D6_PORT, HD44780_D6_PIN, (cmd & 0x04) != 0 ? Bit_SET : Bit_RESET); GPIO_WriteBit(HD44780_D5_PORT, HD44780_D5_PIN, (cmd & 0x02) != 0 ? Bit_SET : Bit_RESET); GPIO_WriteBit(HD44780_D4_PORT, HD44780_D4_PIN, (cmd & 0x01) != 0 ? Bit_SET : Bit_RESET); //Wystawienie sygnału wysokiego na pin E GPIO_WriteBit(HD44780_E_PORT, HD44780_E_PIN, Bit_SET); //Odczekanie 20us Delay(20); //Wystawienie stanu niskiego na pin E GPIO_WriteBit(HD44780_E_PORT, HD44780_E_PIN, Bit_RESET); //Odczekanie 20us Delay(20); }
Do podawania odpowiednich wartości tzn set oraz reset wykorzystano odpowiednią strukturę z biblioteki stm32f4xx_gpio.h.
typedef enum { Bit_RESET = 0, Bit_SET }BitAction; #define IS_GPIO_BIT_ACTION(ACTION) (((ACTION) == Bit_RESET) || ((ACTION) == Bit_SET))
Poniżej przedstawiam funckję wprowadzającą dane na wyświetlacz. W argumentach podaje się miejsce tzn. wartość położenia tekstu w miejscu x oraz y.
void HD44780_Puts(uint8_t x, uint8_t y, char* str) { HD44780_CursorSet(x, y); while (*str) { if (HD44780_Opts.currentX >= HD44780_Opts.Cols) { HD44780_Opts.currentX = 0; HD44780_Opts.currentY++; HD44780_CursorSet(HD44780_Opts.currentX, HD44780_Opts.currentY); } if (*str == '\n') { HD44780_Opts.currentY++; HD44780_CursorSet(HD44780_Opts.currentX, HD44780_Opts.currentY); } else if (*str == '\r') { HD44780_CursorSet(0, HD44780_Opts.currentY); } else { HD44780_Data(*str); HD44780_Opts.currentX++; } str++; } }
Główna funkcja prezentująca funkcje wyświetlacza wygląda następująco:
#include "stm32f4xx.h" #include "stm32f4_discovery.h" #include "itoa.h" #include "stm32f4_delay.h" #include "stm32f4_HD44780.h" int main(void) { int f = 3; char buf[20]; char *buf1[10]; //Inicjalizacja wyswietlacza, podajemy wartosc wierszy i kolumn HD44780_Init(16, 2); //Wypisanie stringu na wyswietlaczu HD44780_Puts(0, 0, "STM32F4 Discover"); itoa(f, buf1, 10); HD44780_Puts(0, 1, buf1); Delayms(4000); HD44780_Clear(); //Zapala kursor HD44780_CursorOn(); HD44780_BlinkOn(); //Wpisanie tekstu HD44780_Puts(0, 1, "16x2 HD44780 LCD"); itoa(34243, buf1, 10); HD44780_Puts(0, 0, buf1); while (1) { } }
Biblioteki dodatkowe do projektu można dodawać poprzez umieszczenie ich w folderach dołączonych do niego, lub poprzez podanie pełnej ścieżki dostępu w cudzysłowie.
Bibliografia:
[1] Dokumentacja sterownika Hitachi HD44780
[2] Galewski M. STM32 Aplikacje i ćwiczenia w języku C
[3] http://stm32f4-discovery.com