PODZESPOAY
Wykorzystaj USB
Implementacja klasy HID
interfejsu USB w STM32
Zmierzch ery interfejsów RS232 i LPT jest faktem niezaprzeczalnym. z myślą o urządzeniach takich jak klawiatura
czy mysz. W artykule przedstawiony zostanie
Interfejsy te, ze względu na prostotę obsługi programowej,
przykład implementacji klasy HID interfejsu USB
były bardzo chętnie wykorzystywane do komunikacji komputera
w mikrokontrolerze STM32 z grupy Performance
z najróżniejszymi urządzeniami elektronicznymi, zarówno tymi
Line (STM32F103) i wykorzystaniu jej do celów
budowanymi przez elektroników hobbystów, jak również przez
innych niż wskazuje na to pierwotne przezna-
profesjonalistów. Ale ich czas się dokonał. W artykule prezentujemy
czenie klasy HID.
sposób implementacji interfejsu USB w mikrokontrolerze STM32
z wykorzystaniem klasy HID (Human Interface Device), dla której Oprogramowanie dla PC
Zastosowanie dowolnego interfejsu komu-
większość systemów operacyjnych posiada wbudowane sterowniki.
nikującego budowane urządzenie elektroniczne
Pojawienie się 10 lat temu interfejsu USB pterów USB/RS232 po karty PCI/ExpressCard, z komputerem PC zawsze odbywa się na dwóch
doprowadziło do wyparcia archaicznych interfej- umożliwiające współpracę z urządzeniami wy- płaszczyznach: implementacji komunikacji po
sów RS232 i LPT. Proces wypierania ich w kom- magającymi interfejsów RS232 lub LPT. stronie mikrokontrolera oraz po stronie kom-
puterach stacjonarnych przebiegał stosunkowo W przypadku nowych urządzeń można za- putera PC. W przypadku interfejsu USB opro-
wolno, w przypadku komputerów przenośnych stosować specjalizowane układy scalone służące gramowanie komunikacji dla komputera PC jest
nieco szybciej. O ile jeszcze dwa, trzy lata temu za konwertery pomiędzy łączem USB a np. por- stosunkowo trudne do wykonania i w większości
problem z brakiem portów występował prak- tem szeregowym. Można również zastosować przypadków wymaga pisania własnych sterow-
tycznie tylko w przypadku komputerów prze- mikrokontroler z wbudowanym interfejsem ników sprzętu. Jednym z wyjątków od tej reguły
nośnych, tak teraz jest powszechny również USB, co jest chyba najbardziej uzasadnionym jest klasa HID (Human Interface Device). Jest ona
w przypadku komputerów stacjonarnych. ekonomicznie rozwiązaniem. pierwszą z klas interfejsu USB i powstała z myślą
Sposoby radzenia sobie z tym problemem Jedną z najprostszych do oprogramowania o urządzeniach służących do sterowania kom-
bywają różne: od nie zawsze działających ada- klas interfejsu USB jest klasa HID, opracowana puterem przez człowieka, takich jak klawiatura,
80 ELEKTRONIKA PRAKTYCZNA 3/2009
USB we własnym urządzeniu
myszka czy też joystick. Najważniejszą jej zaletą land nieco zmieniła branżę i przyszłość jej śro- stosowane są do zestawów STM3210B-EVAL
jest fakt, iż sterowniki są zawarte standardowo dowisk jest niepewna. Dlatego też zdecydowa- i STM3210E-EVAL.
w większości współczesnych systemów opera- łem się na wybór platformy .NET firmy Microsoft Przykładowa aplikacja w pierwotnej wersji
cyjnych. Dzięki temu urządzenie jest gotowe do oraz stosunkowo nowego języka programowa- umożliwiała włączenie 4 diod LED, odczyt war-
pracy prawie natychmiast po podłączeniu. nia C#. Ciekawostką jest fakt, iż język C# został tości napięcia podawanego z potencjometru
Oczywiście bezpośrednio po podłączeniu opracowany przez byłego głównego architekta oraz stanu dwóch przycisków. Aplikacja została
nowego urządzenia klasy HID sterowniki zosta- środowiska Delphi Andersa Hejlsberga. rozszerzona o możliwość sterowania dodatko-
ną zainstalowane automatycznie przez system Podstawowym środowiskiem do tworzenia wymi czterema diodami LED (zestaw ZL27ARM
operacyjny. Jak łatwo można się domyślić z prze- aplikacji dla platformy .NET jest Visual Studio fir- posiada ich osiem), oraz odczyt stanu dodatko-
znaczenia klasy HID prędkość transmisji nie jest my Microsoft. Jest to oprogramowanie komer- wych dwóch przycisków.
najwyższa. W przypadku interfejsu USB LowSpe- cyjne, jednak dobrą tradycją firmy Microsoft jest
ed (1,5 Mbit/s) maksymalna prędkość transmisji udostępnianie za darmo wersji Express Edition. Deskryptory
danych wynosi 0,8 kB/s. W przypadku interfejsu Z punktu widzenia osoby tworzącej proste pro- Najważniejszym plikiem jest usb_desc.c
USB FullSpeed (12 Mbit/s) prędkość transmisji gramy sterujące wykorzystywane prywatnie wer- zawierający deskryptory opisujące konfigurację
danych może osiągnąć wartość do 64 kB/s. sja Express Edition w zasadzie nie posiada żad- urządzenia USB. Pierwszym deskryptorem za-
Oprogramowanie dla komputera PC przed- nych znaczących ograniczeń. Brakuje tu przede wartym w pliku jest deskryptor urządzenia (De-
stawione w artykule zostało przygotowane dla wszystkim całej otoczki korporacyjnej, narzędzi vice Descriptor).
systemu Windows. Komunikacja z urządze- pracy zespołowej, zaawansowanych narzędzi do
niem klasy HID jest możliwa do zrealizowania obsługi baz danych itp. Jeżeli jednak ktoś z ja- Deskryptor urządzenia
poprzez wykorzystanie standardowych funkcji kichkolwiek przyczyn nie chce korzystać z środo- Zawiera takie informacje, jak wersję stan-
WinAPI służących do manipulacji plikami (File- wiska Visual Studio może wykorzystać dostępny dardu USB, numery identyfikujące producenta
Create, FileRead, FileWrite itp.). Gdy istotny jest na zasadach Open Source edytor SharpDevelop. (VendorID) oraz urządzenie (ProductID). Kod
jak najkrótszy czas realizacji aplikacji, to można Jest to IDE przeznaczone do pisania programów deskryptora DeviceDescriptor przedstawiono na
zastosować jedną z wielu gotowych bibliotek dla platformy .NET. Oczywiście konieczne jest list. 1
przeznaczonych do obsługi urządzeń klasy HID, posiadanie pakietu .NET SDK, który jest udostęp- Najistotniejszymi informacjami są numery
które znacznie upraszczają proces pisania apli- niany za darmo przez firmę Microsoft. idVendor oraz idProduct, które zostaną wy-
kacji dla PC. Jest to o tyle istotne, gdyż nie każdy korzystane do połączenia się z urządzeniem USB
elektronik, wykorzystujący mikrokontrolery. Oprogramowanie dla z poziomu aplikacji uruchomionej na kompu-
Wybór narzędzia programistycznego podyk- mikrokontrolera terze PC. Numerów tych w zasadzie nie należy
towany był zakładaną prostotą pisania aplikacji. Mikrokontrolery STM32, podobnie jak i po- modyfikować, gdyż VendorID (VID) jest nada-
Głównym założeniem było szybkie przygotowa- zostałe produkty firmy STMicroelectronics, mają wany członkom organizacji USB-IF (www.usb.
nie aplikacji, najlepiej z wykorzystaniem graficz- mocne wsparcie producenta w postaci bibliotek org). Numer ProductID (PID) jest określany we
nego. Jednymi z najbardziej znanych i lubianych programistycznych oraz przykładowych aplika- własnym zakresie przez posiadacza numeru VID.
są narzędzia opracowane przez firmę Borland, cji je wykorzystujących. Jedną z takich bibliotek Oczywiście do zastosowań prywatnych, czy też
czyli Delphi i C++ Builder. Niestety firma Bor- jest STM32F10xUSBLib przeznaczona do obsługi testów, można przypisać dowolne numery VID
interfejsu USB wraz z szeregiem przykładowych i PID, jednak absolutnie nie wolno tego robić
implementacji poszczególnych urządzeń inter- w przypadku urządzeń wprowadzanych na ry-
fejsu USB. Na potrzeby artykułu wykorzystano nek. W przypadku prezentowanej aplikacji po-
odpowiednio zmodyfikowaną aplikację Cus- zostawiamy oryginalne numery VID i PID. W sys-
tom_HID. Prezentuje ona zastosowanie klasy temie może pracować kilka urządzeń o identycz-
HID do realizacji urządzenia nie będącego jej ty- nych numerach VID i PID, więc naprawdę nie ma
powym przedstawicielem, lecz wykorzystującym potrzeby ich modyfikacji nawet, jeśli zamierza-
ją do własnych, zdefiniowanych przez programi- my zbudować kilka urządzeń pełniących różne
stę celów. Projekt dla środowiska Ride znajduje funkcje.
się w katalogu o następującej ścieżce dostępu:
USBLib\demos\Custom_HID\project\RIDE. Plik Deskryptor raportów
Custom_HID.rprj należy załadować do edytora Deskryptor raportów opisuje wszystkie
Ride. cechy raportów m.in. identyfikator, kierunek
Strukturę drzewa projektu aplikacji przed- transmisji raportu, rozmiar raportu, wartości
stawiono na rys. 1. Projekt składa się z trzech minimalne i maksymalne przyjmowane przez
grup plików zródłowych. W grupie Application raport i inne. Aplikacja demonstracyjna wyko-
files umieszczono pliki zawierające kod zasad- rzystuje 13 raportów po jednym dla każdego
niczej części programu oraz pliki biblioteki USB transmitowanego stanu elementu (8 diod LED,
charakteryzujące konkretne urządzenie. W gru- potencjometr i 4 przyciski). Ze względu na
pie USBLib znajdują się pozostałe pliki, których dużą objętość deskryptora przedstawiono tyl-
zawartość nie zależy od implementowanego ko wybrane jego fragmenty, charakteryzujące
urządzenia, ale zawiera funkcje podstawowej każdy z wykorzystywanych typów raportów.
konfiguracji interfejsu USB. W grupie FWLib Deskryptor raportu stanu diody LED (iden-
znajdują się pliki biblioteki programistycznej tyfikator raportu: 1) przedstawiono na list. 2.
dla pozostałych układów peryferyjnych mikro- Składa się on z dziesięciu pól, na każde pole
kontrolera STM32 wykorzystywanych w apli- przypadają dwa bajty: identyfikatora pola oraz
kacji. Niektóre pliki z grupy Application Files , wartości. Najistotniejsze są pola REPORT_ID
zmodyfikowano w celu dostosowania aplikacji oraz USAGE. Ich wartość odpowiada identyfi-
Rys. 1. Struktura drzewa projektu do zestawu ZL27ARM (www.kamami.pl), gdyż katorowi raportu. Deskryptor raportów zawie-
aplikacji te dostarczone przez STMicroelectronics przy- ra osiem takich struktur, które różnią się war-
ELEKTRONIKA PRAKTYCZNA 3/2009 81
PODZESPOAY
Transfer stanu potencjometru P2
List. 1. Kod zródłowy deskryptora urządzenia
/* USB Standard Device Descriptor */
Odczyt wyniku pomiaru przetwornika ADC
const u8 CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
{ zrealizowano za pomocą układu DMA. Po każ-
0x12, //bLength
dym zakończonym pomiarze wynik transmi-
USB_DEVICE_DESCRIPTOR_TYPE, //bDescriptorType
0x00, //bcdUSB
towany jest bez pośrednictwa CPU do pamięci
0x02,
danych. Po zakończeniu przez układ DMA trans-
0x00, //bDeviceClass
0x00, //bDeviceSubClass
feru danych zgłaszane jest przerwanie. Kod pro-
0x00, //bDeviceProtocol
0x40, //bMaxPacketSize = 40 cedury przerwania od kanału DMA przedstawio-
0x83, //VendorID = 0x0483
ny jest na list. 7.
0x04,
0x50, //ProductID = 0x5750
W celu wyeliminowania cyklicznego trans-
0x57,
feru przez łącze USB identycznych wyników
0x00, //bcdDevice rel. 2.00
0x02,
pomiarów sprawdzana jest różnica pomiarów:
1, //Index of string descriptor describing manufacturer
2, //Index of string descriptor describing product
aktualnego i poprzedniego (po ogranicze-
3, //Index of string descriptor describing the device serial number
niu rozdzielczości do 8 bitów). Jeżeli jest ona
0x01 //bNumConfigurations
}
większa od 4, to raport z wynikiem pomiaru
; /* CustomHID_DeviceDescriptor */
napięcia jest kopiowany do endpointu nadaw-
czego.
List. 2. Kod deskryptora raportu LED
/* Led 1 */
Oprogramowanie dla komputera
0x85, 0x01, //REPORT_ID (1)
0x09, 0x01, //USAGE (LED 1)
PC
0x15, 0x00, //LOGICAL_MINIMUM (0)
0x25, 0x01, //LOGICAL_MAXIMUM (1) Jak już wspomniano na wstępie, oprogra-
0x75, 0x08, //REPORT_SIZE (8)
mowanie dla komputera PC napisano w języku
0x95, 0x01, //REPORT_COUNT (1)
0xB1, 0x82, //FEATURE (Data,Var,Abs,Vol)
C# dla platformy .NET 2.0. Wykorzystano biblio-
0x85, 0x01, //REPORT_ID (1)
tekę HIDLibrary, której autorem jest Michael P.
0x09, 0x01, //USAGE (LED 1)
0x91, 0x82, //OUTPUT (Data,Var,Abs,Vol)
O Brien (www.mike-obrien.net). Bibliotekę tę
napisano w języku Visual Basic.NET. Dostępna
tościami REPORT_ID oraz USAGE. Deskryptor cą instrukcji switch. Po modyfikacji odpowied- jest w postaci zródłowej oraz pliku DLL na stro-
raportu stanu potencjometru (raport o identy- niego wyjścia ustawiany jest odpowiedni status nie autora. Nie jest to oczywiście jedyna bibliote-
fikatorze 9) przedstawiono na list. 3. endpointa odbiorczego informujący o przetwo- ka ułatwiająca korzystanie z klasy HID interfejsu
Podstawową różnicą w stosunku do po- rzeniu odebranych danych. USB. Na stronie www.lvr.com/hid_page znajduje
przedniego deskryptora jest wartość pola LO- się zbiór odnośników do projektów i bibliotek
GICAL_MAXIMUM, które w przypadku raportu Transfer stanu przycisków oprogramowania dla klasy HID.
stanu potencjometru przyjmuje wartość 255. Stan przycisków zestawu ZL27ARM trans- Czytelnik powinien posiadać zainstalowa-
Należy zwrócić uwagę, że wartość tego pola mitowany jest z mikrokontrolera do komputera ne środowisko Visual C# 2008 Express Edition,
jest typu signed i musi być zapisana na 16 bi- PC z wykorzystaniem endpointa nadawczego komercyjną wersję środowiska Visual Studio
tach. W przeciwnym razie stała 0xFF potrakto- i raportów o numerach 10-13. Przyciski SW0- 2008 lub program SharpDevelop wraz z .NET
wana zostałaby jako wartość 128 co byłoby -SW3 są podłączone do wyprowadzeń PA0-PA3, 2.0 Software Development Kit (SDK). Visual C#
błędem. Deskryptor raportu stanu przycisku a więc do linii EXTI0-EXTI3. W ramach procedur 2008 EE umożliwia tworzenie aplikacji wyłącz-
przedstawiono na list. 4. obsługi przerwań Exti0-Exti3 formowany jest nie dla .NET Framework w wersji 3.5, natomiast
Raport ten składa się z dwóch części: zmien- odpowiedni raport z danymi zależnymi od stanu w chwili pisania artykułu środowisko SharpDe-
nej o rozmiarze jednego bitu, która odpowiada przycisku, który wywołał przerwanie. Kod pro- velop było dostępne tylko dla .NET Framework
stanowi przycisku oraz stałej o rozmiarze 7-bi- cedury obsługi przerwania EXTI0 przedstawiono w wersji 2.0. Nie ma to większego znaczenia,
tów. na list. 6. Pozostałe trzy procedury różnią się tyl- gdyż żadna z technologii udostępnianych przez
ko numerem linii przerwania oraz ID raportu. .NET 3.5 nie będzie w projekcie wykorzystywa-
Transfer stanu diod LED
Stan diod LED transmitowany jest z aplikacji
List. 3. Kod deskryptora raportu potencjometru
/* Potencjometr P1 */
uruchomionej na komputerze do mikrokontro-
0x85, 0x09, //REPORT_ID (9)
lera za pomocą ośmiu raportów o numerach ID 0x09, 0x09, //USAGE (P1)
0x15, 0x00, //LOGICAL_MINIMUM (0)
z zakresu 1-8. Po odebraniu przez mikrokontro-
0x26, 0xff, 0x00, //LOGICAL_MAXIMUM (255)
0x75, 0x08, //REPORT_SIZE (8)
ler raportu wywoływana jest procedura EP1_
0x81, 0x82, //INPUT (Data,Var,Abs,Vol)
OUT_Callback, w ramach której podejmowana
0x85, 0x09, //REPORT_ID (9)
0x09, 0x09, //USAGE (P1)
jest reakcja na nadesłane w raporcie dane. Pro-
0xb1, 0x82, //FEATURE (Data,Var,Abs,Vol)
cedura ta jest zdefiniowana w pliku usb_endp.c.
Kod procedury EP1_OUT_Callback przedstawio-
no na list. 5.
List. 4. Kod deskryptora przycisku
/* Przycisk SW0 */
Na początku procedury danych z endpoin-
0x85, 0x0A, //REPORT_ID (10)
ta odbiorczego kopiowane są do tablicy Rece- 0x09, 0x0A, //USAGE (SW0)
0x15, 0x00, //LOGICAL_MINIMUM (0)
ive_Buffer, która reprezentuje odebrany raport.
0x25, 0x01, //LOGICAL_MAXIMUM (1)
0x75, 0x01, //REPORT_SIZE (1)
Następnie sprawdzany jest stan elementu tablicy
0x81, 0x82, //INPUT (Data,Var,Abs,Vol)
o indeksie równym jeden, a więc stan diody LED.
0x09, 0x0A, //USAGE (SW0)
0x75, 0x01, //REPORT_SIZE (1
W zależności od wartości tego elementu tablicy
0xb1, 0x82, //FEATURE (Data,Var,Abs,Vol)
0x75, 0x07, //REPORT_SIZE (7)
odpowiednio modyfikowana jest zmienna Led_
0x81, 0x83, //INPUT (Cnst,Var,Abs,Vol)
State. Następnie w zależności od ID raportu stan
0x85, 0x0A, //REPORT_ID (10)
0x75, 0x07, //REPORT_SIZE (7)
diody LED zostanie przypisany do odpowiadają-
0xb1, 0x83, //FEATURE (Cnst,Var,Abs,Vol)
cego jej wyjścia GPIO mikrokontrolera za pomo-
82 ELEKTRONIKA PRAKTYCZNA 3/2009
USB we własnym urządzeniu
List. 5. Kod procedury EP1_OUT_Callback
problemy to w katalogu References drzewa pro-
void EP1_OUT_Callback(void)
jektu powinna się pojawić pozycja HIDLibrary.
{
BitAction Led_State;
PMAToUserBufferCopy(Receive_Buffer, ENDP1_RXADDR, 2);
if (Receive_Buffer[1] == 0) Okno aplikacji
{
Wygląd projektu okna aplikacji demonstra-
Led_State = Bit_RESET;
}
cyjnej przedstawiony jest na rys. 2. Lista rozwi-
else
jalna comboBox1 służy do wyboru urządzenia
{
Led_State = Bit_SET;
klasy HID, z którym będzie komunikować się
}
switch (Receive_Buffer[0]) // jakie ID raportu ?
aplikacja. Po wybraniu urządzenia z listy, w celu
{
połączenia się z wybranym urządzeniem, należy
case 1: /* Led 1 */
GPIO_WriteBit(GPIOB, GPIO_Pin_8, Led_State);
kliknąć przycisk Połącz. Okienka checkBox1& 8
break;
case 2: /* Led 2 */ (grupa Diody LED) służą do ustawiania stanu
GPIO_WriteBit(GPIOB, GPIO_Pin_9, Led_State);
diod LED zestawu ZL27ARM. Komponenty pane-
break;
case 3: /* Led 3 */
l1& 4 (grupa Przyciski) służą do wizualizacji sta-
GPIO_WriteBit(GPIOB, GPIO_Pin_10, Led_State);
nu przycisków zestawu ZL27ARM. Kolor zielony
break;
case 4: /* Led 4 */
symbolizuje przycisk zwolniony, natomiast czer-
GPIO_WriteBit(GPIOB, GPIO_Pin_11, Led_State);
break;
wony przycisk naciśnięty. Komponent progress-
case 5: /* Led 5 */
Bar1 (grupa Potencjometr) służy do wizualizacji
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Led_State);
break;
wartości podawanej na wejście przetwornika
case 6: /* Led 6 */
GPIO_WriteBit(GPIOB, GPIO_Pin_13, Led_State); analogowo-cyfrowego z potencjometru P1 ze-
break;
stawu ZL27ARM.
case 7: /* Led 7 */
GPIO_WriteBit(GPIOB, GPIO_Pin_14, Led_State);
break;
Wykorzystywane zmienne
case 8: /* Led 8 */
GPIO_WriteBit(GPIOB, GPIO_Pin_15, Led_State);
Aplikacja tworzy dwa wątki: do zapisu oraz
break;
default:
do odczytu danych z urządzenia HID. Wątek
GPIO_Write(GPIOB, ~(GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_
zapisu raportów wyjściowych jest reprezento-
Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15));
break;
wany przez zmienną WriteThread, natomiast
}
SetEPRxStatus(ENDP1, EP_RX_VALID); wątek odczytu raportów wejściowych przez
}
zmienną ReadThread. Stan wszystkich wyko-
rzystywanych elementów zestawu ZL27ARM
przechowywany jest w zmiennych globalnych
List. 6. Kod procedury obsługi przerwania
void EXTI0_IRQHandler(void)
LED, Buttons oraz AnalogValue. Zmienne
{
te wykorzystywane są do przekazywania da-
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
nych o stanie poszczególnych elementów po-
Send_Buffer[0] = 0xA; // ID raportu
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET) między wątkami służącymi do zapisu i odczytu
{
raportów a pozostałą częścią aplikacji. Tablica
Send_Buffer[1] = 0x01; // przycisk naciśnięty
}
HID przechowuje wynik enumeracji wszystkich
else
urządzeń HID zainstalowanych w systemie.
{
Send_Buffer[1] = 0x00; // przycisk zwolniony
Wynik ten może obejmować wszystkie urzą-
}
// skopiowanie raportu do endpointa
dzenia klasy HID lub też urządzenia o poda-
UserToPMABufferCopy(Send_Buffer, ENDP1_TXADDR, 2);
nych identyfikatorach VID oraz PID. Zmienna
SetEPTxCount(ENDP1, 2); // Rozmiar danych w endpoincie
SetEPTxValid(ENDP1); // Dane w endpoincie kompletne
MyHID reprezentuje urządzenie, z którym
EXTI_ClearITPendingBit(EXTI_Line0); aplikacja będzie wymieniać dane. Deklaracje
}
wszystkich zmiennych globalnych przedsta-
}
wiono na list. 8.
na, więc przedstawiona aplikacja powinna po- czynnością należy wykonać jest dodanie refe- Enumeracja urządzeń HID
siadać identyczną funkcjonalność, niezależnie rencji do biblioteki HIDLibrary.dll. W tym celu Proces enumeracji urządzeń dokonywany
od wersji frameworka .NET. należy prawym przyciskiem myszy kliknąć na jest na etapie ładowania formularza aplikacji
folder References drzewa projektu a następnie (zdarzenie FormLoad()). Fragment kodu od-
Tworzenie aplikacji z menu kontekstowego wybrać opcję Add Re- powiedzialny za enumerację urządzeń przedsta-
wykorzystującej bibliotekę ference. Ukaże się okno Add Reference. Należy wiono na list. 9.
HIDLibrary.dll wybrać zakładkę Browse i wskazać plik bibliote- Zakres poszukiwań urządzeń HID został
Proces tworzenia aplikacji przedstawiono ki HIDLibrary.dll. Jeśli nie wystąpiły żadne ograniczony do urządzeń o podanych identyfi-
na przykładzie środowiska VisualC# 2008 EE. Po
uruchomieniu środowiska programistycznego
List. 7. Kod procedury obsługi przerwania od DMA
void DMA1_Channel1_IRQHandler(void)
należy utworzyć nowy projekt typu Windows
{
Forms Application. Główną część okna zajmie
Send_Buffer[0] = 0x09;
if((ADC_ConvertedValueX >> 4) - (ADC_ConvertedValueX_1 >> 4) > 4)
Form Designer, służący do projektowania wy-
{
Send_Buffer[1] = (u8)(ADC_ConvertedValueX >> 4);
glądu okna aplikacji. Po lewej stronie okna jest
UserToPMABufferCopy(Send_Buffer, ENDP1_TXADDR, 2);
ukryty Toolbox zawierający komponenty gra-
SetEPTxCount(ENDP1, 2);
SetEPTxValid(ENDP1);
ficzne. Ukaże się on po najechaniu kursorem na
ADC_ConvertedValueX_1 = ADC_ConvertedValueX;
pole z napisem Toolbox. Po prawej stronie okna }
DMA_ClearFlag(DMA1_FLAG_TC1);
znajduje się Solution Explorer, który przedstawia
}
strukturę plików i folderów projektu. Pierwszą
ELEKTRONIKA PRAKTYCZNA 3/2009 83
PODZESPOAY
nej MyUSB. Następnie w zależności od wartości
List. 8. Deklaracje zmiennych globalnych
// Wątki odczytu i zapisu do urządzenia HID
właściwości ReportID dane z raportu przypisy-
Thread WriteThread, ReadThread;
// tablica urządzeń klasy HID wane są albo do zmiennej AnalogValue, albo
HIDLibrary.HidDevice[] HID;
do jednej z czterech pozycji tablicy Buttons.
// urządzenie klasy HID
HIDLibrary.HidDevice MyHID;
Kod wątku realizującego odczyt raportów wej-
// zmienna przechowująca stan potencjometru
ściowych przedstawiono na list. 11.
byte AnalogValue;
// tablica przechowująca stan przycisków
byte[] Buttons = new byte[4];
// tablica przechowująca stan diod LED Zapis raportów wyjściowych
byte[][] LED = {
Działanie wątku rozpoczyna się od utworze-
new byte[1] { 0 },
new byte[1] { 0 },
nia zmiennej OutputReport, która reprezentu-
new byte[1] { 0 },
new byte[1] { 0 }, je zapisywany do urządzenia raport. Następnie
new byte[1] { 0 },
w pętli nieskończonej wykonywana jest zasa-
new byte[1] { 0 },
new byte[1] { 0 },
dnicza część kodu odpowiedzialna za transfer
new byte[1] { 0 },
do urządzenia HID raportów z danymi. W celu
};
// tablica przechowująca informacje o konieczności zapisu do urządzenia HID
wyeliminowania niepotrzebnych transferów
byte[] pUpdate = new byte[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
danych sprawdzany jest stan każdej pozycji
katorach VID i PID, które są właściwe dla apli-
kacji demonstracyjnej zestawu ZL27ARM. Po
dokonaniu enumeracji następuje sprawdzenie,
czy w tablicy HID znajdują się jakieś dane, to
znaczy czy znaleziono przynajmniej jedno urzą-
dzenie klasy HID. Jeśli warunek sprawdzenia jest
spełniony, to następuje wypełnienie kontrolki
comboBox1 pozycjami reprezentującymi każde
odnalezione urządzenie. W przeciwnym razie
wyświetlany jest komunikat informujący, że nie
znaleziono żadnego urządzenia HID.
Podłączenie do urządzenia HID
Podłączenie do urządzenia HID dokonywane
jest w ramach obsługi zdarzenia OnClick przy-
cisku button1. Kod handlera tego zdarzenia Rys. 2. Okno projektu aplikacji demonstracyjnej
przedstawiono na list. 10.
Na początku sprawdzana jest właściwość
List. 9. Fragment programu odpowiedzialny za enumerację
HID = HidDevices.Enumerate(0x0483, 0x5750);
SelectedIndex komponentu comboBox1,
if (HID.Length > 0)
mówiąca o tym, która pozycja listy została wy- {
for (int i = 0; i < HID.Length; i++)
brana. Jeśli właściwość ta ma wartość większą
{
od -1 to oznacza, że jedna z pozycji została comboBox1.Items.Add( HID device + i.ToString() +
ver. + HID[i].Attributes.Version.ToString());
wybrana i realizowane jest podłączenie do urzą-
}
}
dzenia HID. W przeciwnym razie wyświetlany
else
jest komunikat mówiący, iż nie zostało wybra- {
MessageBox.Show( Nie znaleziono żadnego urządzenia HID! );
ne żadne urządzenie z listy. Samo podłączenie
}
sprowadza się do przypisania do zmiennej My-
HID wybranej pozycji z tablicy HID i wywołaniu
metody OpenDevice(). Następnie tworzone
List. 10. Kod handlera obsługi zdarzenia
private void button1_Click(object sender, EventArgs e)
są i uruchamiane wątki WriteThread oraz
{
ReadThread. Pozostała część kodu odpowiada
if (comboBox1.SelectedIndex > -1)
{
za zmianę stanu właściwości Enabled wykorzy-
MyHID = HID[comboBox1.SelectedIndex];
stywanych kontrolek oraz ustawienie na pasku MyHID.OpenDevice();
if (MyHID.IsOpen == true)
statusu aplikacji napisu Połączony .
{
WriteThread = new Thread(WriteOutputReports);
WriteThread.Start();
Odczyt raportów wejściowych
ReadThread = new Thread(ReadInputReports);
ReadThread.Start();
Działanie wątku rozpoczyna się od utworze-
button2.Enabled = true;
nia zmiennej InputReport, która reprezentuje button1.Enabled = false;
groupBox1.Enabled = true;
odczytany raport wejściowy. Argument konstruk-
checkBox1.Enabled = true;
checkBox2.Enabled = true;
tora tej zmiennej określa rozmiar raportu w baj
checkBox3.Enabled = true;
tach i jest odczytywany z właściwości InputR checkBox4.Enabled = true;
checkBox5.Enabled = true;
eportByteLength podłączonego urządzenia.
checkBox6.Enabled = true;
checkBox7.Enabled = true;
Ponieważ wątek uruchamiany jest tylko raz
checkBox8.Enabled = true;
(po podłączeniu urządzenia) musi wykonywać
toolStripStatusLabel1.Text = Połączony ;
}
się w pętli nieskończonej. W tej pętli następuje
}
sprawdzenie, czy zmienna MyUSB jest właściwie else
MessageBox.Show( Nie wybrano urządzenia );
zainicjowana. Jeśli tak, to za pomocą metody
}
ReadReport() odczytywany jest raport zmien-
84 ELEKTRONIKA PRAKTYCZNA 3/2009
USB we własnym urządzeniu
zainstalować niezbędne sterowniki. Jeśli ste-
List. 11. Kod wątku realizującego odczyt raportów wejściowych
void ReadInputReports()
rowniki zostały poprawnie zainstalowane,
{
należy uruchomić aplikację demonstracyjną.
HIDLibrary.HidReport InputReport =
new HIDLibrary.HidReport(MyUSB.Capabilities.InputReportByteLength);
W przypadku nie znalezienia urządzenia
while (true)
{ o określonych w kodzie programu numerach
if (MyUSB != null)
VID i PID, wyświetlony zostanie odpowiedni
{
InputReport = MyUSB.ReadReport();
komunikat. W przeciwnym razie powinno
switch (InputReport.ReportId)
ukazać się okno aplikacji demonstracyjnej.
{
case 0x9: AnalogValue = InputReport.Data[0]; break;
Z listy comboBox1 należy wybrać pozycję
case 0xA: Buttons[0] = InputReport.Data[0]; break;
case 0xB: Buttons[1] = InputReport.Data[0]; break;
odpowiadającą urządzeniu HID. W przypadku
case 0xC: Buttons[2] = InputReport.Data[0]; break;
podłączenia jednego zestawu na liście powin-
case 0xD: Buttons[3] = InputReport.Data[0]; break;
}
na znajdować się jedna pozycja. Po wybraniu
Thread.Sleep(20);
} urządzenia należy kliknąć przycisk Połącz .
}
Jeśli pomyślnie nawiązano połączenie
}
z urządzeniem HID kontrolki checkBox1& 8
zostaną uaktywnione. Od tej chwili stan tych
List. 12. Kod wątku realizującego zapis raportów wyjściowych kontrolek będzie odwzorowywany na diodach
void WriteOutputReports()
LED zestawu ZL27ARM zaznaczony check-
{
HIDLibrary.HidReport OutputReport =
Box odpowiada włączonej diodzie LED, natomi-
new HIDLibrary.HidReport(MyUSB.Capabilities.OutputReportByteLength);
ast pusty wyłączonej. Pozostałe elementy ap-
while (true)
{
likacji demonstracyjnej służą do odwzorowania
if (MyUSB != null)
{
stanu przycisków i potencjometru, więc
for (byte i = 0; i < 8; i++)
w celu sprawdzenia działania aplikacji należy
{
if (pUpdate[i] == 1)
nacisnąć dowolny z przycisków SW0...SW3
{
pUpdate[i] = 0; lub pokręcić osią potencjometru P1. Wartość
OutputReport.ReportId = (byte)(i + 1);
napięcia podawanego przez potencjometr
OutputReport.Data = LED[i];
MyUSB.WriteReport(OutputReport);
na wejście przetwornika analogowo-cy-
}
frowego zostanie odwzorowana w postaci
Thread.Sleep(20);
}
paska postępu. Z kolei naciśnięty przycisk
}
}
będzie reprezentowany przez czerwony kolor
}
odpowiadającego mu panelu. Na tym kończą
się możliwości przedstawionej aplikacji
demonstracyjnej a otwiera się szerokie pole
List. 13. Kod handlera obsługi zdarzenia generowanego przez timer
private void timer1_Tick(object sender, EventArgs e)
do wykorzystania przedstawionej biblioteki
{
oraz mikrokontrolerów STM32 we własnych
progressBar1.Value = AnalogValue;
aplikacjach wykorzystujących interfejs USB
if (Buttons[0] == 1)
panel1.BackColor = Color.Red; do niewymagających dużej prędkości trans-
else
ferów danych pomiędzy komputerem PC
panel1.BackColor = Color.Green;
if (Buttons[1] == 1)
a urządzeniem z mikrokontrolerem STM32.
panel2.BackColor = Color.Red;
Przedstawiona aplikacja zajmuje nieco
else
panel2.BackColor = Color.Green;
ponad 8 KB pamięci Flash, co w przypadku mi-
if (Buttons[2] == 1)
panel3.BackColor = Color.Red;
krokontrolera STM32F103VBT6 jest ułamkiem
else
całej dostępnej pamięci programu.
panel3.BackColor = Color.Green;
if (Buttons[3] == 1)
panel4.BackColor = Color.Red;
else Podsumowanie
panel4.BackColor = Color.Green;
Temat oprogramowania interfejsu USB,
}
zarówno po stronie mikrokontrolera, jak
i komputera PC, jest na tyle szeroki, że trudno
tablicy pUpdate i w sytuacji, gdy któryś z ele- się w ramach handlera zdarzenia OnTimer przedstawić całość zagadnienia w ramach jedne-
mentów tablicy ma wartość 1, transmitowany Timera 1. Kod handlera zdarzenia przed- go artykułu. W artykule przedstawiono sposób
jest odpowiedni raport zawierajacy stan diody stawiono na list. 13. na postawienie pierwszych kroków na drodze
LED. Kod wątku realizującego zapis raportów programowania interfejsu USB. Droga ta jest ni-
wyściowych do urządzenia HID przedstawiono Obsługa aplikacji estety bardzo długa i wymaga szczegółowego
na list. 12. demonstracyjnej zagłębienia się tak w specyfikacje standardu, jak
Zestaw ZL27ARM z zaprogramowanym i informacje oraz przykładowe aplikacje dostarc-
Aktualizacja stanu kontrolek mikrokontrolerem należy podłączyć do złącza zane przez producenta mikrokontrolerów
wizualnych USB komputera przed uruchomieniem ap- STM32.
Aktualizacja stanu kontrolek wejściowych likacji demonstracyjnej. System powinien au- Radosław Kwiecień, EP
na podstawie odczytanych danych odbywa tomatycznie wykryć nowe urządzenie oraz radoslaw.kwiecien@ep.com.pl
forum.ep.com.pl
ELEKTRONIKA PRAKTYCZNA 3/2009 85
Wyszukiwarka
Podobne podstrony:
07 Java klasy abstrakcyjne, interfejsy, polimorfizm 0Uniwersalny modu‡ interfejsowy USBProgramowy interfejs USB w AVRQART Serwis s c Pamięci flash z interfejsem USB USB 2 0USB InterfaceJava Klasy Interfejsy1 KROK Instalacja interfejsu BMW USB i INPY5 0Instrukcja interfejs Renault USBVAG Tacho USB interface info04b USB Audio InterfaceUSB Uniwersalny interfejs szeregowy komusbInstrukcja instalacji interfejsu ELM327 USBMikrokontrolery STM32 Użycie interfejsu I2C, USART, SPIBootloader dla mikrokontrolerów STM32 Aktualizacja oprogramowanie z zastosowaniem karty SD lub przdesign user interface?ABE09FSTM32 Butterfly RS232PS4 ZB4 501 UM3 UM4 Interface Converter h1371gwięcej podobnych podstron