Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2014:led-snake

LED snake 8x8 na FRDM-KL25Z

Zadání

  • Displej použitý v rámci staršího projektu pro hru LED SNAKE připojte k vývojové desce FRDM-KL25Z a aplikaci portujte na tuto desku.
  • Využijte prostředí KDS nebo mbed.

Provedení

Hra snake má několik možných variant. Vzhledem k velikosti a rozlišení displeje jsou vhodné následující parametry:

  • Had začíná na velikosti 3.
  • Had se může pohybovat všemi směry a může procházet přes okraj displeje.
  • Pokud had sežere jablko prodlouží se o jednu kuličku a nedojde k jeho zrychlení.
  • Had je ovládán čtveřicí tlačítek a kdykoli v průběhu hry je možné měnit jeho rychlost pomocí kapacitního slideru.
  • Pokud se had kousne do svého těla dojde k ukončení hry a zobrazeni dosažené délky hada.

Možnosti pohybu hada a jeho chování jsou zobrazeny na animaci níže. Také je zobrazeno číslování jednotlivých diod jak bylo použito pro mapování displeje v programu.

Prehled dvou mapovani disp.

Hardware

Pro aplikaci hada je využita vývojová deska FRDM-KL25Z. Na této desce jsou využity následující periferie.

  • Piny PTC<0-7> pro řízení sloupců displeje zelené barvy.
  • Piny PTC<8,9,10,11,12,13,16,17> jsou využity pro řízení sloupců červené barvy.
  • Piny PTB<0-2> jsou využity pro řízení řádků matice pro obě barvy.
  • Piny PTD6, PTD7, PTE0 a PTE1 jsou využívány jako vstupní piny pro tlačítka.
  • Pin PTB3 je nastaven na analogový vstup sloužící pro generování náhodných čísel.
  • Poslední využitou periferií je kapacitní slider, který slouží pro nastavení rychlosti hada. Tu lze proti základní rychlosti zpomalit, ale i zrychlit.

Blokové schéma

Vývojová deska je s displejem propojena pomocí redukčního přípravku, který má možnost připojení dvou tlačítek a rozhraní UART. Jelikož je had ovládán pomocí 4 tlačítek byla tlačítka vyvedena mimo na nepájivé kontaktní pole. Uspořádání tlačítek bylo zvoleno jako uspořádání kurzorových šipek na PC klávesnici.
Redukce KL25Z na disp.Schéma zapojení tlačítek

Vzhledem k umístění kapacitního slideru na desce a jeho překrytí redukční deskou byly piny na tuto desku napájené v maximální délce. Ovládání rychlosti je tedy možné, ale špatně dosažitelné.

Software

K psaní kódu bylo použito webové prostředí www.mbed.org. Použití tohoto prostředí skýtá některé výhody, ale i nevýhody. Mezi výhody patří:

  • Množství example a knihoven
  • Dostupnost odkudkoli kde je internetové připojení
  • Rychlé zprovoznění, není nutné řešit potíže
  • Zvýrazňování syntaxe
  • Možnost provést automatické formátování kódu

Mnou pozorované nevýhody jsou následující:

  • Nutnost stahování bin souboru - zdržuje
  • Nemožnost sbalení funkcí nebo cyklů
  • Tabulátor odskakuje příliš daleko (4 mezery)
  • Občasná nedostupnost kompilátoru - vytížení (minimálně)

Vzhledem k popsaným nevýhodám byla konečná vizuální podoba kódu upravena v textovém editoru kate.

KOD

Program je tvořen několika funkcemi jejich zaměření lze rozdělit na funkce starající se o zobrazení, generování dat a řízení hada. Do programu byly importovány knihovny TSI (kapacitní slider) a knihovna mbed. Kompletní program, binárka a soubory pro kompilaci jsou v archivu snake.zip.

Řízení hada probíhá pomocí pole o rozměru 64 bodů. Pole s názvem h[64] o definovaném rozměru je naplněno číslem 65. Toto číslo nemůže nikdy nastat a složí jako informace o nepřítomnosti hada. Jednotlivé segmenty pole představují pořadové číslo článku hada a jejich hodnota udává pozici tohoto článku. Platí tedy že hlava bude vždy v h[0] a bude se lišit číselná hodnota. Pohyb hada je řešeny vytvořením nové hlavy na příslušné pozici podle zvoleného směru pohybu a vymazáním posledního článku ocasu hada.

