poniedziałek, 17 września 2018

[27] STM32F7 - Obsługa wyświetlacza sterowanego przez UART

W tym poście chciałem przedstawić obsługę wyświetlacza z panelem dotykowym sterowanego przez UART.

[Źródło: http://www.st.com/en/evaluation-tools/32f746gdiscovery.html]
[Źródło: http://www.artronic.eu/pl/p/LCD-AG-TFTSD-UART-480272C-43TP-B/997]

Wykorzystywany prze zemnie wyświetlacz to LCD-AG-TFTSA-UART-480272C-43TP-B. Zaletą tego rozwiązania jest to, że tylko wysyłamy odpowiednie komendy do wyświetlacza a on sam zajmuje się wszystkimi zadaniami. Grafiki, czcionki ładujemy bezpośrednio na kartę SD i z niej wyświetlacz pobiera odpowiednie dane. Do wyświetlacza dołączona jest karta SD o pojemności 500 mb.

Konfiguracja wyświetlacza:


Wszystkie dostępne do konfiguracji parametry można ustawić w pliku CONFIG.INI.

  1. BaudRate=115200    //´®żÚ˛¨ĚŘÂĘ
  2.  
  3. StartColor=30 //żŞ»úŃŐÉ«
  4.  
  5. DemoStatus=1    //żŞ»úĘÇ·ń×Ô¶ŻäŻŔŔͼƬ
  6. DemoTime=1000    //×Ô¶ŻäŻŔŔͼƬĽä¸ôʱĽä(µĄÎ»:ms)
  7. DemoXaddr=0    //×Ô¶ŻäŻŔŔͼƬX×ř±ę
  8. DemoYaddr=0    //×Ô¶ŻäŻŔŔͼƬY×ř±ę
  9.  
  10. Monitor=0    //´®żÚĽŕĘÓĆ÷ą¦ÄÜ,ÔÚĆÁÄ»ÉĎ´®żÚ˝ÓĘŐµ˝×Ö·ű,(·ÇÖ¸Áî)
  11.  
  12. MotionSize1=1024   //¶Ż»­ĘýľÝÁżÉčÖĂ,µĄÎ»(KB)
  13. MotionSize2=200
  14. MotionSize3=0
  15. MotionSize4=0
  16.  
  17.  
  18. TpTestFlag=0    //TP˛âĘÔÄŁĘ˝,´ňżŞ´ËÄŁĘ˝şóÔÚµă»÷λÖĂĎÔʾһ¸öСԲȦ
  19. TpColor=63488      //СԲȦµÄŃŐÉ«
  20. TpInterval=100    //TPĽě˛âĽä¸ôʱĽä(µĄÎ»:ms)
  21.  
  22.  
  23. ***************ĆÁÄ»ĹäÖòÎĘý,ÇëÎđËćŇâ¸Ä¶Ż*********************
  24.  
  25. TFT_CLK=0      //ĆÁĻʱÖÓĐźŷ˝Ďň1±íĘľÉĎÉýŃŘ,0±íĘľĎ½µŃŘ
  26. TFT_THD=480   //ĐĐĎÔĘľĎńËŘĘý
  27. TFT_THPW=41   //ĐĐͬ˛˝Đźſí¶Č
  28. TFT_THB=2   //ĐĐĐĹşĹÇ°Ľä
  29. TFT_THFP=2  //ĐĐĐźźóĽä
  30. TFT_TVD=272   //ÿһłˇĐĐĘý
  31. TFT_TVPW=10    //łˇÍ¬˛˝Đźſí¶Č
  32. TFT_TVB=2    //łˇĐĹşĹÇ°Ľä
  33. TFT_TVFP=2    //łˇĐźźóĽä
  34.  
  35. RTPHV=0      //RTPËłĐň
  36. XA=221
  37.  
  38. XB=-18016
  39. YA=157
  40. YB=-24723

Na samym początku opisana jest konfiguracja prędkości transmisji z wyświetlaczem. Kolejne elementy to ustawienie programu demonstracyjnego (wyświetlanie przykładowych grafik na ekranie, tutaj parametr DemoStatus należy ustawić na 0 w celu wyłączenia działania tej funkcji), dalej program demonstracyjny dla panelu dotykowego (wyświetlanie kropek na ekranie w miejscu wciśnięcia panelu dotykowego, parametr TpTestFlag należy ustawić na 0, aby wyłączyć tą funkcję). Dalej są parametry ekranu oraz wartości dla panelu dotykowego.

Program:


Poniżej opisz niektóre funkcje odpowiedzialne za sterowanie wyświetlaczem.

Czyszczenie wyświetlacza:

  1. uint8_t M7Axa_ClearScreen(uint16_t bgColor)
  2. {
  3.     if(bgColor > 65535)
  4.     {
  5.         return 1;
  6.     }
  7.     char bufferOut[16];
  8.     sprintf(bufferOut, "CLS %d", bgColor);
  9.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  10.     return 0;
  11. }

Do układu wysyłany jest rozkaz wraz z kolorem tła. Wysłaną komendę kończymy znakiem powrotu karetki oraz przejścia do nowej linii.

Kolejną komendą jest rysowanie okręgu:

  1. void M7Axa_Disp_DrawCircle(uint16_t Xa, uint16_t Ya, uint16_t R, uint16_t Color)
  2. {
  3.     char bufferOut[30];
  4.     sprintf(bufferOut, "CIRCLE %u %u %u %u", Xa, Ya, R, Color);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Tutaj jako argumenty podajemy pozycje startową na osi X oraz osi Y następnie promień oraz kolor.

Zapełnienie fragmentu kolorem:

  1. void M7Axa_Disp_FillInColor(uint16_t Xa, uint16_t Ya, uint16_t Xe, uint16_t Ye, uint16_t Color)
  2. {
  3.     char bufferOut[50];
  4.     sprintf(bufferOut, "CLR %u %u %u %u %u", Xa, Ya, Xe, Ye, Color);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Tutaj jako argumenty podawany jest początek, koniec oraz kolor wypełnienia.

W celu przycięcia obrazu należy podać numer seryjny obrazka od 0 do 999 oraz miejsce położenia obrazka, rozmiar aktualny i na końcu nowy rozmiar obrazu:

  1. void M7Axa_CutPicture(uint16_t Pn, uint16_t Xa, uint16_t Ya, uint16_t Xb, uint16_t Yb, uint16_t Xs, uint16_t Ys)
  2. {
  3.     char bufferOut[60];
  4.     sprintf(bufferOut, "CUT %u %u %u %u %u %u %u", Pn, Xa, Ya, Xb, Yb, Xs, Ys);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Rysowanie kropki na ekranie:

  1. void M7Axa_DrawDot(uint16_t Xa, uint16_t Ya, uint16_t Color)
  2. {
  3.     char bufferOut[30];
  4.     sprintf(bufferOut, "DOT %u %u %u", Xa, Ya, Color);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Kropka jest interpretowana jako pojedynczy piksel. Dzięki takiej funkcji można rysować jakiekolwiek kształty. Tutaj aby to rysowanie miało sens, przynajmniej dla dużych kształtów, to należałoby wykorzystać DMA. To może przyda przy normalnym trybie przesyłania gdy chcemy narysować np. wykres z pojedynczej linii na wyświetlaczu.

Rysowanie linii:

  1. void M7Axa_DrawLine(uint16_t Xa, uint16_t Ya, uint16_t Xe, uint16_t Ye, uint16_t Color)
  2. {
  3.     char bufferOut[40];
  4.     sprintf(bufferOut, "LINE %u %u %u %u %u", Xa, Ya, Xe, Ye, Color);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Tutaj sprawa jest dosyć mało skomplikowana na początku podajemy punkty startowe, następnie zakończenie linii oraz kolor.

Funkcja odpowiedzialna za włączanie/wyłączenia podświetlenia:

  1. void M7Axa_BacklightControl(uint8_t onOffState)
  2. {
  3.     char bufferOut[20];
  4.    
  5.     if(onOffState == 0)
  6.     {
  7.         sprintf(bufferOut, "LEDOFF");
  8.     }
  9.     else
  10.     {
  11.         sprintf(bufferOut, "LEDON");
  12.     }
  13.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  14. }

Wyświetlenie obrazu na podstawie id obrazka:

  1. uint8_t M7Axa_LoadPicById(uint16_t Pn, uint16_t Xa, uint16_t Ya)
  2. {
  3.     char bufferOut[40];
  4.    
  5.     if(Pn > 999)
  6.     {
  7.         return 1;
  8.     }
  9.    
  10.     sprintf(bufferOut, "PIC %u %u %u", Pn, Xa, Ya);
  11.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  12.    
  13.     return 0;
  14. }

Wyświetlenie obrazu na podstawie nazwy pliku znajdującego się na karcie SD od wyświetlacza. Przykładowy sposób wywołania komendy: LOAD 0 0 jpg\filename.jpg

  1. void M7Axa_LoadPicture(char * path, uint16_t posX, uint16_t posY) {
  2.  
  3.     char bufferOut[64];
  4.     memset(bufferOut, 0, sizeof bufferOut);
  5.    
  6.     sprintf(bufferOut, "LOAD %d %d %s", posX, posY, path);
  7.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  8. }

Rysowanie prostokąta na ekranie:

  1. void M7Axa_DrawRactangle(uint16_t Xa, uint16_t Ya, uint16_t Xb, uint16_t Yb, uint16_t Color)
  2. {
  3.     char bufferOut[80];
  4.     sprintf(bufferOut, "RECT %u %u %u %u %u", Xa, Ya, Xb, Yb, Color);
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Pobierz rozmiar wyświetlacza:

  1. void M7Axa_GetScreenSize()
  2. {
  3.     char bufferOut[10];
  4.     sprintf(bufferOut, "SIZE");
  5.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  6. }

Wyświetl napis na ekranie:

  1. void M7Axa_DisplayAlphabeticString(const char * str, uint16_t Xa, uint16_t Ya, uint16_t Color) {
  2.     char bufferOut[128];
  3.     sprintf(bufferOut, "STR %u %u %u %s", Xa, Ya, Color, str);
  4.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  5. }

Wyświetlanie tekstu wraz z kolorem tła:

  1. void LCD_PrintStringWithBg(const char * str, uint16_t len, FontSize_TypeDef fontSize,
  2.         uint16_t posX, uint16_t posY, uint16_t textColor, uint16_t bgColor)
  3. {
  4.     char sendText[len + 1];
  5.    
  6.     memset(sendText, 0, sizeof(sendText));
  7.     memcpy(sendText, str, len);
  8.  
  9.     char bufferOut[128];
  10.     sprintf(bufferOut, "HZB%d %d %d %d %d %s", fontSize, posX, posY, textColor, bgColor, sendText);
  11.    
  12.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  13. }

Wyświetlenie tekstu bez koloru tła:

  1. void LCD_PrintString(const char * str, FontSize_TypeDef fontSize, uint16_t posX, uint16_t posY,
  2.         uint16_t textColor)
  3. {
  4.     char bufferOut[128];
  5.     sprintf(bufferOut, "HZ%d %d %d %d %s", fontSize, posX, posY, textColor, str);
  6.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  7. }

Sterowanie buzerem. Jako parametry podaje się czas załączenia oraz częstotliwość (1k do 4k):

  1. uint8_t M7Axa_BuzzerControl(uint16_t Tb, uint16_t Fb) {
  2.     char bufferOut[40];
  3.    
  4.     if(Fb < 1000 || Fb > 4000)
  5.     {
  6.         return 1;
  7.     }
  8.    
  9.     sprintf(bufferOut, "BUZ %u %u", Tb, Fb);
  10.     Usart_Uart_SendString(USART1, bufferOut, LF_CR);
  11.    
  12.     return 0;
  13. }

Obsługa panelu dotykowego polega na odczycie ramki danych zwracanej przez wyświetlacz. Funckja obsługująca ramkę danych:

  1. TPCoords_Typedef getTouchPadData(uint8_t * recBuffer, uint16_t bufferSize) {
  2.     TPCoords_Typedef coords = { -1, -1 };
  3.  
  4.     uint8_t dataReadyStatus = 0;
  5.     uint16_t i = 1;
  6.  
  7.     while(bufferSize)
  8.     {
  9.         if(recBuffer[bufferSize] == '\n')
  10.         {
  11.             dataReadyStatus = 1;
  12.         }
  13.         else if(dataReadyStatus && recBuffer[bufferSize] >= 0x30 && recBuffer[bufferSize] <= 0x39)
  14.         {
  15.             if(dataReadyStatus == 1)
  16.             {
  17.                 coords.positionY += (recBuffer[bufferSize] - 0x30) * i;
  18.             }
  19.             else if(dataReadyStatus == 2)
  20.             {
  21.                 coords.positionX += (recBuffer[bufferSize] - 0x30) * i;
  22.             }
  23.             i *= 10;
  24.         }
  25.         else if(recBuffer[bufferSize] == ' ')
  26.         {
  27.             dataReadyStatus = 2;
  28.             i = 1;
  29.         }
  30.  
  31.         bufferSize--;
  32.     }
  33.  
  34.     return coords;
  35. }

Na karcie SD znajduje się kilka przykładowych czcionek. Możliwe jest też wykonanie polskich znaków, natomiast wymaga to trochę wprawy. Sposób na poprawne wykonanie czcionek do tego wyświetlacza opiszę w kolejnym poście. 

W większości przypadków te wyświetlacze nie powinny się wypalać. Natomiast nie jest to reguła i mogą się trafić przypadki partii w których takie wypalanie będzie występowało. Z tego powodu warto uwzględnić wygaszanie ekranu na krótki czas, np. raz na 30 minut na 1 czy 2 sekundy. Pozwoli to trochę wydłużyć czas życia tego wyświetlacza. Dotyczy to przypadku gdy przez większość czasu będzie wyświetlany obraz niezmieniany o kontrastowych kolorach względem koloru tła. Dodatkowo należy pamiętać. 

Gdy wygaszanie/resetowanie ekranu będzie następowało przez odłączenie zasilania to należy uwzględnić czas około 500ms na poprawne uruchomienie wszystkich funkcji wyświetlacza przed wysyłaniem do niego komend. 

Bibliotekę do obsługi wyświetlacza można pobrać z dysku Google pod tym linkiem.