czwartek, 11 sierpnia 2016

[12] STM32F4 - Discovery - Obsługa wyświetlacza HD44780

W tym poście opiszę w jaki sposób obsłużyć wyświetlacz 2x16 ze sterownikiem HD44780. 

Program


Poniżej przejdę po poszczególnych głównych funkcjach całego programu.

Rozpoczęcie pracy z wyświetlaczem należy rozpocząć od jego poprawnego włączenia, co się wykonuje na podstawie przedstawionej poniżej funkcji inicjującej pracę wyświetlacza oraz uruchamiającą potrzebne wyprowadzenia GPIO.



Definicję rejestrów:

  1. #define HD44780_CLEAR                  0x01
  2. #define HD44780_HOME                   0x02
  3. #define HD44780_ENTRY_MODE             0x04
  4. #define HD44780_EM_SHIFT_CURSOR        0x00
  5. #define HD44780_EM_SHIFT_DISPLAY       0x01
  6. #define HD44780_EM_DECREMENT           0x00
  7. #define HD44780_EM_INCREMENT           0x02
  8. #define HD44780_DISPLAY_ONOFF          0x08
  9.     #define HD44780_DISPLAY_OFF        0x00
  10.     #define HD44780_DISPLAY_ON         0x04
  11.     #define HD44780_CURSOR_OFF         0x00
  12.     #define HD44780_CURSOR_ON          0x02
  13.     #define HD44780_CURSOR_NOBLINK     0x00
  14.     #define HD44780_CURSOR_BLINK       0x01
  15. #define HD44780_DISPLAY_CURSOR_SHIFT   0x10
  16.     #define HD44780_SHIFT_CURSOR       0x00
  17.     #define HD44780_SHIFT_DISPLAY      0x08
  18.     #define HD44780_SHIFT_LEFT         0x00
  19.     #define HD44780_SHIFT_RIGHT        0x04
  20. #define HD44780_FUNCTION_SET           0x20
  21.     #define HD44780_FONT5x8            0x00
  22.     #define HD44780_FONT5x10           0x04
  23.     #define HD44780_ONE_LINE           0x00
  24.     #define HD44780_TWO_LINE           0x08
  25.     #define HD44780_4_BIT              0x00
  26.     #define HD44780_8_BIT              0x10

  27.     #define HD44780_SETCGRAM           0x40
  28.     #define HD44780_SETDDRAM           0x80

Funkcja rozpoczynająca pracę układu z mikrokontrolerem:

  1. void LCD_HD44780_Init(void)
  2. {
  3.     //Deklaracja zmiennych
  4.     volatile unsigned char i = 0;
  5.     //volatile unsigned int delayCnt = 0;
  6.     //Wlaczenie pinow
  7.     LCD_InitPins();
  8.     //Ustawienie wszystkich pinów w stan niski
  9.     ((LCD_D4_Port)->BSRRH = (LCD_D4));
  10.     ((LCD_D5_Port)->BSRRH = (LCD_D5));
  11.     ((LCD_D6_Port)->BSRRH = (LCD_D6));
  12.     ((LCD_D7_Port)->BSRRH = (LCD_D7));
  13.     ((LCD_RS_Port)->BSRRH = (LCD_RS));
  14.     ((LCD_RW_Port)->BSRRH = (LCD_RW));
  15.     ((LCD_EN_Port)->BSRRH = (LCD_EN));
  16.    
  17.     //Opoznienie przynajmniej 40ms
  18.     LCD_Delay(300000);
  19.     //Wybranie trybu 4 bitowego, nalezy dane wyslac 3 razy
  20.     for(= 0; i < 3; i++)
  21.     {
  22.     LCD_WriteNibble(0x03);            
  23.         //Odczekac przynajmniej 40ms
  24.     LCD_Delay(30000);
  25.     }
  26.     //Wlaczenie trybu 4 bitowego
  27.     LCD_WriteNibble(0x02);            
  28.     //Delay
  29.     LCD_Delay(6000);
  30.     //Ustawienie wielkosci czcionek rozmiar linie komunikacje
  31.     //HD44780_FUNCION_SET = 0x20 | HD44780_FONT5x8 = | HD44780_TWO_LINE = 0x08 
  32.     //| HD44780_4_BIT = 0x00
  33.     LCD_WriteCommand(HD44780_FUNCTION_SET | HD44780_FONT5x8 | 
  34.     HD44780_TWO_LINE | HD44780_4_BIT);
  35.     //Wlaczenie oraz wylaczenie wyswietlacza w pelnym trybie
  36.     //HD44780_DISPLAY_ONOFF = 0x08 | HD44780_DISPLAY_OFF = 0x00
  37.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_OFF);
  38.     //Wyczyszczenie wyswietlacza
  39.     //HD44780_CLEAR - 0x01
  40.     LCD_WriteCommand(HD44780_CLEAR);
  41.     //Ustawienie dodatkowe do trybów wyswietlania, kursora
  42.     //HD44780_ENTRY_MODE = 0x04 | HD44780_EM_SHIFT_CURSOR = 0x00 | 
  43.     //HD44780_EM_INCREMENT = 0x02
  44.     LCD_WriteCommand(HD44780_ENTRY_MODE | HD44780_EM_SHIFT_CURSOR | HD44780_EM_INCREMENT);
  45.     //HD44780_DISPLAY_ONOFF = 0x08 | HD44780_DISPLAY_ON = 0x04| HD44780_CURSOR_OFF = 0x00     //| HD44780_CURSOR_NOBLINK = 0x00
  46.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_ON | HD44780_CURSOR_OFF | HD44780_CURSOR_NOBLINK);
  47. }

