Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2017:pc-app-ctrl

Ovládací panel pro PC aplikace

Vypracoval: Dan Raszka


Zadání

Navrhněte zařízení sloužící ke zjednodušenému ovládání pro různé programy v PC. Zařízení realizujte pomocí vlastního návrhu DPS s procesorem řady STM32F1. Jako ovládací prvky zvolte tlačítka a rotační enkodér. K zobrazení stavu zařízení využijte RGB LED. Napájení uvažujte přes USB rozhraní.

Úvod

Základní myšlenkou tohoto projektu bylo vytvoření ovládacího zařízení, které by zjednodušilo používání PC s vícero zvukovými kartami. Vyhneme se tak otravnému přepojování kabeláže v případě, že si chceme něco poslechout na sluchátka. V případě, že k integrované zvukové kartě jsou připojeny reproduktory, k externí zvukové kartě jsou připojeny sluchátka a navíc využíváme například domácího kina s prostorovým zvukem přes HDMI konektor, je otavné i přepínání v systému Windows. U Windows 10 už je zakomponováno zjednodušení, díky kterému lze přepínat výstup bez nutnosti otevírání systémového nastavení. I tak je proces zdlouhavý, zejména když by šel nahradit pouhým stiskem tlačítka. Naštěstí existují programy umožňující nastavení klávesové zkratky pro cyklování mezi vybranými zvukovými výstupy. V tomto projektu bude využit konkrétně program AudioSwitch. V něm pouze nastavíme požadovanou klávesovou zkratku pro cyklování mezi výstupy.

Hardware

Protože předpokladem bylo vytvořit ovládací prvek, který bude nejenom praktický, ale bude taktéž dobře vypadat, byla zvolena cesta vytvoření hardwaru přímo na míru aplikaci. Jako řídící procesor byl vybrán STM32F103 zejména z důvodu dobré dostupnosti, nízké ceny a také malého ale lehce osaditelného pouzdra. Jako ovládací prvky byly zvoleny 4 tlačítka a rotační enkodér. Pro signalizaci byly zvoleny RGB LED diody podsvětlující knoflík rotačního enkodéru. Ty jsou řízeny pomocí trojice NMOS tranzistorů spínaných pomocí PWM z procesoru.

Dále byl implementován taktéž kapacitní dotykový senzor připojený na tělo rotačního enkodéru. Díky tomu lze signalizovat dotyk zařízení. Pro snížení napájecího napětí z 5V z USB sběrnice na 3,3V pro procesor byl zvolen miniaturní DC/DC měnič.

Protože předem nebylo jasné jakou bude mít zařízení finální podobu, byla nejprve vytvořena DPS obsahující napájecí obvody, USB konektor, procesor STM32F103 a konektory umožňující připojení desky s ovládacími a zobrazovacími prvky. Na ní byly otestovány funkčnosti jednotlivých bloků a psán obslužný program.

V mezičase se začalo pracovat na mechanickém provedení, kdy vzhledem k použití optického rotačního enkodéru byla zvolena koncepce typu stojánek. Zvoleno bylo provedení z fošny švestkového dřeva s hliníkovými krytkami tlačítek a knoflíkem enkodéru. Ty ale vzhledem k vytíženosti CNC frézky zatím vytvořeny nebyly a proto byly vytvořeny knoflíky tlačítek z březového dřeva pro otestování funkčnosti a vytvoření demonstračního videa. Tlačítka, LED diody, kapacitní senzor i rotační onkodér jsou osazeny na druhé DPS, která zároveň plní funkci montážního subpanelu a je zapuštěna ve vyfrézované kapse fošny. Jeden z montážních otvorů rotačního enkodéru navíc slouží jako elektroda kapacitního senzoru.

Software

USB

Při tvorbě obslužného programu jsem vycházel Z PC cvičení. Díky HAL knihovnám nebylo těžké upravit vygenerovaný kód z CubeMX. Problém ovšem nastal u multimediální kláves typu Play/Pause atd. Ukázalo se, že i přesto, že byly definovány v deskriptoru klávesnice, tak nedocházelo k odezvě na straně PC. Proto byl upraven deskriptor tak, aby se zařízení hlásilo jako složené zařízení sestávající se z klávesnice, myši a takzvaného uživatelského zařízení. Díky tomu je možné zadefinovat různé multimediální klávesy. Deskriptor byl vygenerován pomocí programu HID Descriptor Tool.

