C suli 8 - KITT futófény, tömb kezelés

2016-10-27

 

Ezt a kapcsolást fogjuk most programozni. Jócskánt átrendeztem a lábakat, mert a PORTD-nek van az összes lába kivezetve.

Emlékeztetőül az ATmega8 bekötése:

Ebben a programban egy LED-et kapcsolunk be. Figyeljük a két kapcsolót, és attól függően, hogy a BAL, vagy a JOBB hombot nyomjuk le, a fény balra, vagy jobbra lép. A már korábban megismert bit léptető operátort használjuk. Az ott leírtak szerint, a byte-ba 0 bitek lépnek be, ezért a belépő bitet felül kell írnunk, hogy az a LED ne világítson. Majd meg kell vizsgáljuk, ha végigléptettük a 0-t, akkor egy 0-t újra be kell tennünk, hogy a folyamat újra kezdődjön. A ciklus végén a várakozásnak az a jelentősége, hogy különben egy hosszab gombnyomásra ki tudja hány léptetést hajtana végre az áramkör? Így 300 miiisecundumonként legfeljebb egyet.


/*******************************************************************************
*
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2016.10.25.
*   Chip         -  ATmega8
*   Compiler     -  avr-gcc
*
*   c_suli_8_1.c
*   Vilagito pont leptetese gombnyomasra
*
*******************************************************************************/

#define F_CPU  4 MHZ

#include "tkiraaly_atmega8.h"
#include <util/delay.h>

#define  BAL_FELHUZAS    PB1_PULLUP
#define  BAL_GOMB        PB1_RD == 0

#define  JOBB_FELHUZAS   PB2_PULLUP
#define  JOBB_GOMB       PB2_RD == 0


int main( void) 
{
   BAL_FELHUZAS;
   JOBB_FELHUZAS;
   PORTD= 0B11111110;                                 // csak a jobb szelso LED vilagit
   DDRD=  0B11111111;                                 // D port osszes laba kimenet
   for(;;)
   {
      if ( BAL_GOMB)
      {
         PORTD= ( PORTD << 1)+ 0B00000001;      // leptetes, legalso bit feluliras
         IF ( PORTD == 0B11111111) PORTD= 0B11111110; // ha vegigfutot, kezdes elolrol 
      }
      if ( JOBB_GOMB)
      {
         PORTD= ( PORTD >> 1)+ 0B10000000;      // leptetes, legfelso feluliras
         IF ( PORTD == 0B11111111) PORTD= 0B01111111; // ha vegigfutot, kezdes elolrol 
      }
      _delay_ms( 300);
   }
}

Ezt most átalakítjuk KITT-nek. Remélem a legtöbb embernek megva a fekete, beszélő Pontiac Firebird, a Knigh Rider-ből, az elején jobbra balra futó piros fénnyel. A programunkban használunk egy irany változót, és ez fogja vezérelni, hogy éppen balra, vagy jobbra kell léptetni a biteket. Ha 0 bit a byte szélére ért, egyszerűen irányt váltunk, és a következő ciklusban már visszafelé léptetünk.


/*******************************************************************************
*
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2016.10.25.
*   Chip         -  ATmega8
*   Compiler     -  avr-gcc
*
*   c_suli_8_2.c
*   KITT futofeny
*
*******************************************************************************/

#define F_CPU  4 MHZ

#include "tkiraaly_atmega8.h"
#include <util/delay.h>

#define BAL        0
#define JOBB       1


int main( void) 
{
   PORTD= 0B11111110;                                 // csak a jobb szelso LED vilagit
   DDRD=  0B11111111;                                 // D port osszes laba kimenet
   unsigned char irany= BAL;
   for(;;)
   {
      if ( irany == BAL)
      {
         PORTD= ( PORTD << 1)+ 0B00000001;            // leptetes, legalso bit feluliras
         IF ( PORTD == 0B01111111) irany= JOBB;       // ha vegigfutot, iranyvaltas 
      }
      else
      {
         PORTD= ( PORTD >> 1)+ 0B10000000;            // leptetes, legfelso feluliras
         IF ( PORTD == 0B11111110) irany= BAL;        // ha vegigfutot, iranyvaltas 
      }
      _delay_ms( 300);
   }
}