Funkcja ustawiająca piny:

  1. //Wlaczenie pinów===================================
  2. void LCD_InitPins()
  3. {
  4.     //Wlaczenie pinow dla wyswietlacza
  5.     GPIO_InitTypeDef GPIO_InitDef;
  6.    
  7.     //Ustawienia dla poszczególnych wyprowadzen  
  8.     RCC->AHB1ENR |= RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB |
  9.     RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE;
  10.    
  11.     //Linie sygnalowe
  12.     //Wybranie pinów
  13.     GPIO_InitDef.GPIO_Pin = LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
  14.      
  15.     GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
  16.     GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
  17.     GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
  18.     GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
  19.     GPIO_Init(Signal_Port, &GPIO_InitDef);
  20.    
  21.     //E
  22.     GPIO_InitDef.GPIO_Pin = LCD_EN;
  23.      
  24.     GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
  25.     GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
  26.     GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
  27.     GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
  28.     GPIO_Init(LCD_EN_Port, &GPIO_InitDef);
  29.    
  30.     //RS
  31.     GPIO_InitDef.GPIO_Pin = LCD_RS;
  32.      
  33.     GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
  34.     GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
  35.     GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
  36.     GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
  37.     GPIO_Init(LCD_RS_Port, &GPIO_InitDef);
  38.    
  39.     //RW
  40.     GPIO_InitDef.GPIO_Pin = LCD_RW;
  41.      
  42.     GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
  43.     GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
  44.     GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
  45.     GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
  46.     GPIO_Init(LCD_RW_Port, &GPIO_InitDef);
  47. }

Pętla opóźniająca, wykonana za pomocą pętli for();

  1. void LCD_Delay(volatile unsigned int delayLic)
  2. {
  3.     for(delayLic = 0; delayLic < 30000; delayLic++);
  4. }

Funkcja wysyłająca tzw. nibbla czyli młodszą oraz starszą część bitu, którego należy podać w dwóch partiach. Spowodowane jest to wykorzystywanie 4 bitowego trybu transmisji danych:

  1. void LCD_WriteNibble(unsigned char cmd)
  2. {
  3.   GPIO_WriteBit(LCD_EN_Port, LCD_EN, Bit_SET);
  4.   GPIO_WriteBit(LCD_D4_Port, LCD_D4, (cmd & 0x01));
  5.   GPIO_WriteBit(LCD_D5_Port, LCD_D5, (cmd & 0x02));
  6.   GPIO_WriteBit(LCD_D6_Port, LCD_D6, (cmd & 0x04));
  7.   GPIO_WriteBit(LCD_D7_Port, LCD_D7, (cmd & 0x08));
  8.   GPIO_WriteBit(LCD_EN_Port, LCD_EN, Bit_RESET);
  9. }

Oraz odczytująca 4 bity:

  1. unsigned char LCD_ReadNibble(void)
  2. {
  3.   unsigned char tmp = 0;
  4.   GPIO_WriteBit(LCD_EN_Port, LCD_EN, Bit_SET);
  5.   tmp |= (GPIO_ReadInputDataBit(LCD_D4_Port, LCD_D4) << 0);
  6.   tmp |= (GPIO_ReadInputDataBit(LCD_D5_Port, LCD_D5) << 1);
  7.   tmp |= (GPIO_ReadInputDataBit(LCD_D6_Port, LCD_D6) << 2);
  8.   tmp |= (GPIO_ReadInputDataBit(LCD_D7_Port, LCD_D7) << 3);
  9.   GPIO_WriteBit(LCD_EN_Port, LCD_EN, Bit_RESET);
  10.   return tmp;
  11. }

Funkcja włączająca oraz wyłączająca wyświetlacz:

  1. void LCD_HD44780_BlinkOn(void)
  2. {
  3.     //HD44780_CURSOR_BLINK = 0x01
  4.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_CURSOR_BLINK);
  5. }
  6. void LCD_HD44780_BlinkOff(void)
  7. {
  8.     //HD44780_CURSOR_NOBLINK = 0x00
  9.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF  | HD44780_CURSOR_NOBLINK);
  10. }