void pohyb()     //pohyb hada v pracovnich souradnicich h[]
{
  unsigned char i;
  switch (posun){       //na zaklade velikosti posunu rozhodne o smeru, funkce v case jsou temer totozne
    case 0:
      if(h[0]==7 || h[0]==15 || h[0]==23 || h[0]==31 || h[0]==39 || h[0]==47 || h[0]==55 || h[0]==63){      //osetreni projeti hada okrajem
    for(i=0;i<size-1;i++){      //vytvoreni kopie hada
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){      // ulozeni kopie hada s posunutim
      h[i+1]=hh[i];
        }
        h[0]=h[0]-7;        //posunuti hlavy
    break;
 
      }else{                //stejne jako nahore jen bez prestupu krajem obrazovky
    for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
        }
        h[0]=h[0]+1;
        break;
        }
 
    case 1:
      if(h[0]==0 || h[0]==8 || h[0]==16 || h[0]==24 || h[0]==32 || h[0]==40 || h[0]==48 || h[0]==56){
        for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
          h[i+1]=hh[i];
        }
        h[0]=h[0]+7;
        break;
 
      }else{
    for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
    }
        h[0]=h[0]-1;
    break;
      }
    case 2:
      if(h[0]==0 || h[0]==1 || h[0]==2 || h[0]==3 || h[0]==4 || h[0]==5 || h[0]==6 || h[0]==7){
        for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
        }
        h[0]=h[0]+56;
        break;
      }else{
    for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
        }
        h[0]=h[0]-8;
        break;
        }
    case 3:
      if(h[0]==56 || h[0]==57 || h[0]==58|| h[0]==59 || h[0]==60 || h[0]==61 || h[0]==62 || h[0]==63){
        for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
        }
        h[0]=h[0]-56;
        break;
 
      }else{
        for(i=0;i<size-1;i++){
      hh[i]=h[i];
        }
        for(i=0;i<size-1;i++){
      h[i+1]=hh[i];
        }
        h[0]=h[0]+8;
        break;
    }
    }
  nuldisp();        //volani vynulovani displeje
}

Další zajímavou částí programu je generování pozice jablka. To probíhá pomocí srand a rand. Pro zajištění maximální náhodné hodnoty je vstupem funkce srand 1000 násobek hodnoty na pinu PTB3, který je nastaven jako analogový vstup a součet času od spuštění desky.

void genj()      // funkce generujici pozici jablka
{
  char i;       // pomocna
 
  ja = rand() % 64;     //pozice jablka od 0 do 63
  for(i = 0;i<=63;i++){     //kontrola zda neni jablko v hadovi
    if(h[i] == ja){
      ja = rand() % 64;
      i = 0;
    }
  }
  s++;      // pricteni jablka do skore - o jedno spozdeno
}

Poslední podrobně rozebranou částí kódu budou dvě funkce starající se o zobrazení hada na displeji. První z nich převede hodnoty z h[i] vyjádření do maticového zápisu had[8][8]. Druhá potom provede samotné zobrazení na displeji nastavením příslušných pinů.

void dejmat()       // prepocet pracovnich souradnic na souradnice na dipleji
{
  unsigned char i,t1,t2;
  for(i = 0; i <= 65; i++){
    if(h[i] != 65){
      t1 = h[i] % 8;        //sloupek
      t2 = h[i] / 8;        //radek
      had[t2][t1] = 0;      //vlozeni priznaku o pritomnosti do matice
    }
  }
  t1 = h[0] % 8;
  t2 = h[0] / 8;
  hlava[t2][t1] = 0;
  t1 = ja % 8;
  t2 = ja / 8;
  jablko[t2][t1] = 0;
}
 