Számos fény mintát ki tudunk gondolni, olyanokat is, amelyeket elég nehéz fügvénnyel, vagy programmal megvalósítani. Egyszerű megoldhatjuk a problémát, ha a mintákat letároljuk, és a tárból lépésenként vesszük elő a következőt. A tárolást egy egydimenziós adattömbben, másképpen füzérben (idegen szóval string-ben, vagy vektorban) tudjuk megvalósítani. Így néz ki egy 5 elemű tömb (0..4) létrehozása.


unsigned int t[ 5];

Ez követően így tárolhatunk el a tömmben adatokat:.


t[ 1]= 123;
t[ 3]= 0x12;
t[ 0]= 0;

Egyszerübb helyzetben vagyunk, ha már kezdetben tudjuk milyen adatokkal akarjuk a tömböt feltölteni. Ekkor így adhatjuk meg a tömböt, a C fordító ki fogja számolni, hány elemű tömb kell hozzá.


unsigned int t[]= { 123, 48, 21, 98, 120};

Tehát kombinációinkat a minta nevű tömbbe tároljuk el. Az i fogja mutatni, hogy melyik elem következik. Háromtized másodpercenként kiírunk egy mintát PORTD-re, majd a mutatót megnöveljük. Fontos, hogy i ne mutasson a tömbön túlra, mert nem fogunk hibaüzenetet kapni, a C kiszámolja a memóriában hova esne az az elem, és visszadja annak a memória cellának az értékét, ha a tömb egy eleme van benne, ha nem.


/*******************************************************************************
*
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2016.10.25.
*   Chip         -  ATmega8
*   Compiler     -  avr-gcc
*
*   c_suli_8_3.c
*   Feny minta, tomb kezeles
*
*******************************************************************************/

#define F_CPU  4 MHZ

#include "tkiraaly_atmega8.h"
#include <util/delay.h>


int main( void) 
{
   unsigned int i= 0;                                 // mutato
   unsigned int minta[]=
   {
      0B10111111,
      0B11011111,
      0B11101111,
      0B11110111,
      0B11111011,
      0B11111101,
      0B10111101,
      0B11011101,
      0B11101101,
      0B11110101,
      0B11111001,
      0B10111001,
      0B11011001,
      0B11101001,
      0B11110001,
      0B10110001,
      0B11010001,
      0B11100001,
      0B10100001,
      0B11000001,
      0B10000001
   };
   DDRD=  0B11111111;                                 // D port osszes laba kimenet
   for(;;)
   {
      if ( i > 20) i= 0;
      PORTD= minta[ i];
      i++;
      _delay_ms( 300);
   }
}

Fontos megemlíteni, hogy a C-ben nemcsak egy dimenziós, hanem 2, 3... sőt több dimenziós tömbök is kezelhetők. uC környezetben ezek nem jellemzők, mert az ilyen nagy tömbök tárolásához azért jelentős memóriai is kell. A példában szereplő k tömbhöz 2kB memória szükséges. És lehet ezt fokozni, ha nagyobb számú, vagy nagyobb méretű adat elemeket kell eltárolnunk...


unsigned char c[ 3, 10];
int k[ 10, 10, 10, 10],

Szintén fontos megemlíteni, hogy a C-ben nemcsak indexxel tudunk egy tömbre hivatkozni, hanem úgyneveztt mutatóval is. Most csak elvi szinten beszélek a mutatókról, majd megpróbálok valami jó, ideillő példát kitalálni. Mutatókat nagyon gyakran használunk C-ben. Sokan utálják a mutatókat. Egy mutató mutathat a tömb egy elemére, valamilyen adatra, de akár egy függvényre is, értékét eltárolhatjuk, vagy műveleltet végezhetünk vele. Előnye, hogy mutatóval a C gyorsabban tudja kezelni az adatokat, mint index segítségével. Például az objektum orientált programozásnál (C++) fontos szerepe van függvényre mutató mutatónak, mert így az adatokhoz tudjuk kapcsolni az azt kezelő függvényt.