Biblioteka Segger STemWin w praktyce (1): prosta aplikacja okienkowa

Artykuł jest wprowadzeniem do projektowania graficznych interfejsów użytkownika z zastosowaniem biblioteki STemWin oraz zestawu STM32F429I-Discovery jako platformy testowej. Przedstawiono w nim informacje niezbędne do utworzenia szablonowego projektu oraz pokazano przykład prostej aplikacji okienkowej, która zawiera klasyczny tekst „Hello, World!” oraz przyciski pozwalające na zmianę jego czcionki i koloru.

 

Fot. 1. Zestaw STM32F429I-Discovery

Fot. 2. Przykładowa aplikacja okienkowazaimplementowana w zestawie STM32F429I-Discovery

Biblioteka STemWin umożliwia tworzenie zaawansowanych interfejsów graficznych użytkownika (GUI, Graphical User Interface) współpracujących z dowolnym mikrokontrolerem z rodziny STM32 oraz dowolnym wyświetlaczem i kontrolerem LCD/TFT. Powstała ona na bazie opracowanej przez firmę SEGGER biblioteki emWin do której jest udostępniana obszerna dokumentacja oraz liczne przykłady różnych aplikacji graficznych [2, 7].

 

Rys. 3. Przykładowe widżety biblioteki STemWin

 

Swoją przygodę z projektowaniem interfejsów graficznych najlepiej rozpocząć od przygotowania i uruchomienia klasycznego projektu typu „Hello, World!”. Załóżmy, że w ramach tego zadania oprócz utworzenia prostego okienka oraz wyświetlenia w nim tekstuzostaną dodatkowo dodane przyciski do zmiany koloru i rozmiaru tegoż tekstu.Do przygotowania projektu możemy wykorzystać bezpłatne środowisko CooCoxCoIDE [5]wraz z narzędziami nie nakładającymi ograniczeń do objętości generowanego kodu wynikowegoGNU Tools for ARM [3]. Przykładowy opis instalacji i konfiguracji środowiska można znaleźć w [4].

Na początku uruchamiamy środowisko CoIDE i z paska menu wybieramyProject > New Project. W otwartym okienkuNew Project podajemy nazwę projektu oraz jego lokalizację (rysunek 4). W kolejnym kroku najeżdżamy myszką na obszar Chip i przechodzimy dalej (rysunek 5). Ponieważ obecna wersja środowiska nie obsługuje jeszcze mikrokontrolera STM32F429ZI to wybieramy inny pokrewny do niego, np. STM32F407VG (rysunek 6) – wybór konkretnego modelu nie ma większego znaczenia, gdyż wszystkie niezbędne parametry zostaną później zmienione. Po zamknięciu okienka przyciskiem Finish zostanie otwarta zakładka Repository, którą możemy zamknąć, ponieważ wykorzystamy pliki z zewnątrz, dostępne w standardowej bibliotece do zestawu STM32F429I-Discovery. Standardowa biblioteka wraz z przykładowymi projektami jest dostępna w pliku archiwalnym pod nazwą STSW-STM32138 w zakładce All na stronie producenta ST [9].

 

Rys. 4. Wprowadzenie nazwy i lokalizacji nowego projektu

 

 

Rys. 5. Wybór modelu projektu

 

Rys. 6. Wybór typu mikrokontrolera

 

W następnej kolejności w zakładce Project okna głównego tworzymy grupy plików, tak jak to przedstawia rysunek 7. W tym celu klikamy prawym przyciskiem myszy na nazwie projektu lub grupy i wybieramy AddGroup lub AddFiles. Jednocześnie w utworzonym katalogu z projektem za pomocą dowolnego menedżera plików budujemy strukturę katalogów zgodną z utworzonymi grupami plików. Na rysunku pokazano również pliki jakie powinny znaleźć się w danych grupach, a informacje skąd je można pobrać znajdują się tabeli 1 (pliki znajdują się w pobranej bibliotece).

 

Rys. 7.Struktura projektu – grupy i ich pliki

 

Tab. 1. Lokalizacje plików wykorzystanych w projekcie

