Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2014:teeter-game

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Následující verze
Předchozí verze
2014:teeter-game [2015/01/19 00:08]
Roman Deneš vytvořeno
2014:teeter-game [2015/01/19 02:17] (aktuální)
Roman Deneš
Řádek 1: Řádek 1:
 +===== Hra Teeter =====
 +
 ==== Zadání: ==== ==== Zadání: ====
  
 Na vývojovém kitu [[http://​www.st.com/​web/​catalog/​tools/​FM116/​SC959/​SS1532/​PF259090|32F429IDISCOVERY]] realizujte androidovou hru teeter. Na základě údajů z gyroskopu se na displeji bude pohybovat kulička. Cílem hry je dopravit kuličku na požadované místo. Při pohybu je nutné se vyhnout případným překážkám (stěny, díry). Na vývojovém kitu [[http://​www.st.com/​web/​catalog/​tools/​FM116/​SC959/​SS1532/​PF259090|32F429IDISCOVERY]] realizujte androidovou hru teeter. Na základě údajů z gyroskopu se na displeji bude pohybovat kulička. Cílem hry je dopravit kuličku na požadované místo. Při pohybu je nutné se vyhnout případným překážkám (stěny, díry).
 +
 +
 +  ​
 +==== Použitá zařízení ====
 +Projekt je realizován na vývojovém kitu [[http://​www.st.com/​web/​catalog/​tools/​FM116/​SC959/​SS1532/​PF259090|32F429IDISCOVERY]],​ který obsahuje 2.4 palcový displej ​ QVGA TFT s rozlišením 240x320. Dále byl použit akcelerometr [[http://​www.dipmicro.com/​store/​GY521-MOD|GY-521]].
 +
 +{{ :​2014:​teeter-game:​imag_teeter.jpg?​300 |Použitá zařízení}}
 +
 +  ​
 +Zapojení PINů:
 +
 +^ GY-521 ​ ^ 32F429IDISCOVERY ^ Popis                ^
 +| SCL     | PA8              | Hodinový signál ​     |
 +| SDA     | PC9              | Data                 |
 +| AD0     | GND              | Adresa zařízení ​     |
 +| VCC     | 3V               | Napájecí napětí 3.3V |
 +| GND     | GND              | Uzemnění ​            |
 +
 +==== Software: ====
 +Pro vývoj aplikace bylo využito volně dostupné vývojové prostředí [[http://​www.coocox.org/​|CooCox CoIDE]], které využívá ​ [[https://​launchpad.net/​gcc-arm-embedded|GCC kompiler]] určený pro ARM procesory. Dále bylo využito několika knihoven z webu http://​stm32f4-discovery.com/​.
 +
 +Seznam použitých knihoven:
 +
 +^ Název knihovny ​            ​^ ​ Popis                                 ^
 +| stm32f4xx ​                 | Obecná knihovna pro daný vývojový kit  |
 +| tm_stm32f4_delay ​          | Přesné zpoždění ​                       |
 +| tm_stm32f4_ili9341_ltdc ​   | Ovladač k displeji ​                    |
 +| tm_stm32f4_mpu6050 ​        | Ovladač k akcelerometru ​               |
 +| tm_stm32f4_i2c ​            | knihovna pro použití I2C               |
 +| tm_stm32f4_sdram ​          | knihovna pro přístup do paměti ​        |
 +
 +==== Realizace: ====
 +
 +Celý layout hry je uložen v SDRAM pamětí a při interakci vykreslován na displej zařízení. Nejprve bylo nutné definovat makro pro přístup do paměti na základě souradnic x, y. Pamět není mapována hned od prvního dostupného místa, jelikož některé z dalších knihoven taktéž využívaly tento prostor a docházelo ke konfliktům. Z toho důvodu je matice v paměti posunuta o přibližně 7 MB.
 +
 +<code cpp>
 +#define X_SIZE 240
 +#define Y_SIZE 320
 +#define OFFSET 7000000
 +
 +#define MATRIX_SET_VALUE(x,​ y, val)  TM_SDRAM_Write8(OFFSET + x * Y_SIZE + y, val)
 +#define MATRIX_GET_VALUE(x,​ y)       ​TM_SDRAM_Read8(OFFSET + x * Y_SIZE + y)
 +</​code>​
 +
 +Na jednotlivé pozice se pomocí funkce DrawLayout "​vykreslil"​ požadovaný layout v závislosti na aktuální úrovni. ​ Pod číslem 11 jsou uloženy stěny. Pod číslem 12 pak rozšířený prostor do kterého kulička nemůže vstoupit. Tento prostor odpovídá poloměru kuličky. Pod čísly 5 a 6 jsou jednotlivé díry. K nim odpovídají středy jsou uloženy pod čísly 4 a 7. Pro vykreslování děr (kruhů) je použita modifikovaná funkce z knihovny [[http://​stm32f4-discovery.com/​2014/​06/​library-18-ili9341-ltdc-stm32f429-discovery/​|tm_stm32f4_ili9341_ltdc]]. Místo vykreslování jednotlivých pixelů funkce provádí zápis do paměti.
 +
 +Na konci funkce je pak dvojitá smyčka, která na základě číselných údajů z matice vykresluje na displej jednotlivé barevné pixely.
 +
 +<​code>​
 +    for(i = 0; i < 240; i++){
 +     ​  ​ for(j = 0; j < 320; j++){
 +        if((MATRIX_GET_VALUE(i,​ j)) < 6)
 +        TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_GREEN);​
 +        if((MATRIX_GET_VALUE(i,​ j)) == 6)
 +        TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_YELLOW);​
 +        if((MATRIX_GET_VALUE(i,​ j)) == 11)
 +         ​  ​ TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_YELLOW);​
 +     ​  ​ }
 +    }
 +</​code>​
 +
 +V následující supersmyčce jsou opakovaně čteny data z připojeného akcelerometru,​ která jsou dále zpracována. Nejprve jsou váhována (60 % předchozí hodnoty + 40% z nově načtené hodnoty) a dále je od těchto hodnot vždy odečtena referenční hodnota, která se načte při zapnutí přistroje. Toto opatření je zejména kvůli nedokonalému připevnění sensoru, který nemusí být v naprosto stejné poloze jako deska.
 +
 +<code cpp>
 +        if (sensor1)
 +        TM_MPU6050_ReadAll(&​MPU6050_Data0);​
 +
 +    // Nacteni vychozi pozice
 +    if(start == 1){
 +    X_axis_ref = MPU6050_Data0.Accelerometer_X;​
 +                Y_axis_ref = MPU6050_Data0.Accelerometer_Y;​
 +                start = 0;
 +    }
 +
 +    // Setrvacnost
 +        X_axis = (Q*X_axis + (10-Q)*(MPU6050_Data0.Accelerometer_X - X_axis_ref))/​10;​
 +        Y_axis = (Q*Y_axis + (10-Q)*(MPU6050_Data0.Accelerometer_Y - Y_axis_ref))/​10;​
 +
 +</​code>​
 +           
 +Dále se uloží současná poloha a provede se změna na základě údajů z akcelerometru. Zde ukázka pouze pro jeden směr. Poslední podmínka ošetřuje okraj displeje. ​
 +
 +<​code>​
 +       ​ if(X_axis < -th1){
 +      Xpos++;
 +       ​if(X_axis < -th2)
 + ​ Xpos++;​
 +       ​if(X_axis < -th3)
 +            Xpos++;
 +        if(Xpos > 228)
 +        Xpos = 228;
 +      }
 +                   
 +           // dalsi tri smery ...
 +            ​
 +</​code> ​     ​
 +
 +Za předpokladu,​ že nově získaná poloha není dostupná (zeď), provede se načtení staré polohy. Tato akce probíhá pro oba směry (x, y) jednotlivě.
 +
 +Nově získaná poloha se vykresluje pomocí funkce DrawBall. Nejprve se smaže stará kulička a následně se vykreslí na nových souřadnicích. ​
 +
 +<​code>​
 +void DrawBall(uint16_t Xpos, uint16_t Ypos, uint16_t Xpos_old, uint16_t Ypos_old)
 +{
 +
 +
 + TM_ILI9341_DrawFilledCircle(Xpos_old,​ Ypos_old, 10, ILI9341_COLOR_BLACK);​
 + TM_ILI9341_DrawFilledCircle(Xpos_old,​ Ypos_old, 10, ILI9341_COLOR_BLACK);​
 +
 + TM_ILI9341_DrawFilledCircle(Xpos,​ Ypos, 10, ILI9341_COLOR_BLUE);​
 + TM_ILI9341_DrawFilledCircle(Xpos,​ Ypos, 10, ILI9341_COLOR_BLUE);​
 +
 + Delayms(15);​
 +}
 +</​code> ​       ​
 +
 +Před každým vykreslením kuličky je ještě volána funkce ReDrawLayout,​ která překresluje (obnovuje) layout v okolí kuličky. Jde především o vykreslení děr, které mohou být částečně smazány procházející kuličkou.
 +
 +<​code> ​
 +void ReDrawLayout(uint16_t Xpos, uint16_t Ypos){
 +
 +    ​static uint16_t i, j;
 +
 +       for(i = (Xpos-20); i < (Xpos+20); i++){
 +          for(j = (Ypos-20); j < (Ypos+20); j++){
 +           ​ if((MATRIX_GET_VALUE(i,​ j)) < 6)
 +           ​ TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_GREEN);​
 +
 +           ​ if((MATRIX_GET_VALUE(i,​ j)) == 6)
 +           ​  ​  ​TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_YELLOW);​
 +
 +          if((MATRIX_GET_VALUE(i,​ j)) == 11)
 +              TM_ILI9341_DrawPixel(i,​ j, ILI9341_COLOR_YELLOW);​
 +          }
 +       }
 +}
 +</​code> ​
 +
 +V případě, že kulička spadne do díry (načtená souřadnice má hodnotu 5 nebo 6) je volána funkce DrawDrop, která provede animaci kuličky do díry a vykreslení (mezi)výsledků.
 +
 +<​code> ​
 +void DrawDrop(uint16_t Xpos, uint16_t Ypos, uint16_t Xpos_old, uint16_t Ypos_old, uint8_t level)
 +{
 +
 +
 + TM_ILI9341_DrawFilledCircle(Xpos_old,​ Ypos_old, 10, ILI9341_COLOR_BLACK);​
 +
 + TM_ILI9341_DrawFilledCircle(Xpos,​ Ypos, 10, ILI9341_COLOR_BLUE);​
 +
 +
 + uint16_t i, j;
 + uint16_t Xmid, Ymid;
 + int16_t deltaX, deltaY;
 +
 +    for(i = (Xpos-22); i < (Xpos+22); i++){
 +     ​  ​ for(j = (Ypos-22); j < (Ypos+22); j++){
 +     ​  ​ if((MATRIX_GET_VALUE(i,​ j) == 4 )|(MATRIX_GET_VALUE(i,​ j) == 7 )){
 +     ​  ​ Xmid = i;
 +     ​  ​ Ymid = j;
 +     ​  ​ }
 +       ​  ​ }
 +    }
 +
 +    deltaX = (Xmid-Xpos);​
 +    deltaY = (Ymid-Ypos);​
 +
 +
 +    TM_ILI9341_DrawFilledCircle(Xpos,​ Ypos, 10, ILI9341_COLOR_BLUE);​
 +    Delayms(50);​
 +    TM_ILI9341_DrawFilledCircle(Xpos,​ Ypos, 10, ILI9341_COLOR_BLACK);​
 +
 +    TM_ILI9341_DrawFilledCircle(Xpos+deltaX/​4,​ Ypos+deltaY/​4,​ 10, ILI9341_COLOR_BLUE);​
 +    Delayms(50);​
 +    TM_ILI9341_DrawFilledCircle(Xpos+deltaX/​4,​ Ypos+deltaY/​4,​ 10, ILI9341_COLOR_BLACK);​
 +
 +    TM_ILI9341_DrawFilledCircle(Xpos+2*deltaX/​4,​ Ypos+2*deltaY/​4,​ 10, ILI9341_COLOR_BLUE);​
 +    Delayms(50);​
 +    TM_ILI9341_DrawFilledCircle(Xpos+2*deltaX/​4,​ Ypos+2*deltaY/​4,​ 10, ILI9341_COLOR_BLACK);​
 +
 +    TM_ILI9341_DrawFilledCircle(Xpos+3*deltaX/​4,​ Ypos+3*deltaY/​4,​ 10, ILI9341_COLOR_BLUE);​
 +    Delayms(50);​
 +    TM_ILI9341_DrawFilledCircle(Xpos+3*deltaX/​4,​ Ypos+3*deltaY/​4,​ 10, ILI9341_COLOR_BLACK);​
 +
 +    TM_ILI9341_DrawFilledCircle(Xmid,​ Ymid, 10, ILI9341_COLOR_BLUE);​
 +    Delayms(50);​
 +
 +
 +    //
 + if((MATRIX_GET_VALUE(Xpos,​ Ypos)) == 5){
 +
 +    TM_ILI9341_DrawFilledCircle(Xmid,​ Ymid, 12, ILI9341_COLOR_BLUE2);​
 +    TM_ILI9341_DrawFilledCircle(Xmid,​ Ymid, 10, ILI9341_COLOR_BLUE);​
 +
 +
 + Delayms(1250);​
 +
 +
 +    TM_ILI9341_Fill(ILI9341_COLOR_RED);​
 +    Delayms(250);​
 +    TM_ILI9341_Fill(ILI9341_COLOR_BLACK);​
 +    Delayms(250);​
 +    TM_ILI9341_Fill(ILI9341_COLOR_RED);​
 +    Delayms(250);​
 +    TM_ILI9341_Fill(ILI9341_COLOR_BLACK);​
 +    Delayms(250);​
 +    TM_ILI9341_Fill(ILI9341_COLOR_RED);​
 +     ​ Delayms(250);​
 +        TM_ILI9341_Fill(ILI9341_COLOR_BLACK);​
 +        Delayms(250);​
 +        TM_ILI9341_Fill(ILI9341_COLOR_RED);​
 +
 + TM_ILI9341_Puts(50,​ 100, "Game Over", &​TM_Font_16x26,​ 0x0000, ILI9341_COLOR_RED);​
 +
 + while(1){}
 +
 + }
 +             // Obdobne i pro MATRIX_GET_VALUE(Xpos,​ Ypos)) == 6 -> dalsi kolo.
 +
 +}
 +
 +
 +</​code> ​
 +
 +==== Závěr ====
 +
 +V projektu byl místo interního gyroskopu využit externí akcelerometr,​ jelikož se na danou aplikace hodí lépe. Zadání bylo splněno, hra je plně funkční. Při popisu byly vynechány některé zřejmé části kódu, které jsou jasné už z jejich popisu. Dále pak některé definice proměnných a další méně podstatné funkce.
 +
 +Hra obsahuje dvě úrovně a je nastíněn systém pro přechod mezi jednotlivými úrovněmi. Případné rozšíření o další úrovně je tedy poměrně snadná záležitost. ​
 +
 +Video je k dispozici na adrese https://​www.youtube.com/​watch?​v=NFYOeizr5jU&​feature=youtu.be. Výsledný soubor je uložen v souborovém systému.
 +
2014/teeter-game.1421622497.txt.gz · Poslední úprava: 2015/01/19 00:08 autor: Roman Deneš