0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01,  // COLLECTION (Application)
0x85, 0x01,  // REPORT ID (1)
0x05, 0x07,  // USAGE_PAGE (Keyboard)
0x19, 0xe0,  // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7,  // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00,  // LOGICAL_MINIMUM (0)
0x25, 0x01,  // LOGICAL_MAXIMUM (1)
0x75, 0x01,  // REPORT_SIZE (1)
0x95, 0x08,  // REPORT_COUNT (8)
0x81, 0x02,  // INPUT (Data, Var, Abs)
0x75, 0x08,  // REPORT_SIZE (8)
0x95, 0x01,  // REPORT_COUNT (1)
0x81, 0x03,  // INPUT (Cnst, Var, Abs)
0x75, 0x08,  // REPORT_SIZE (8)
0x95, 0x06,  // REPORT_COUNT (6)
0x15, 0x00,  // LOGICAL_MINIMUM (0)
0x25, 0x65,  // LOGICAL_MAXIMUM (101)
0x05, 0x07,  // USAGE_PAGE (Keyboard)
0x19, 0x00,  // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65,  // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00,  // INPUT (Data, Ary, Abs)
0xc0,       // END_COLLECTION

0x05, 0x01,  // USAGE_PAIGE (Generic Desktop)
0x09, 0x02,  // USAGE (Mouse)
0xa1, 0x01,  // COLLECTION (Application)
0x09, 0x01,  // USAGE (Pointer)
0xa1, 0x00,  // COLLECTION (Physical)
0x85, 0x02,  // REPORT_ID (2)
0x05, 0x09,  // USAGE_PAGE (Button)
0x19, 0x01,  // USAGE_MINIMUM (Button 1)
0x29, 0x03,  // USAGE_MAXIMUM (Button 3)
0x15, 0x00,  // LOGICAL_MINIMUM (0)
0x25, 0x01,  // LOGICAL_MAXIMUM (1)
0x95, 0x03,  // REPORT_SIZE (1)
0x75, 0x01,  // REPORT_COUNT (3)
0x81, 0x02,  // INPUT (Data,Var,Abs)
0x95, 0x01,  // REPORT_COUNT (1)
0x75, 0x05,  // REPORT_SIZE (5)
0x81, 0x03,  // INPUT (Cnst, Var, Abs)
0x05, 0x01,  // USAGE_PAGE (Generic Desktop)
0x09, 0x30,  // USAGE (X)
0x09, 0x31,  // USAGE (Y)
0x09, 0x38,  // USAGE (Wheel)
0x15, 0x81,  // LOGICAL_MINIMUM (-127)
0x25, 0x7f,  // LOGICAL_MAXIMUM (127)
0x95, 0x03,  // REPORT_SIZE (8)
0x75, 0x08,  // REPORT_COUNT (3)
0x81, 0x06,  // INPUT (Data,Var, Rel)
0xc0,       // END_COLLECTION
0xc0,       // END_COLLECTION

0x05, 0x0c,  // USAGE_PAGGE (Consumer Devices)
0x09, 0x01,  // USAGE (Consumer Control)
0xa1, 0x01,  // COLLECTION (Application)
0x85, 0x03,  // REPORT_ID (3)
0x05, 0x0c,  // USAGE_PAGE (Consumer Devices)
0x15, 0x00,  // LOGICAL_MINIMUM (0)
0x25, 0x01,  // LOGICAL_MAXIMUM (1)
0x75, 0x01,  // REPORT_SIZE (1)
0x95, 0x07,  // REPORT_COUNT (7)
0x09, 0xB5,  // USAGE (Scan Next Track)
0x09, 0xB6,  // USAGE (Scan Previoun Track)
0x09, 0xB7,  // USAGE (Stop)
0x09, 0xCD,  // USAGE (Pause)
0x09, 0xe2,  // USAGE (Mute)
0x09, 0xe9,  // USAGE (Volume Up)
0x09, 0xea,  // USAGE (Volume Down)
0x81, 0x02,  // INPUT (Data, Var, Abs)
0x95, 0x01,  // REPORT_COUNT (1)
0x81, 0x01,  // INPUT (Cnst, Ary, Abs)
0xc0         // END_COLLECTION