Katalog główny projektu
Katalog Projects\Demonstration\TrueSTUDIO\STM32F429I-Discovery_Demo\
STM32F429ZI_FLASH.ld
Katalog Projects\Demonstration\Core\User\
main.c
Katalog Application\inc
Katalog Libraries\STemWinLibrary522_4x9i\Config\
GUIConf.h
Katalog Projects\Demonstration\Config\
FreeRTOSConfig.h, global_conf.h
global_includes.h(zakomentowaćwiersze włączające pliki nagłówkowe od USB i FatFS)
Katalog Projects\Demonstration\Core\Lib\
cpu_utils.h
Katalog Projects\Demonstration\Core\User\
bsp.h, rtc.h, stm32xxx_it.h
Katalog Application\src
Katalog Libraries\STemWinLibrary522_4x9i\Config\
GUIConf.c, GUIDRV_stm32f429i_discovery.c
Katalog Libraries\STemWinLibrary522_4x9i\OS\
GUI_X_FreeRTOS.c
Katalog Projects\Demonstration\Core\Lib\
cpu_utils.c
Katalog Projects\Demonstration\Core\User\
bsp.c (zakomentować nieużywane fragmenty kodu dotyczące komunikacji USB)
rtc.c, stm32xxx_it.c (zakomentować nieużywane fragmenty kodu dotyczące komunikacji USB)
Katalog CMSIS
Katalog Libraries\CMSIS\Include\
core_cm4.h, core_cm4_simd.h, core_cmFunc.h, core_cmInstr.h
Katalog Libraries\CMSIS\Device\ST\STM32F4xx\Include\
stm32f4xx.h, system_stm32f4xx.h
Katalog Projects\Template\
stm32f4xx_conf.h
Katalog CMSIS_Boot
Katalog Projects\Demonstration\TrueSTUDIO\
startup_stm32f429_439xx.s (zakomentować wiersz:
/*  bl  __libc_init_array */)
Plik .s powinien zawierać poniższy fragment kodu – w przeciwnym wypadku aplikacja może nie działać:
g_pfnVectors:
.word  _estack
.word  Reset_Handler
.word  NMI_Handler
.word  HardFault_Handler
.word  MemManage_Handler
.word  BusFault_Handler
.word  UsageFault_Handler
.word  0
.word  0
.word  0
.word  0
.word  vPortSVCHandler
.word  DebugMon_Handler
.word  0
.word  xPortPendSVHandler
.word  xPortSysTickHandler
Katalog Projects\Demonstration\Core\Devices\STM32F4xx\
system_stm32f4xx.c
Katalog FreeRTOS\inc
Katalog Utilities\Third_Party\FreeRTOS\Source\include\
croutine.h, FreeRTOS.h, list.h, mpu_wrappers.h, portable.h, projdefs.h, queue.h, semphr.h, StackMacros.h, tasks.h, timers.h
Katalog Utilities\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\
portmacro.h
Katalog FreeRTOS\src
Katalog Utilities\Third_Party\FreeRTOS\Source\portable\MemMang\
heap_2.c
Katalog Utilities\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\
port_cm4.c
Katalog Utilities\Third_Party\FreeRTOS\Source\
croutine.c, list.c, queue.c, tasks.c, timers.c
Katalog STemWinLibrary
Katalog Libraries\STemWinLibrary522_4x9i\
Skopiować katalog inc z całą jego zawartością
Katalog Libraries\STemWinLibrary522_4x9i\Lib\
STemWin522_4x9i_CM4_OS_GCC.a (zmienić nazwę pliku na libstemwin.a, gdyż w przeciwnym wypadku przy kompilacji projektu może wystąpić błąd nie znalezienia biblioteki)
Katalog STM32F429I-Discovery\inc
Katalog Utilities\Common\
fonts.h
Katalog Utilities\STM32F429I-Discovery\
stm32f429i_discovery.h, stm32f429i_discovery_ioe.h, stm32f429i_discovery_l3gd20.h,
stm32f429i_discovery_lcd.h, stm32f429i_discovery_sdram.h
Katalog STM32F429I-Discovery\src
Katalog Utilities\Common\
fonts.c
Katalog Utilities\STM32F429I-Discovery\
stm32f429i_discovery.c, stm32f429i_discovery_ioe.c, stm32f429i_discovery_l3gd20.c,
stm32f429i_discovery_lcd.c, stm32f429i_discovery_sdram.c
Katalog STM32F4xx_StdPeriph_Driver\inc
Katalog Libraries\STM32F4xx_StdPeriph_Driver\
Skopiować katalog inc z całą jego zawartością
Katalog STM32F4xx_StdPeriph_Driver\src
Katalog Libraries\STM32F4xx_StdPeriph_Driver\
Skopiować katalog src z całą jego zawartością

