Zpět na seznam článků     Číst komentáře (13)     Verze pro tisk

Programování mikrokontrolérů architektury AVR (2)

Autor: Prog0el   
30.12.2015

Tentokrát o proměnných a operací s nimi. Proměnné jsou místa v paměti, které mají danou délku a formát dat a podle těchto kritérií v jazyce C rozlišujeme několik typů proměnných podobně, jako číselné obory v matematice. Bez použití proměnných by bylo čistě na programátorovi, aby si pamatoval kde má jaká data uložena a hlavně aby program zabezpečil proti nechtěnému přepsání jiných buněk paměti.


Všimněte si, že v tabulce celočíselných proměnných je ke každému datovému typu doplněn jakýsi ekvivalent s předřazeným klíčovým slovem „unsigned“. Ono tajemné slovo před datovým typem znamená, že se jedná o proměnnou bez znaménkového bitu, jinými slovy pro data máme k dispozici celý rozsah proměnné, nicméně, můžeme zaznamenávat pouze čísla kladná a to v celém rozsahu dle pravidla n=2k, kde „n“ je počet hodnot, které je možno zaznamenat, „2“ je základ binární soustavy a „k“ je délka proměnné v bitech. Mějte na paměti, že počet hodnot, které může proměnná nabývat, je včetně „0“, tj. pro zjištění maximální zaznamenatelné hodnoty do proměnné, musíme uvažovat výraz nc=2k-1.

Proměnné bez klíčového slova před datovým typem, nebo, mají-li předřazeno slovo „signed“, které se nemusí povinně uvádět, se považují za proměnné se znaménkovým bitem, což je bit, který rozhoduje o tom, zda bude následující blok dat reprezentovat kladné či záporné číslo. Kdybychom zase uvažovali vzorec pro počet stavů, které můžou být zaznamenány, dostaneme následující vzorec: ns=2k-1

Platí zde fakt, že při změně jednoho z bitů proměnné na znaménkový, dojde ke zmenšení počtu hodnot části s absolutní hodnotou na polovinu, avšak počet hodnot výsledného čísla zůstane zachován- viz tabulka níže.

Způsoby ukládání racionálních čísel si detailně probereme později, protože je v následujících dílech nebudeme ještě dlouhou dobu potřebovat. Obecně se racionálním číslům snažíme při programování vyhýbat kvůli nepřesnostem, které vyplývají z principu ukládání dat v těchto proměnných. Datový typ float se skládá z jednoho znaménkového bitu, osmi bitů pro exponent a 23 bitů pro mantisu, z čehož vyplývá, že způsob uložení dat se od celočíselných proměnných liší. Číslo uložené v proměnné se vypočítá následovně: x=a*2r, kde „a“ je mantisa a „r“ je exponent.


celočíselné proměnné
klíčové slovorozsahdélka [B]
char-128 ÷ 1271
unsigned char0 ÷ 2551
int-32768 ÷ 327672
unsigned int0 ÷ 655352
long int-4294967296 ÷ 42949672954
unsigned long int0 ÷ 42949672954
racionální proměnné
float -3.4*(10^38) ÷ 3.4*(10^38)4
double-3.4*(10^38) ÷ 3.4*(10^38)4

*Odlišností jazyka C pro počítače a jazyka lehce modifikované verze označované jako „GCC“ je mimo jiné fakt, že není rozdíl mezi datovými typy float a double. V klasickém C je datový typ double dvojnásobně přesný a bývá obvykle o délce 8B.

Deklarace proměnných v jazyce C

Dosud jsme se seznámili pouze s datovými typy proměnných, které bychom mohli definovat jako množiny proměnných se stejným formátem dat. Konkrétních proměnná má svou adresu v paměti a v prostředí jazyka C také svůj název, se kterým se programátorovi pracuje mnohem lépe v porovnání s použitím pouhých adres v paměti. Na příkladu níže si uvedeme příklad deklarace proměnné typu unsigned char.

Příklad
  1. unsigned char pocet_sovich_hnizd;
  2. // Proběhla deklarace proměnné „pocet_sovich_hnizd“