Když už se zařízení hlásilo korektně v systémů, zbývalo pouze naprogramovat obslužné rutiny pro periferie procesoru obsluhující ovládací a signalizační prvky.

Rotační enkodér

Protože časovače procesoru podporují připojení rotačních enkodérů, je jejich použití značně zjednodušeno, protože se periferie sama stará o debouncing. Lze nastavit parametry jako filtraci vstupních pulzů, děličky pulzů a taky citlivost na náběžnou/sestupnou hranu. Důležité je nastavit časovač tak, aby reagoval na oba směry otáčení (byl v módu TI12). Použit byl časovač TIM4. Vzhledem k použitému optickému enkodéru s 400 pulzy na otáčku, byla zvolena vysoká předdělička z důvodu nevyužití tohoto rozlišení.

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 10000;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity = TIM_ICPOLARITY_FALLING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV2;
  sConfig.IC1Filter = 15;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV2;
  sConfig.IC2Filter = 15;
 

RGB LED

Pro napájení RGB LED diod bylo využito napětí 5V s předřadnými rezistory. LED diody jsou zapojeny paralelně a jsou rozděleny do tří samostatných okruhů podle barvy. Pro řízení jsou využity 3 miniaturní MOSFET tranzistory s N kanálem. Ty jsou řízeny PWM výstupy procesoru. Konkrétně byl využit časovač TIM3 obsahující 4 nezávislé výstupní kanály. Využity byly samozřejmě pouze 3 pro RGB kanály. Předdělička časovače byla nastavena tak aby byla frekvence čítače 1 MHz. S periodou čítání nastavenou na 1000 dostaneme výslednou periodu PWM 1 kHz.

Zařízení signalizuje navolený ovládací mód podle barvy. Byl zvolený efekt pomalého pulzování. Navíc při dotyku rotačního enkodéru (snímaném kapacitním snímačem) dojde k zvýšení intenzity a zrychlení efektu. Tohoto efektu bylo docíleno vyčítáním z předpřipravené tabulky. Protože intenzita svitu LED není lineární s dobou pulzu PWM a navíc nebylo chtěné aby docházelo k úplnému zhasnutí LED byla tabulka vygenerována pomocí polynomu vyššího řádu s přidaným offsetem. Zjištění optimálního nastavení bylo spíše experimentální metodou. Cílem bylo aby zařízení neoslňovalo i v temné místnosti - proto nebyl využit ani celý rozsah PWM.

Tlačítka a kapacitní snímač

Tlačítka jsou připojena pomocí pull-up rezistorů k napájecímu napětí 3,3 V. Při sepnutí je tedy generována sestupná hrana, na kterou reaguje přerušení procesoru. Ošetření zákmitů je řešeno tak, že při vyvolání přerušení je do proměnné odpovídající danému tlačítku zapsána zpožďovací konstanta, která je v hlavním cyklu postupně dekrementována. Při dosažení nulové hodnoty je znova načtená hodnota na daném pinu a pokud je rovna nule (stále zmáčknuté tlačítko) je provedena obsluha stisknutého tlačítka.

Kapacitní snímač je řešen pomocí integrovaného obvodu AT42QT1011. Při dotyku je vyvoláno přerušení, které nastaví vlajku. Toho je využito v obsluze LED diod, kde dojde ke zvýšení intenzity svitu a zrychlení pulzování. Zde bylo zapotřebí pouze experimentálně zjistit hodnotu kondenzátoru, kterým byla ovlivněna citlivost tak, aby k detekci docházelo pouze při dotyku enkodéru. Funkčnost tohoto řešení lze vidět na konci demonstračního videa níže.

Hlavní obslužný program

V hlavní smyčce jsou 3 neblokující funkce:

while (1) {
  EncoderTask();
  LEDTask();
  ButtonTask();
}