Ostatnie czynności konfiguracyjne wykonujemy w zakładce Configuration/Compile oraz Configuration/Link. W pierwszej wybieramy programową obsługę operacji zmiennoprzecinkowych (wybór sprzętowej obsługi może prowadzić do błędów podczas procesu konsolidacji) oraz dodajemy definicje stałych: STM32F4xx, STM32F429_439xx, USE_STDPERIPH_DRIVER (rysunek 8). Ponieważ w zakładce Project dodaliśmy zarówno pliki źródłowe .c jak i nagłówkowe .h to nie ma potrzeby dodawania ścieżek dostępu w sekcji Includepaths. W drugiej zakładce odznaczamy pole Use Memory Layout from Memory Window, a z listy rozwijanej wybieramy Usebase C Library. W polu Scatter Filemusimy podać ścieżkę do wcześniej skopiowanego plikuze skryptem konsolidatora stm32f429zi_flash.ld (rysunek 9).

 

Rys. 8.Konfiguracja projektu w zakładce Configuration/Compile

Rys. 9. Konfiguracja projektu w zakładce Configuration/Link

Po przygotowaniu szablonowego projektu można przejść do drugiego etapu, a mianowicie do implementacji prostej aplikacji okienkowej.Od tego momentu wszystkie operacje dodawania i modyfikowania kodu będą odbywać się w pliku main.c (chyba, że podano inaczej). Tak więc otwieramy ten plik i modyfikujemy główną funkcję main() tak, aby wyglądała jak na poniższym listingu:

W powyższym kodzie znajdują się wywołania funkcji związanych z systemem operacyjnym czasu rzeczywistego FreeRTOS [6] iwarto zwrócić szczególną uwagę na dwie z nich. Pierwsza funkcja xTaskCreate() tworzy nowe zadanie w systemie i przyjmuje następujące parametry:

  • wskaźnik do funkcji zadania,
  • nazwa zadania (do celów debugowania),
  • rozmiar stosu danego zadania,
  • opcjonalna lista parametrów,
  • priorytet zadania,
  • uchwyt do zadania.

Druga funkcjavTaskStartScheduler() uruchamia planistę, który jest odpowiedzialny za optymalne rozdzielenie czasu mikroprocesora oraz zasoby systemu pomiędzy uruchomione zadania z uwzględnieniem priorytetów i wymagań związanych z czasem ich realizacji [1]. Jak tylko planista został uruchomiony to wywoływana jest funkcjaMainTask() przedstawiona na poniższym listingu (w programie nie zdefiniowano innych zadań, więc wszystkie zasoby i czas będą wykorzystywane przez jedno zadanie).

Na początku powyższej funkcji wykonywana jest inicjalizacja wszystkich wymaganych układów sprzętowych, a następnie inicjalizowana jest sama biblioteka graficzna. Dalej ustawiamy domyślny styl dla przycisków i okien za pomocą funkcji <WIDGET>_SetDefaultSkin() – dostępne są dwa style: klasyczny oraz Flex (rysunek 10).

 

Rys. 10. Porównanie stylu klasycznego oraz stylu Flex

 

Wywołaniem funkcji WM_SetDesktopColor() ustawiamy kolor pulpitu – najwyżej położonego w hierarchii okna tworzonego automatycznie (listę definicji kolorów wykorzystywanych przez bibliotekę można znaleźć w pliku GUI.h). Do utworzenia okna wykorzystujemy funkcję FRAMEWIN_CreateEx() przyjmującą następujące parametry:

  • położenie widżetu w osi X okna rodzicielskiego (tutaj jest nim pulpit),
  • położenie widżetu w osi Y okna rodzicielskiego,
  • szerokość w osi X,
  • wysokość w osi Y,
  • uchwyt do okna rodzicielskiego (0 – dla pulpitu),
  • flagi tworzenia okna (CreationFlags) (WM_CF_SHOW powoduje, że widżet staje się widoczny natychmiast),
  • dodatkowe flagi,
  • numer identyfikacyjny widżetu,
  • wskaźnik do tekstu jaki zostanie wyświetlony na pasku tytułowym okna,
  • wskaźnik do funkcji zwrotnej.