Funkcja przesyłająca funkcje sterującą:

  1. void LCD_WriteCommand(unsigned char data)
  2. {
  3.     //Przed wyslanie nalezy RW oraz RS ustawic
  4.     //w stanie niski,
  5.     GPIO_WriteBit(LCD_RW_Port, LCD_RW, Bit_RESET);
  6.     GPIO_WriteBit(LCD_RS_Port, LCD_RS, Bit_RESET);
  7.     //Wyslanie starszej czesci
  8.     LCD_WriteNibble(data >> 4);
  9.     //Wyslanie mlodszej czesci
  10.     LCD_WriteNibble(data & 0x0F);
  11.     //Odczytanie stanu przycisku
  12.     while(LCD_ReadStatus() & 0x80);
  13. }

Funkcja wprowadzające dane do wyświetlania:

  1. void LCD_WriteData(unsigned char dataToWrite)
  2. {
  3.   //Reset RW | ustawienie bitu RS
  4.   GPIO_WriteBit(LCD_RW_Port, LCD_RW, Bit_RESET);
  5.   GPIO_WriteBit(LCD_RS_Port, LCD_RS, Bit_SET);
  6.   LCD_WriteNibble(dataToWrite >> 4);
  7.   LCD_WriteNibble(dataToWrite & 0x0F);
  8. }

Wprowadzanie tekstu na wyświetlacz:

  1. void LCD_WriteText(unsigned char * text)
  2. {
  3.     while(*text)
  4.     LCD_WriteData(*text++);
  5. }

Funkcja wyłączająca oraz włączająca kursor:

  1. void LCD_HD44780_CursorOff(void)
  2. {
  3.     //HD44780_DISPLAY_ONOFF = 0x08 | HD44780 = 0x00
  4.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_OFF);
  5. }
  6. void LCD_HD44780_CursorOn(void)
  7. {
  8.     //HD44780_DISPLAYCONTROL = 0x08 | HD44780_CURSORON = 0x02
  9.     LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_CURSORON);
  10. }

Przesunięcie kursora w lewo oraz w prawo:

  1. //Przesuniecie w lewo
  2. void LCD_ShiftLeft(void)
  3. {
  4.     //HD44780_DISPLAY_CURSOR_SHIFT = 0x10 | HD44780_SHIFT_LEFT = 0x00
  5.     //HD44780_SHIFT_DISPLAY = 0x08
  6.   LCD_WriteCommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_LEFT | HD44780_SHIFT_DISPLAY);
  7. }
  8. //Przesuniecie kursora w prawo
  9. void LCD_ShiftRight(void)
  10. {
  11.     //HD44780_DISPLAY_CURSOR_SHIFT = 0x10 | HD44780_SHIFT_RIGHT = 0x04| HD44780_SHIFT_DISPLAY = 0x08
  12.   LCD_WriteCommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_RIGHT | HD44780_SHIFT_DISPLAY);
  13. }

Czyszczenie wyświetlacza:

  1. void LCD_HD44780_Clear(void)
  2. {
  3.     //HD44780_CLEAR = 0x01
  4.     LCD_WriteCommand(HD44780_CLEAR);
  5.     LCD_Delay(300000);
  6. }

Dodatkowo istnieje jeszcze możliwość tworzenia własnej tablicy znaków, którą można stworzyć poprzez wprowadzenie go do pamięci wyświetlacza. Układ może przechowywać do 8 własnych zdefiniowanych znaków:

  1. void HD44780_Char(uint8_t location, uint8_t *data)
  2. {
  3.     uint8_t i;
  4.     //Maksymalnie mozna zdefiniowac 8 znakow
  5.     location &= 0x07;
  6.     LCD_WriteCommand(HD44780_SETCGRAM | (location << 3));
  7.    
  8.     for (= 0; i < 8; i++)
  9.     {
  10.         LCD_WriteData(data[i]);
  11.     }
  12. }

Podłączenie

  • VSS - Masa GND
  • VDD - Zasilanie
  • V0 - Potencjometr do regulacji kontrastu
  • RS - Do zdefiniowanego pinu
  • RW - Do zdefiniowanego pinu
  • E - Do zdefiniowanego pinu
  • D4 - Do zdefiniowanego pinu
  • D5 - Do zdefiniowanego pinu
  • D6 - Do zdefiniowanego pinu
  • D7 - Do zdefiniowanego pinu
  • A - Podświetlenie do 3,3V
  • K - Masa podświetlenia
W części głównej programu należy włączyć wyświetlacz po czym można kolejnymi komendami go obsługiwać.