Důležitým faktem je, že jména proměnných nesmí být složena ze specifických symbolů a klíčových slov, kterými jsou například slova: if, while, for, char, ... Jazyk C je tzv. „Case Sensitive“, což znamená, že rozlišuje malá a velká písmena (na rozdíl od HTML) a na tuto skutečnost je také nutno přihlížet při volbě jmen proměnných. Použití diakritiky není doporučeno, jelikož není zaručeno, že ji kompilátor zpracuje korektně.

Aritmetické operace

Aritmetické operace v jazyce C nepředstavují žádný problém a zapisují se obdobně jako v matematice. Obecný způsob zápisu je proměnná, kam chceme ukládat výsledek následovaná znakem přiřazení „=“ za kterým následují dvě proměnné nebo čísla či jejich vzájemné kombinace oddělené znakem příslušné operace. V tabulce níže je uveden přehled aritmetických operací a jejich příslušných znaků:


aritmetické operace
operaceznakpříklad
Sčítání+a=a+b;
Odčítání-a=b-c;
Násobení*a=2*b;
Dělení/a=a/b;
Zbytek po celočíselném dělení („modulo“)%a=a%b;

Všimněte si, že do aritmetických operací s čísly, či proměnnými je možno zahrnout proměnnou, do které bude výsledek uložen, což se z hlediska matematiky může zdát jako nesmysl.

Mějte na paměti, že pokud při sčítání překročíte maximální zaznamenatelnou hodnotu konkrétní proměnné, dojde k přetečení a zbytek přičítaného čísla se přičte k „0“. Příkladem může být například následující operace s proměnou typu unsigned char:

Příklad
  1. a=250;
  2. a=a+10;
  3. // Výsledkem bude číslo „4“

U odčítání platí podobná pravidla, která si vysvětlíme rovnou na příkladu:

Příklad
  1. a=10;
  2. a=a-20;
  3. // Výsledkem bude číslo „246“

Pamatujte si, tedy, že čísla v proměnných je třeba uvažovat na číselné ose tvořenou uzavřenou kružnicí a nikoliv tedy přímkou.

Násobení nepředstavuje žádné obtíže, tj. pouze uvedu příklad:

Příklad
  1. unsigned char a=20;
  2. a=a*5;
  3. // Výsledkem je číslo „100“

Dělení je v jazyce C celočíselné, což znamená, že výsledkem je pouze číslo bez informace o zbytku po dělení. Zbytek po celočíselném dělení nám poskytuje funkce modulo. Užívá se stejně, jako kdybychom chtěli dělit dvě čísla avšak s tím rozdílem, že použijeme znak „%“ (viz tabulka výše).

Příklad
  1. a=5/3;
  2. // Výsledkem bude číslo „1“
  3.  
  4. a=5%3;
  5. // Výsledkem bude číslo „2“

Při přetečení u násobení, dělení a zbytku po celočíselném dělení se zaznamenají pouze bity, které se do dané proměnné zapsatelné a zbylé bity jsou ignorovány.

Zkrácené tvary

Aritmetické operace můžeme zapisovat zkráceně, abychom ušetřili čas a zvýšili přehlednost našeho zdrojového kódu.

  1. a++;    //a=a+1; (inkrementace)
  2. a--;    //a=a-1; (dekrementace)
  3. a+=10;  //a=a+10;
  4. a-=10;  //a=a-10;
  5. a*=10;  //a=a*10;
  6. a/=10;  //a=a/10;

Bitové operace a logické funkce

Doposud jsme si vysvětlovali operace, které sice známe z běžné matematiky, ale v mikroprocesorové technice bychom brzy narazili na problém, že nám v určitých případech, zejména při modifikaci hodnot části konfiguračních registrů, nedostačuje. Bitové operace spadají do tzv. „Booleovy algebry logiky“, která operuje pouze se stavy „1“-TRUE a „0“-FALSE a logické funkce zpracovávají čísla po jednotlivých bitech ve stejných vahách, protože původně byly logické funkce určeny pro vstupy i výstupy jednobitových dat. Níže je tabulka bitových operací jazyka C včetně kombinací, které můžou nastat za daných podmínek na vstupech (pravdivostní tabulka):


Logické funkce
názevzkratkaoperátorS0S1S2S3
Logický součinAND&0&0=00&1=01&0=01&1=1
Logický součetOR|0|0=00|1=11|0=11|1=1
NegaceNOT~~0=1~1=0
NonekvivalenceXOR^0^0=00^1=11^0=11^1=0
Posuny
Posun vlevo-<<----
Posun vpravo->>----