Funkce EncoderTask se stará o vyhodnocení otáčení rotačního enkodéru. To je řešeno pouhým načtením čítacího registru časovače TIM4. Vyhodnocení je řešeno porovnáním s minulou hodnotou s nastaveným prahem citlivosti. Aby vyhodnocování nedocházelo příliš často, je použito následující konstrukce zaručující neblokující čekání:

  static uint32_t delay = 18000;  // Zpozdeni mezi vyhodnocenim
  uint16_t i;                     // Aktualni hodnota citaciho registru
  static uint16_t li;             // Minula hodnota citaciho registru
 
  delay--;
  if(delay == 0) {
    delay = 18000;
    i = TIM4->CNT ;
 
    if(li - i >= THRESHOLD) {     
      switch(MODE) {              // Vyhodnoceni provedeni funkce na zaklade modu zarizeni
      case MEDIA:
      case SPOTIFY:
        media(VOL_UP);
        break;
      case USER:
        wheel(1);
        break;
      }
 
      li = i;
      ...
  }

Stejná konstrukce je použita také ve funkci LEDTask starající se o obsluhu LED diod a tedy plnění časovače. Funkce ButtonTask zajišťuje ošetření zákmitů při stisku tlačítka a provedení dané funkce při korektním stisku.

Jak lze vidět z předcházejícího kódu, Zařízení pracuje ve 3 módech, které lze přepínat prvním tlačítkem, a které jsou signalizovány barvou podsvícení. Jedná se o módy Media, Spotify a User. V tabulce níže lze vidět funkce jednotlivých tlačítek:

Mód Barva podsvětlení Rotační enkodér Tlačítko 1 Tlačítko 2 Tlačítko 3 Tlačítko 4
Media Modrá Systémová hlasitost Přepínání módů Mute Změna zvukové karty Spuštění Spotify a přepnutí do tohoto módu
Spotify Zelenomodrá Play/Pause Další skladba
User Fialová Kolečko myši Spuštění Google Chrome Spuštění kalkulačky

Pomocné funkce

Jedná se především o podpůrné funkce zajišťující provedení zadané akce. Jde o odeslání specifického reportu pro jednotlivé akce po USB.

void wheel(int8_t change);  // Otočení kolečkem myši
void media(uint8_t change); // Zmáčknutí multimediální klávesy
void changeDevice(void);    // Změna zvukového výstupu - klávesová zkratka
void runSpotify(void);      // Spuštění Spotify
void runChrome(void);       // Spuštění Google Chrome
void runCalc(void);         // Spuštění kalkulačky

Demonstrační video

Zdrojová data: xraszk04_mpoa_projekt.zip

Závěr

Zařízení je jak po hardwarové tak i po softwarové stránce funkční. Zbývají pouze kosmetické dokončovací práce typu finální broušení a namoření dřeva a instalace vyfrézovaných hmatníků. Úpravou jistě projde stojánek protože díky vyšší hmotnosti hmatníků tlačítek a celkově vyššímu těžišti zařízení nebylo dosaženo dostatečné stability. Překvapením byl kapacitní dotykový senzor, který přes mou počáteční nedůvěru funguje skvěle a díky tomu jsou v budoucnu možné úpravy kódu typ poklepání na enkodér jako stisk tlačítka myši apod. Dobrou volbou byl taky použitý optický rotační enkodér (přestože jde o čínský výrobek), díky jehož mechanické konstrukci bylo možné se vyvarovat složitých mechanických úprav. Zařízení je nyní ve fázi dlouhodobého testování, kdy bude třeba vypozorovat způsob využití a nejčastější úkony a případně optimalizovat program pro lepší uživatelský komfort.

Zdroje

USB HID Development on STM32 - http://andybrown.me.uk/2016/01/09/f042usbhid/

HID Consumer Device for volume control - http://www.microchip.com/forums/m618147.aspx

HID Descriptor Tool - http://www.usb.org/developers/hidpage/

AudioSwitch - https://github.com/sirWest/AudioSwitch

2017/pc-app-ctrl.txt · Poslední úprava: 2018/01/14 19:51 autor: Dan Raszka