Domyślnie po utworzeniu okno zawiera tylko pasek tytułowy oraz obszar klienta (Client window). Aby dodać przyciski minimalizacji, maksymalizacji oraz zamknięcia (tabela 2) wywołujemy trzy funkcje FRAMEWIN_Add<Close/Max/Min>Button() – wszystkie przyjmują uchwyt do okna, parametr rozmieszczenia (po lewej lub prawej stronie) oraz wartość przesunięcia przycisku. Jeśli chcemy aby tekst na pasku tytułowym był bardziej czytelny to za pomocą funkcji FRAMEWIN_SetFont() zmieniamy jego czcionkę (listę definicji czcionek można znaleźć w pliku GUI.h).

 

Tab. 2. Przyciski minimalizacji, maksymalizacji oraz zamknięcia okna [2]

Po utworzeniu okna możemy dodać do niego tekst za pomocą funkcji TEXT_CreateEx(). Znaczenia pierwszych czterech parametrów funkcji są podobne do tych jakie występują przy tworzeniu okna (wymiary widżetu określają tylko miejsce jakie może zajmować tekst, ale dopiero czcionka określa ile dokładnie jest zajmowane), piąty parametr to uchwyt do okna w jakim zostanie utworzony tekst, szósty parametr to flagi tworzenia (podobnie jak dla okna), siódmy parametr to atrybuty wyrównania tekstu (tabela 3), ósmy parametr tonumer ID widżetu, a ostatni parametr to wskaźnik do ciągu znakowego jaki zostanie wyświetlony.

 

Tab. 3. Dopuszczalne atrybuty wyrównania tekstu

TEXT_CF_LEFT Wyrównanie w poziomie do lewej
TEXT_CF_RIGHT Wyrównanie w poziomie do prawej
TEXT_CF_HCENTER Wyrównanie w poziomie do środka
TEXT_CF_TOP Wyrównanie w pionie do góry
TEXT_CF_BOTTOM Wyrównanie w pionie do dołu
TEXT_CF_VCENTER Wyrównanie w pionie do środka

 

Fot. 11. Efekt działania aplikacji okienkowej w zależności od wciśniętego przycisku

 

Ostatni krok to utworzenie przycisków za pomocą funkcji BUTTON_CreateEx() (znaczenie parametrów jest takie same jak podano powyżej). Minusem w tym przypadku może być konieczność tworzenia oddzielnych etykiet do nich. Ponieważ interesuje nas obsługa zdarzeń od wciśnięcia przycisków to deklarujemy funkcje zwrotne oraz przypisujemy je do konkretnych widżetów za pomocą funkcji WM_SetCallback(). Funkcja zwrotna przyjmuje wskaźnik do wiadomości typu WM_MESSAGE i na podstawie informacji w niej zawartejmoże ona określić jakie zdarzenia miały miejsce oraz zdecydować jakie czynności należy wykonać.

W taki oto sposób została stworzona prosta aplikacja okienkowa wykorzystująca 3 podstawowe komponenty interfejsu GUI. Z pozostałymi komponentami można się pobieżnie zapoznać na stronie biblioteki emWin [8].

Jan Szemiet

 

Literatura:

[1] K. Paprocki, Mikrokontrolery STM32 w praktyce, wydawnictwo BTC, Legionowo 2011

[2] UM03001: emWin, Graphic Library with Graphical User Interface, User & Reference Guide

[3] http://launchpad.net/gcc-arm-embedded – narzędzia kompilacji dla ARM

[4] http://mikrokontroler.pl/content/coocox-coide-i-stm32f4discovery-–-jak-zacząć

[5] http://www.coocox.org – środowisko CoIDE

[6] http://www.freertos.org/ – oficjalna strona systemu FreeRTOS

[7] http://www.segger.com/emwin.html – oficjalna strona biblioteki emWin

[8] http://www.segger.com/emwin-widgets.html – lista widżetów biblioteki emWin

[9] http://www.st.com/web/en/catalog/tools/PF259225 – oficjalna strona biblioteki STemWin

Do pobrania

Autor: admin

Admin