void ukaz()     //funkce zobrazeni zobrazovacich souradnic na displej provede několik zobrazeni po sobe
{
  char i,j;
  for(i = 0; i < 8; i++){
    for(j=0;j<8;j++){       // pro zamezeni blikani
      if(i == 0){
    A=1;B=1;C=1;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
        z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
        wait(0.0001);
      }
      if(i == 1){
    A=0;B=1;C=1;
    c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
    z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
    wait(0.0001);
      }
      if(i == 2){
    A=1;B=0;C=1;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
        z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
        wait(0.0001);
      }
      if(i == 3){
    A=0;B=0;C=1;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
        z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
        wait(0.0001);
      }
      if(i == 4){
    A=1;B=1;C=0;
    c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
    z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
    wait(0.0001);
      }
      if(i == 5){
    A=0;B=1;C=0;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
        z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
        wait(0.0001);
      }
      if(i == 6){
    A=1;B=0;C=0;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
     z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
         wait(0.0001);
      }
      if(i == 7){
    A=0;B=0;C=0;
        c0=had[i][0];c1=had[i][1];c2=had[i][2];c3=had[i][3];c4=had[i][4];c5=had[i][5];c6=had[i][6];c7=had[i][7];
        z0=jablko[i][0]*hlava[i][0];z1=jablko[i][1]*hlava[i][1];z2=jablko[i][2]*hlava[i][2];z3=jablko[i][3]*hlava[i][3];z4=jablko[i][4]*hlava[i][4];z5=jablko[i][5]*hlava[i][5];z6=jablko[i][6]*hlava[i][6];z7=jablko[i][7]*hlava[i][7];
        wait(0.0001);
      }
    }
  }
}

Funkce main probíhá celá v nekonečné smyčce, pro zajištění opakování hry. Následuje plnění pracovních polí příznakem o nepřítomnosti hada, nulování displeje a definice hada do výchozí polohy. Následuje smyčka hry která trvá tak dlouho dokud funkce konec nevrátí 0. Následují funkce pro zablikání hada po zakousnutí, výpočet a zobrazení skóre. Poslední smyčka while probíhá dokud není stisknuté tlačítko UP.

int main()
{
  while(1){
    int i,k=0,kk=40,t1,t2;
 
    srand (time(NULL)+ran*1000);        //pro skoronahodnou posloupnost
 
    for(i=0;i<65;i++){      //nulovani pracovnich poli
      h[i] = 65;
      hh[i] = 65;
    }
 
    nuldisp();      //na zacatku vynuluj displej
 
    for (i = 0; i < size; i++){     //pocatecni delka hada v zobrazovaci matici
      had[0][i] = 0;
    }
 
    h[0]=2;h[1]=1;h[2]=0;       // pocatecni had v pracovnim poli
    genj();     //generovani jablka
      while(konec()){       //smycka vlastni hry
        tlac();         //obsluha tlacitek
        dejmat();       //prevod z prac do matic
        ukaz();         //zobrazeni matice
 
        if(100*tsi.readPercentage() > 10){      // ovladani rychlosti hada, pokud se dotknu slideru ulozi se aktualni hodnota do promene
          kk = 110-100*tsi.readPercentage();    // doleva pomalejsi doprava rychlejsi
        }
 
        if(k >= kk ){       // zajisteni pohybu hada danou rychlosti
          pohyb();
          chlamst();
          k = 0;
        }
        k++;
      }
  // zablikani hada pokud se zakousne
    nuldisp();
    cekej();
    dejmat();
    cekej();
    nuldisp();
    cekej();
    dejmat();
    cekej();
    nuldisp();
    cekej();
    nuldisp();
 
    score(s);   // prepocet skore
    for(i = 0; i <= 65; i++){       // prevedeni do maticove podoby
      if(h[i] == 66){
    t1 = i % 8;
    t2 = i / 8;
      had[t2][t1] = 0;
      }
    }
    while(1){       //smycka zobrazujici skore az do stisku reset nebo sipky nahoru
      ukaz();
      if(up ==0){
    size = 3;s=2;posun = 0;
    wait(0.5);
    break;
      }
    }
  }
}

Videoukázka

Na videu jsou ukázané všechny funkce. Je ukázána krátká hra s hadem pohybujícím se všemi směry, sežrání jablka, zakousnutí hada a zobrazení skóre. Následuje restart hry a ukázka změny rychlosti.

Zhodnocení

V programu jsou implementovány všechny důležité funkce a hra je plně funkční. Program je připraven pro možnost implementování dalších funkcí jako výpočet skóre s ohledem na rychlost hada nebo náhodné generování překážek případně zrychlování hada po sežrání jablka. Tato vylepšení hry by vyžadovala implementaci jednoduchého menu které by umožnilo zapnout různé funkce.

2014/led-snake.txt · Poslední úprava: 2015/01/18 13:27 autor: Jan Novotný