Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'HID'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - DIY
    • Projekty - DIY roboty
    • Projekty - DIY (mini)
    • Projekty - DIY (początkujący)
    • Projekty - DIY w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie

Kategorie

  • Quizy o elektronice
  • Quizy do kursu elektroniki I
  • Quizy do kursu elektroniki II
  • Quizy do kursów Arduino
  • Quizy do kursu STM32L4
  • Quizy do pozostałych kursów

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Imię


Strona

Znaleziono 1 wynik

  1. W przypływie wolnego czasu chciałem przećwiczyć sobie obsługę USB w STM32 i przy okazji zrobić coś praktycznego do podłączenia do komputera. Ponieważ mam klawiaturę mechaniczną z przyciskami multimedialnymi ukrytymi pod mało praktyczną kombinacją z klawiszem FN (klawisz po prawej stronie - totalnie niepraktyczne w tym zastosowaniu) postanowiłem zrobić sobie dedykowany pilot do multimediów. Platforma STM32F103 bo mam mały zapas płytek BluePill. Jako sterowanie wybrałem joystick z enkoderem na wzór tych z systemów infotainment w samochodzie. Żeby doprecyzować joysticki ALPS RKJXT1F42001 zamówione jakiś czas temu na aliexpress i czekające na projekt jak ten. Kod na STM32 powstawał na bazie generowanego przez CubeIDE przy middleware USB_DEVICE z wybranym Human Interface Device Class (HID). W moim odczuciu generowany kod jest chyba bardziej demonstracją, ponieważ kod z definicjami deskryptorów jest stworzony dla myszy, i nie ma nigdzie znaczników USER_CODE_BEGIN/END. Próbowałem coś zadziałać z klasą Custom Human Interface Device ale mogłem znaleźć deskryptorów urządzenia, konfiguracji i interfejsu w kodzie, a deskryptor raportu HID był do napisania od zera, co jest raczej trudne przy pierwszym projekcie z USB. Zostałem przy przykładzie z myszką od ST, który sukcesywnie modyfikowałem, tworząc kopie zapasowe na wypadek potrzeby generowania kodu z Cube (przez brak znaczników USER_CODE wszystkie zmiany - głównie zmodyfikowany deskryptor raportu - byłyby nadpisane przez wygenerowany kod). Nie będę opisać tworzenia mojego deskryptora bo robiłem to raczej na czuja metodą prób i błędów. W skrócie chodzi o to, że deskryptor raportu HID informuje host(komputer) o możliwościach urządzenia oraz przypisuje funkcjonalności bajtom w raporcie HID - w moim przypadku każdy bit w drugim bajcie raportu niesie informacje o wciśnięciu przycisku z grupy consumer page (0x0C) (więcej o nich w dokumentacji USB HID - HID Usage Tables 1.12). Utworzenie deskryptora od zera jest raczej trudne dla początkującego ale w internecie jest sporo informacji - wielką pomocą był dla mnie raport z przykładowej implementacji (http://www2.ece.rochester.edu/~parihar/pres/Report_MultiMedia-KB.pdf) w którym o wiele lepiej wytłumaczono działanie USB, klas i deskryptorów, niż ja to jestem w stanie zrobić. Oprócz tego mój deskryptor raportu jest lekko zmodyfikowaną wersją tego spod linku. Deskryptory urządzenia, konfiguracji i interfejsu wykorzystałem w wersji wygenerowanej przez cube dla myszy - zmieniłem jedynie typ urządzenia na klawiaturę (0x01) w deskryptorze konfiguracji (Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c). Deskryptor raportu powstał na podstawie tego podlinkowanego. Mapowanie przycisków do bitów w raporcie jest tam zobrazowane na stronie 11. Dobry tutorial o deskryptorach raportów HID tutaj. Gotowy deskryptor raportu przedstawia się tak: 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) 0x09, 0x01, // USAGE (Consumer Control) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x10, // REPORT_COUNT (16) 0x09, 0xe2, // USAGE (Mute) 0x01 0x09, 0xe9, // USAGE (Volume Up) 0x02 0x09, 0xea, // USAGE (Volume Down) 0x03 0x09, 0xcd, // USAGE (Play/Pause) 0x04 0x09, 0xb7, // USAGE (Stop) 0x05 0x09, 0xb6, // USAGE (Scan Previous Track) 0x06 0x09, 0xb5, // USAGE (Scan Next Track) 0x07 0x0a, 0x8a, 0x01, // USAGE (Mail) 0x08 0x0a, 0x92, 0x01, // USAGE (Calculator) 0x09 0x0a, 0x21, 0x02, // USAGE (www search) 0x0a 0x0a, 0x23, 0x02, // USAGE (www home) 0x0b 0x0a, 0x2a, 0x02, // USAGE (www favorites) 0x0c 0x0a, 0x27, 0x02, // USAGE (www refresh) 0x0d 0x0a, 0x26, 0x02, // USAGE (www stop) 0x0e 0x0a, 0x25, 0x02, // USAGE (www forward) 0x0f 0x0a, 0x24, 0x02, // USAGE (www back) 0x10 0x81, 0x62, // INPUT (Data,Var,Abs,NPrf,Null) 0xc0 I definicje bitów dla przycisków oraz zmiennej przechowującej raport HID do wysłania #define HID_REPORT_SIZE 3 #define MEDIA_MUTE 0 #define MEDIA_VOLUP 1 #define MEDIA_VOLDOWN 2 #define MEDIA_PLAY_PAUSE 3 #define MEDIA_STOP 4 #define MEDIA_PREV 5 #define MEDIA_NEXT 6 /* USER CODE END PD */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim1; /* USER CODE BEGIN PV */ extern USBD_HandleTypeDef hUsbDeviceFS; uint8_t HID_report[HID_REPORT_SIZE] = {0x01,0,0}; //empty hid report W celu zakomunikowania hostowi wciśnięcia przycisku wysyłamy raport HID z ustawionym bitem odpowiadającym wciśniętemu przyciskowi. Przykładowo dla przycisku VOL_UP ustawić należy drugi bit w drugim bajcie raportu. Ponieważ należy zasymulować wciśniecie i zwolnienie przycisku należy wysłać po chwili drugi raport z samymi zerami. Ważne jest też zachowanie co najmniej 10 ms odstępu między wysyłaniem raportów, by dać czas na przetworzenie informacji bibliotece USB na STMie oraz hostowi (komputerowi). Poniżej kod w funkcji main() obsługujący wysyłanie raportów o wciśnięciu przycisków HID_report[1]=0; //0 means none of the buttons pressed ////THIS CODE CAN SUPPORT ONLY 1 KEY AT A TIME, AND VERY SLOW REPEAT WITH LONG PRESS//// CheckButtonsState(); //check if any button is pressed and set appropriate bits in HID_report[1] if(HID_report[1]!=0){ USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); //send key-press and after 15 ms key-release reports HAL_Delay(400); HID_report[1]=0; USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); } Funkcja CheckButtonsState() ustawia na podstawie stanów logicznych na wejściach uC, bity w 2 bajcie tablicy uint8_t przechowującej raport HID. void CheckButtonsState(){ if(!HAL_GPIO_ReadPin(PUSH_GPIO_Port, PUSH_Pin)) { //push input is low when whichever button is pressed uint8_t isPushPressed=1; if(!HAL_GPIO_ReadPin(RIGHT_GPIO_Port, RIGHT_Pin)) {SetKeyPress(MEDIA_NEXT); isPushPressed=0; } if(!HAL_GPIO_ReadPin(LEFT_GPIO_Port, LEFT_Pin)) {SetKeyPress(MEDIA_PREV); isPushPressed=0; } if(!HAL_GPIO_ReadPin(UP_GPIO_Port, UP_Pin)) {SetKeyPress(MEDIA_MUTE); isPushPressed=0; } if(!HAL_GPIO_ReadPin(DOWN_GPIO_Port, DOWN_Pin)) {SetKeyPress(MEDIA_STOP); isPushPressed=0; } if(isPushPressed==1){SetKeyPress(MEDIA_PLAY_PAUSE);} } } void SetKeyPress(uint8_t key){ HID_report[1] |= 1<<key; } Zastosowany joystick ALPS jest tak skonstruowany, że wciśnięcie jakiegokolwiek przycisku zwiera także wyprowadzenie PUSH odpowiadające wciśnięciu joysticka. Z tego powodu funkcja jest napisana tak, że jeżeli na wejściu PUSH jest 1 to na każdym innym musi być 1 (styki otwarte). Jeżeli wciśnięty jest PUSH (logiczne 0) ale też 0 jest na pinie od innego przycisku, oznacza to że wciśnięto inny przycisk, a stan na wejściu PUSH jest ignorowany. Jeżeli 0 jest tylko na wejściu PUSH, oznacza to że joystick rzeczywiście został wciśnięty. Takie rozwiązanie prosi się aż o generowanie przerwania z wejścia PUSH i wykonywania kodu wtedy. Ponieważ jestem leniwy i miałem już gotowy kod do wysyłania raportów HID kiedy to odkryłem, zostałem przy pollingu stanu na wejściach. Delay po wysłaniu raportu rozwiązuje mi także problem z debouncingiem przycisków (obserwowałem wejścia na oscyloskopie i stwierdzam że styki w tym joysticku drżą jak złe 😁). Regulację głośności obsługuję przez timer 1 w trybie enkodera (przydał się kurs zaawansowanych timerów na STM32 z waszego bloga 😁). Przy zmianie wartości licznika timera wartość jest porównywana z zapisaną w poprzednim przejściu głównej pętli while(1). Jeżeli się zmieniła na mniejszą lub większą wysyłany jest raport HID z ustawionym bitem odpowiadającym klawiszowi VOLUP/VOLDOWN a zmienna lastEncoderCount jest in/dekrementowana. Dopóki obie wartości nie są równe raporty są wysyłane co przejście głównej pętli while. Wartość licznika jest dzielona przez 2 gdyż przy poprawnej pracy enkodera o tyle zmienia się po przeskoczeniu "o jeden ząbek". Czasem miałem sytuację że wartość licznika była nieparzysta (może błąd połączeń/drżenie styków) i algorytm w kółko podnosił/obniżał głośność o 1 bo wartości encoderCount i lastEncoderCount nigdy nie były równe. Dzielenie przez 2 gwarantuje parzystość wartości zmiennej ///TE ZMIENNE SA GLOBALNE/// uint16_t encoderCount=32766; //half of timers resolution (16bit) uint16_t lastEncoderCount=16383; //////////////////////////// //TEN KOD WYKONUJE SIE W PETLI WHILE FUNKCJI MAIN()// encoderCount=__HAL_TIM_GET_COUNTER(&htim1)/2; //get encoder absolute position if(encoderCount!=lastEncoderCount){ if(encoderCount<lastEncoderCount){SetKeyPress(MEDIA_VOLDOWN);lastEncoderCount-=1;} //set key press depending on encoder movement direction else{SetKeyPress(MEDIA_VOLUP);lastEncoderCount+=1;} USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); HID_report[1]=0; USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); } Kompletne oprogramowanie STMa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot. Po zweryfikowaniu działania prototypu zaprojektowałem i wytrawiłem prostą płytkę w KiCADzie żeby się pozbyć luźnych kabelków. Urządzenie zasilane jest z USB na BluePillu, programuje je z wyprowadzeń SWD po drugiej stronie płytki za pomocą ST-Linka V2. Żeby urządzenie jakoś wyglądało zaprojektowałem i wydrukowałem obudowę oraz gałkę do joysticka. Od razu ostrzegam że na drukarce FDM ciężko jest osiągnąć taką precyzję żeby gniazdo w gałce ciasno siedziało na wałku joysticka - ja zaprojektowałem 0,1mm ciaśniej i przy montażu rozgrzałem plastik tak by się uplastycznił i dopasował do kształtu na końcu drążka joysticka. Nie jest to ciasne pasowanie ale wystarcza żeby sterować bez urywania gałki co drugie dotknięcie 😁. I wydrukowane: Wszystkie pliki z kodem, płytka i obudowa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot. Z racji że chciałbym dalej to rozwijać to zakupiłem moduł NRF51822 i będę próbował zrobić coś podobnego, ale na Bluetooth HID, i z zastosowaniem w aucie do sterowania tanim tabletem z emulatorem headunitu AndroidAuto (używam apki HeadUnit Reloaded która wspiera obsługę z klawiatury do sterowania API Androida Auto np. sterowanie jasny/ciemny tryb, multimedia, poruszanie się po interfejsie za pomocą enkodera - AA jest tak zaprojektowany bo piloty do systemów infotainment z reguły mają też enkodery). Jedyna moja obawa jest taka że pilocik będzie musiał działać cały czas ze stałej instalacji 12V, bo tablet z niewiadomych powodów po rozłączeniu z sparowanym urządzeniem BT wymaga ręcznego ponownego połączenia, więc po wyłączeniu i włączeniu pilocika czeka mnie wycieczka do ustawień tabletu by go z powrotem połączyć. Nie mam doświadczenia z programowaniem nRF więc zobaczymy jak mi pójdzie na raz z BT HID, przerwaniami, enkoderem i jeszcze minimalizacją poboru energii😁 Łatwiej by było dorobić drugie USB w tablecie i podłączyć taki pilot jak opisałem powyżej. Tu jest problem tej natury, że tablet który mam już zmodyfikowany i założony na bardzo mocną taśmę dwustronną (😁) nie chce działać na OTG z więcej niż jednym urządzeniem. Podłączałem do niego kilka HUBów USB, kupiłem nawet specjalną przejściówkę do OTG z paroma portami USB ale nic nie chce ruszyć. Póki co moduł z NRF81 dopiero przyszedł, będę teraz się oswajał z SDK do niego, może jakiś hello world 😛. Nie jestem jeszcze pewny czy będę w stanie go programować i debugować bo mam tylko ST-Linka na stanie w tej chwili 😞 Podobno korzystając z OpenOCD można ST-Linka z tym połączyć ale to musiałbym przy wolnej chwili zrobić próby. Jak nie ruszy to będę szukać jakiegoś JTAGa ale ceny mnie trochę odstraszają. Wszelkie sugestie, pochwały, krytyka i komentarze mile widziane 🙂
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.