Jak již jsem zmínil, při použití bitové operace na více, než 1bitové číslo se zpracovává každý bit zvlášť, což ilustruje následující tabulka na funkci AND:


Číslo bitu76543210
proměnná 111110000
operátor&&&&&&&&
proměnná 200111100
přiřazení========
výsledek00110000

Pokud budete číst tabulku po sloupcích, všimnete si, že se jedná o stejné operace jako v tabulce logických funkcí výše. Je nutno poznamenat fakt, že pokud je jedno číslo kratší, než druhé, tak je využito od nejnižšího bitu a chybějící bity jsou doplněny nulami.

Abyste si byli schopni zapamatovat, co která funkce reprezentuje, nabízí se zde jejich definice:

  • Logický součin navrací 1, pokud jsou všechny vstupní proměnné rovny 1
  • Logický součet navrací 1, pokud je alespoň jedna vstupní proměnná rovna 1
  • Negace navrací 1, pokud je vstupní proměnná rovna 0 (jedná se o logickou funkci o jedné vstupní proměnné)
  • Nonekvivalence (exkluzivní logický součet) je roven 1, pokud si vstupní proměnné nejsou rovny (nejsou ekvivalentními).

Příklad
  1. unsigned char a;
  2. unsigned char b=0x0F;
  3. unsigned char a=0b11110000|b;
  4. //a bude rovno 0xFF (0x0F=0b00001111)

Jistě jste si všimli, že v předchozí tabulce jsem zmínil posun vlevo/vpravo. Nejedná se o funkci spadající do booleovy algebry logiky, avšak její funkce je často využívána.

  • Bitový posun vlevo „<<“ posouvá číslo doleva a zprava přidává nuly. Lze jej využít také pro rychlé násobení mocninami čísla 2.
  • Bitový posun vpravo „>>“ posouvá číslo doprava a zleva přidává nuly. Lze jej využít pro rychlé dělení čísla mocninami čísla 2.

Většina kompilátorů využívá pro úsporu času bitový posun kdykoliv to je možné, avšak nikdy na tento fakt nespoléhejte a v případě potřeby raději použijte přímo bitový posun.

Syntaxe příkazu je číslo, které chceme posouvat následované operátorem posuvu vlevo/vpravo, za kterým se nalézá číslo, o kolik míst chceme posouvat; celý příkaz ukončíme středníkem.

Příklad
  1. unsigned char a=16;
  2. a=a>>2;
  3. /* Posune číslo 16 (0b00010000) o dvě místa doprava, výsledkem bude 4 (0b00000100) */

Praktický příklad

Tento příklad již bude poněkud více efektní, než v prvním díle; jedná se o efekt tzv. „běžící had“, který bude využívat výše popsané operace. Jelikož jsem ještě nezmiňoval podmínky a cykly, budu se jim snažit vyhnout. Podmínky a cykly budou náplní již příštího dílu a následující kód by se jimi zjednodušil, což si budeme demonstrovat později.

Program nejprve inicializuje port B jako výstup a následně se spustí hlavní smyčka programu. V hlavní smyčce programu se zapíše do třech nejnižších bitů logická 1. Tato trojbitová skupina logických 1 reprezentuje „hada“. Pomocí bitových posunů vlevo a čekacích smyček zajistíme odsun hada vlevo až do jeho zmizení. Posléze se nastaví první, druhý a následně třetí nejvyšší bit do logické 1 (záměrně jsem zde pro demonstraci použil funkci OR) a k dalším posunům hada směrem doprava se využije bitový posun vpravo. Jakmile dojde k úplnému zmizení hada napravo, celý cyklus se opakuje po ukončení čekací smyčky.

Sestavíme si v nepájivém kontaktním poli následující obvod:

Podle návodu z prvního dílu připojte programátor a spusťte kompilaci stiskem tlačítka „F5“. Zkontrolujte si, zda máte nastaven zdroj taktovacího signálu na interní RC oscilátor o frekvenci 8MHz.

Zdrojový kód běžícího hada poskytuji ke stažení.

Reference:

https://gcc.gnu.org/wiki/avr-gcc
http://www.atmel.com/images/doc8453.pdf


Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 1.13/8

1  2  3  4  5    
(známkování jako ve škole)