AVR GCC kompilator C dla mikrokontrolerów AVR, część 3


K U R S
AVR-GCC: kompilator C
mikrokontrolerów AVR, część 3
Kontynuujemy cykl artykułów, których zadaniem jest przedstawienie podstaw
oraz praktycznych zasad programowania mikrokontrolerów AVR w języku C
z użyciem kompilatora avr-gcc. Oczywiście wybór kompilatora AVR-GCC może
się jednym podobać, a innym nie. Postaramy się jednak uzasadnić, że nie
jest to zły wybór.
Zmienne liczbowe i organizacja kowanych pod znanym adresem w zerowany po włączeniu zasilania, ale
pamięci wewnętrznej ATmega pamięci danych, zobaczmy najpierw zachowywał swoją wartość podczas
Pisząc oprogramowanie dla mi- jak avr gcc zarządza tą pamięcią (a resetu spowodowanego zadziałaniem
krokontrolera cały czas operujemy konkretnie obszarem przeznaczonym watchdoga). Oczywiście wtedy mu-
na rozmaitych wielkościach: odczy- dla użytkownika  powyżej rejestrów simy sami zadbać w kodzie o wpi-
tujemy, uśredniamy i filtrujemy wy- SFR). Na rys. 8 (zaczerpniętym z sanie odpowiednich wartości (także
niki przetwarzania ADC, zliczamy podręcznika avr libc) widzimy do- zer)  w przeciwnym razie pozosta-
impulsy na wejściach licznikowych, myślnie stosowany schemat wykorzy- ną one całkowicie przypadkowe.
odmierzamy czas, wyświetlamy na- stania wewnętrznego SRAMU. Pojawiło się tutaj pojęcie sekcji
pisy i liczby na różnego rodzaju Stos (jak już stwierdziliśmy wcze-  jest to mechanizm wykorzystywa-
wyświetlaczach, wyliczamy wypeł- śniej) rozpoczyna się od końcowego ny przez konsolidator do podziału
nienie cyklu PWM itd. Wszystkie te adresu (określanego w avr libc sym- dostępnych zasobów pamięci na po-
wielkości zmieniające swoją wartość bolem RAMEND)  jest wypełniany szczególne obszary i odpowiedniego
w trakcie działania programu noszą  w dół czyli dekrementowany. przydzielenia do nich składników
ogólną nazwę zmiennych. Klasyfika- Bezpośrednio za obszarem SFR programu (oprócz wspomnianych po-
cja zmiennych jest bardzo różnorod- rozpoczyna się sekcja .data, w któ- wyżej sekcji danych mamy do czy-
na, na przykład: rej konsolidator umieszcza wszystkie nienia z sekcją .text opisującą kod
 według pełnionej funkcji: zmien- zmienne inicjalizowane (z przypisaną programu umieszczony w pamięci
ne liczbowe, znakowe, logiczne, wstępnie niezerową wartością). Flash oraz sekcją .eeprom przezna-
tekstowe (łańcuchowe), wskazniki; Dalej jest ulokowana sekcja .bss, czoną dla zawartości wewnętrznego
 według złożoności: zmienne pro- zawierająca zmienne bez przypisanej EEPROMu kostki). Adresy startowe
ste (np. pojedyncza liczba) i zło- wartości, które zgodnie ze standar- sekcji oraz ich maksymalne rozmiary
żone (tablice, struktury, unie); dem C zostają na początku progra- dla danego mikrokontrolera znajdzie-
 według zakresu, znaku oraz typu mu wyzerowane; my we wspomnianych już wcześniej
liczby (dotyczy zmiennych liczbo- Następnie przewidziano dodat- skryptach linkera.
wych); kowÄ…  specyficznÄ… dla mikrokon- Przypisanie zmiennej do konkret-
 według sposobu obsługi przez kom- trolerów  sekcję .noinit. Obejmuje nej sekcji jest realizowane albo do-
pilator (inicjalizowane lub nie). ona zmienne, które chcemy pozosta- myślnie przez konsolidator (sekcje
Tutaj zajmiemy się sposoba- wić wyłącznie pod własną kontrolą .data oraz .bss są obsługiwane sa-
mi używania różnych zmiennych  kompilator nie wykonuje na nich moczynnie na podstawie deklaracji
w avr gcc. Bardziej sformalizowane żadnych automatycznych operacji. zmiennej) albo poprzez dodatkowy
i szczegółowe opisy i klasyfikacje Ma to na celu głównie zróżnicowanie atrybut (dla .noinit lub .eeprom).
znajdziemy w każdym uniwersalnym sposobu inicjalizowania niektórych Zobaczmy teraz jak to działa w
podręczniku języka C. Ponieważ każ- zmiennych w zależności od przyczy- praktyce. Załóżmy sobie w AvrSide
da zmienna jest dla mikrokontrolera ny resetu (np. możemy zechcieć aby  zgodnie z poprzednimi opisami
po prostu pewną liczbą bajtów ulo- licznik czasu pracy urządzenia był  nowy projekt Test02 w subfolderze
[Projects\Kurs\Przyklad 02], z jednym
plikiem zródłowym main.c. Zade-
klarujmy kilka zmiennych typu int
(mają one rozmiar 2 bajtów, o czym
dokładniej za chwilę) oraz zdefiniuj-
my uproszczony zapis atrybutu sek-
cji .noinit (ta ostatnia operacja nic
nie zmienia w działaniu kodu, służy
wyłącznie wygodzie pisania):
// główny moduł projektu
#define _MAIN_MOD_ 1
#define NOINIT __attribute__ ((section
( .noinit )))
// pliki dołączone (include):
// dane:
Rys. 8. Sekcje pamięci w wewnętrznym SRAM ATmega
int data1 = 2; // zmienna inicjalizowa-
Elektronika Praktyczna 5/2005
101
K U R S
na wartością
pokazał nam 116 bajtów. Te dodatko- ale niestety bez prawidłowego pod-
int bss1; // zmienne zerowane
int bss2; we dwa bajty to właśnie początkowa glądu zawartości pamięci).
int noinit1 NOINIT; // zmienna nie ini-
wartość zmiennej data1. Nie wez- Omówimy teraz dokładniej używa-
cjalizowana
mie się ona przecież  z powietrza ne przed chwilą zmienne liczbowe.
// funkcje:
//==================
i musi być gdzieś przechowywana  1  Najprostszą wersją zmiennej
// funkcja main()
avr gcc dopisuje ją na końcu pliku liczbowej jest liczba całkowita bez
int main(void)
{
wynikowego kodu, skąd przy starcie znaku, (czyli podzbiór liczb natural-
// inicjalizacja
programu jest przepisywana (spójrz- nych oraz zero). Avr gcc obsługuje
noinit1 = 0x55; // tutaj samodzielnie
my jeszcze raz na omówiony wcze- następujące typy liczby bez znaku,
inicjalizujemy zmiennÄ… NOINIT
// pętla główna
śniej kod automatycznej inicjalizacji) różniące się tylko wielkością:
while (1)
pod odpowiedni adres SRAM. Zajęty unsigned char  zajmuje jeden
{
}
obszar zasobów Flash jest więc w bajt, może więc przyjąć wartość od
}
rzeczywistości równy sumie sekcji zera do 0xff czyli 255;
Po kompilacji pasek statusu poka- .text i .data  taki też rezultat wy- unsigned int  2 bajty, a więc 0
że nam zużycie RAM równe 8 baj- świetla AvrSide.  0xffff (65535);
tów  jest to suma zmiennych we Zobaczmy teraz jak powyższe unsigned long  4 bajty  0 
wszystkich sekcjach (4*2). Po bar- zmienne zachowajÄ… siÄ™ w AvrStudio. 0xffffffff (4294967295);
dziej szczegółowe informacje sięgnij- Po uruchomieniu nowej sesji ustaw- unsigned long long  8 bajtów 
my do pliku rejestracyjnego Text02. my sobie podgląd wszystkich zmien- do rzeczywiście wielkich wartości (ra-
txt. Znajdziemy tam m.in. tabelę do- nych oraz uaktywnijmy okienko pa- czej rzadko będzie nam potrzebny w
kładnej specyfikacji używanych sek- mięci z obszarem danych (rys. 9). świecie małych mikrokontrolerów, nie
cji (utworzoną w wyniku wywołania Widzimy, że data1 przybrała od- jest też obsługiwany przez AvrStudio).
narzędzia avr objdump z opcją  h): powiednią początkową wartość (2), Te typy są interpretowane najbar-
zmienne bss1 i bss2 zostały wyzero- dziej bezpośrednio  wartość jest po
Sections:
Idx Name Size VMA
wane, a noinit1 pozostała bez inge- prostu równa zawartości odpowied-
0 .text 00000072 00000000
rencji (symulator AvrStudio jest nie- niej liczby jednobajtowych komórek
1 .data 00000002 00800060
2 .bss 00000004 00800062 co wyidealizowany i nadaje jej war- pamięci. Jednak nawet w tym pro-
3 .noinit 00000002 00800066
tość 0xffff, w rzeczywistości komórki stym przypadku konieczne jest przy-
4 .eeprom 00000000 00810000
SRAM mogą po włączeniu zasilania jęcie pewnej konwencji  określanej
Widzimy, że zmienne powędrowa- zawierać całkiem przypadkowe war- mianem  endianess  czyli sposo-
ły do odpowiednich sekcji (jedna ini- tości). Przejdzmy teraz pracą kroko- bu uporządkowania kolejnych bajtów
cjalizowana  2 bajty w .data, dwie wą (F11) do pętli while. Zmienna liczby w pamięci. W różnych kom-
zerowane  4 bajty w .bss, jedna noinit1 przybierze wartość zgodną z pilatorach możemy napotkać dwie
 samodzielna  2 bajty w .noinit; w wpisanym przez nas kodem (0x55 przeciwstawne metody:
.eeprom nie deklarowaliśmy nic). W czyli 85 dziesiętnie). Jeśli teraz zre- big endian  bajty liczby są lo-
kolumnie VMA znajdziemy też ad- setujemy program (Shift + F5), to kowane pod kolejnymi adresami pa-
res startowy każdej sekcji (początek zobaczymy, że wartość noinit1 pozo- mięci od najbardziej do najmniej
.data to 0x60  zaraz po obszarze stanie nienaruszona. znaczÄ…cego (czyli np. liczba unsigned
SFR w Atmega 8 ; rolę przesunięcia Zwróćmy uwagę, że debugger C long 0x11223344 będzie zapamiętana
0x800000 wyjaśnimy pózniej). z AvrStudio całkowicie pomija auto- w SRAM jako kolejno: 0x11, 0x22,
Spójrzmy jeszcze na sekcję kodu matyczną inicjalizację  widzimy od 0x33, 0x44);
.text. Ma ona rozmiar 0x72=114 baj- razu efekty jej działania (możemy little endian  bajty liczby są lo-
tów. Wynik kompilacji w AvrSide ją prześledzić w oknie disasemblera, kowane od najmniej znaczącego (czy-
li 0x44, 0x33, 0x22, 0x11).
Jeśli spojrzymy na rys. 9 (oraz
obejrzymy generowany kod asemblera)
zauważymy od razu, że avr gcc po-
sługuje się modelem little endian. Za-
zwyczaj ta informacja nie będzie nam
specjalnie potrzebna, kompilator sam
dba o odpowiedni porzÄ…dek, jednak
może być przydatna w momencie wy-
korzystywania zmiennej wielobajtowej
z poziomu wstawki asemblerowej.
Aby sprawy nie wyglądały tak
prosto należy dodać, że niektóre
opcje kompilacji potrafią zmieniać
domyślny rozmiar powyższych typów.
Jeśli więc mamy w planach ich sto-
sowanie (konkretnie chodzi o opcjÄ™
 mint8, która zmniejsza rozmiary ty-
pów liczb, a tym samym pozwala na
zredukowanie w razie konieczności
Rys. 9. Zmienne inicjalizowane w AvrStudio objętości kodu), to dla zmiennych o
Elektronika Praktyczna 5/2005
102
K U R S
3  Liczby rzeczywiste  może-
my je obsługiwać w dwojaki sposób.
Uproszczona forma to tzw. zapis sta-
łoprzecinkowy (fixed point). Używamy
tutaj z góry określonej i niezmiennej
liczby cyfr po przecinku, niezależnie
od wartości. Przykładem z codzien-
nego świata liczb dziesiętnych mogą
być ceny. Zauważmy, że stosowanie
liczb stałoprzecinkowych w programie
jest  przy odpowiednim doborze
Rys. 10. Zapis pojedynczej precyzji liczby rzeczywistej jednostek  równoznaczne z oblicze-
niami na liczbach całkowitych. Np.
wymaganym znanym i stałym roz- Musimy też dodać do deklaracji chcemy mierzyć napięcie w woltach
miarze użyjmy raczej typów zdefi- data1 słowo kluczowe volatile (vola- z rozdzielczością 0,001 V. Wystarczy
niowanych w pliku nagłówkowym tile int data1 =  1;) gdyż w prze- wtedy zaprojektować tor analogowo
stdint.h w subfolderze [avr\include] ciwnym razie optymalizator wytnie  cyfrowy tak, aby jednemu najmniej
kompilatora. Jest to metoda bardzo zbędne z jego punktu widzenia po- znaczącemu bitowi wyniku konwer-
zalecana przez autorów avr libc jako średnie operacje na data1 wstawiając sji AC odpowiadał 1 mV sygnału
zapewniająca całkowitą jednoznacz- od razu ostateczny wynik. wejściowego. Wszystkie wewnętrzne
ność określonego typu przy różnych Oczywiście, ponieważ zajęty zo- pomocnicze obliczenia (filtrowanie,
warunkach kompilacji (np. int8_t ma stał najbardziej znaczący bit  zakres alarmy itp.) wykonujemy wtedy na
zawsze 1 bajt, int16_t  2 bajty itd.). wartości bezwzględnej typu zostanie wartościach całkowitych wyrażonych
Pozostaje oczywiście kwestia indywi- zmniejszony o mniej więcej poło- w miliwoltach. Ostateczna prezenta-
dualnych gustów i przyzwyczajeń, wę. Ze sposobu kodowania wynika cja wyniku w woltach będzie polegać
jednak C pozwala za pomocą opera- pewna asymetria: np. dla typu int wyłącznie na wstawieniu kropki dzie-
tora typedef określić zupełnie dowol- wartością maksymalną będzie 0b0111 siętnej w odpowiednim miejscu.
ne własne nazwy typów (np. często 1111 1111 1111 (czyli 0x7fff)=32767 Zapis stałoprzecinkowy sprawdzi
spotykane s08, s16, u08, u16). W zaś minimalną 0b1000 0000 0000 się dobrze jeśli wartość zmiennej po-
prezentowanych przykładach również 0000 (0x8000)= 32768. zostaje w ustalonym, znanym zakresie.
używam nazewnictwa tradycyjnego, Liczby ze znakiem możemy dla Jednak wartości zbyt małe lub zbyt
które mi jakoś lepiej pasuje niż stan- pełnej jasności deklarować ze sło- duże nie będą przedstawiane skutecz-
dard proponowany w avr libc. wem kluczowym signed, ale ponie- nie. Np. dla dużych wartości mie-
2  Liczby całkowite ze znakiem waż jest to opcja domyślna zazwy- rzonych z dokładnością 1000 istotne
są już nieco bardziej skomplikowa- czaj ją pomijamy. jest rozróżnienie pomiędzy 1200000
ne. Znak jest określony stanem naj- Należy jeszcze dodać, że typ int a 1201000  zapis 1200000,00 nie
starszego bitu  0 oznacza plus, a 1 jest domyślny dla kompilatora. Wszę- wnosi żadnej informacji i może pro-
minus. Jednak wbrew oczekiwaniom dzie gdzie z kodu nie wynika jed- wadzić tylko do marnowania czasu
pozostałe bity określają bezpośrednio noznacznie, jakiego  rozmiaru liczby programu na zbędne przeliczenia. Z
wartość liczby tylko dla wartości do- użyć w operacji stosowany jest int kolei małe liczby będą całkiem nie-
datniej, wartości ujemne są zakodo- (tzw. promocja do int). Czasem jest to rozróżnialne: zarówno 0,001 jak i
wane w tzw. dopełnieniu do dwóch pożyteczne, ale w pewnych przypad- 0,004 zostaną zapisane jako 0,00. Od
(U2). Obejrzyjmy to zaraz w symula- kach powoduje zgoła nieprzewidziane razu widać, że istotna jest nie przyję-
torze wpisując do naszych zmiennych rezultaty (np.  obcinanie wielkości ta liczba cyfr po przecinku, ale grupa
(np. data1) różne wartości i oglądając liczb na pośrednich etapach bardziej cyfr znaczących niosąca rzeczywistą
w okienku pamięci ich bajtową repre- złożonych przeliczeń). Będziemy do informację o wartości.
zentację. Na przykład wartość  1 zo- tej sprawy, jak również powiązanego W takich przypadkach stosuje-
stanie zapisana jako 0xffff. Taki mało z nią rzutowania typów wielokrotnie my format zmiennoprzecinkowy (flo-
intuicyjny sposób kodowania wynika przy różnych okazjach powracać. ating point). Jest on bardzo podobny
z prostoty zachowania wartości przy Jak widać z powyższego staranność do znanej notacji tzw. inżynierskiej:
rzutowaniu typów oraz symetrycznej i i uwaga przy doborze odpowiednie- liczba jest zapisana jako mantysa
niezależnej od liczby bajtów procedu- go typu dla zmiennej może w wielu (przedstawiająca grupę cyfr znaczą-
ry odwracania znaku. Znak liczby w przypadkach wręcz decydować o po- cych) oraz wykładnik potęgi (określa-
kodzie U2 zmieniamy negując wszyst- prawności działania programu. Prze- jący mnożnik decydujący o wielkości
kie bity liczby i dodając do wyniku kroczenie zakresu, potraktowanie war- liczby). Zarówno wartości wielkie
jeden. Możemy od razu sprawdzić jak tości dodatniej jako liczby ze znakiem np. 2,78E6 (czyli 2,78*106=2780000),
to działa w praktyce poddając odpo- (np. ten sam bajt 0xff zadeklarowany j a k i m ałe n p. 3, 55E 3 (czy li
wiednim operacjom naszÄ… zmiennÄ… jako unsigned char jest traktowany 3,55*10 3=0,00355) sÄ… przedstawione
 np. data1. Dopisujemy na początku przez kompilator jako wartość dodat- w jednakowy sposób bez utraty do-
main() sekwencję: nia +255, natomiast użyty jako signed kładności. Zapis samej mantysy jest
char zostanie odczytany jako  1) itp. również znormalizowany: wartość X
// inicjalizacja
data1 = ~data1;
mogą powodować trudne do zlokalizo- umieszczona przed kropką dziesiętną
data1 +=1;
wania (i w żaden sposób nie sygnali- zawiera się w zakresie 1= data1 = ~data1;
data1 +=1;
zowane na etapie kompilacji) błędy. (a generalnie < podstawa używanej
Elektronika Praktyczna 5/2005
103
K U R S
potęgi)  nie piszemy np. 35,5E2 jekcie zmienną float i na początku że przedstawiony powyżej zapis bi-
(3550), ale 3,55E3. funkcji main przypiszmy jej wartość narny jest tylko przybliżony i nie
Reprezentacja binarna formatu np.  300,0. Po skompilowaniu znaj- zawsze dokładnie odzwierciedli war-
zmiennoprzecinkowego jest określona dziemy kod (F7  relokowalny): tość liczby. Nasz przykład z liczbą
specyfikacją IEEE 754 (Institute of tst= 300.0;  300 był pod tym względem przy-
8: 80 e0 ldi r24, 0x00 ; 0
Electrical and Electronics Engineers  jazny, ale np. zwyczajne 0,01 już
a: 90 e0 ldi r25, 0x00 ; 0
zajmuje się m.in. międzynarodowymi się nie da przedstawić dokładnie
c: a6 e9 ldi r26, 0x96 ;
150
standardami i normami). Stosowane (możemy to obejrzeć w podglądzie
e: b3 ec ldi r27, 0xC3 ;
sÄ… dwie odmiany zapisu: pojedynczej zmiennych AvrStudio: otrzymujemy
195
10: 80 93 00 00 sts 0x0000, r24
precyzji (single precision) zajmujący 0,0099999998). Użycie takich przy-
14: 90 93 00 00 sts 0x0000, r25
4 bajty oraz znacznie dokładniejszy bliżonych liczb w dłuższych pętlach
18: a0 93 00 00 sts 0x0000, r26
podwójnej precyzji (double precision obliczeniowych może prowadzić do
1c: b0 93 00 00 sts 0x0000, r27
 8 bajtów). Avr gcc obsługuje tylko Do rejestrów została załadowana znaczącego  i niemożliwego do wy-
pojedynczą precyzję (możemy spraw- wartość 0xC3960000, co odpowiada eliminowania błędu.
dzić, że niezależnie od użytej w zapisowi binarnemu: Znając już strukturę liczby rze-
programie deklaracji zmiennej: float 1100 0011 1001 0110 0000 czywistej stwierdzimy, że nie jest
czy double zajmie ona zawsze tylko 0000 0000 0000 żadnym problemem przesyłanie jej
4 bajty). Znaczenie poszczególnych Zgodnie ze specyfikacją: w różny sposób pomiędzy urządze-
bitów w 4 bajtowym pakiecie przed- znak=1 czyli liczba ujemna, niami. Np. w komunikacji szerego-
stawia rys. 10. w y k Å‚ a d n i k = 1 3 5 wej po prostu transmitujemy kolejne
Najstarszy bit (31) określa znak ( 1 0 0 0 0 1 1 1 )  1 2 7 = 8 ; 4 bajty, musimy jedynie pamiętać o
liczby: 0 odpowiada wartości dodat- zatem mnożnik wyniesie 28=256, ich takiej samej kolejności w bufo-
niej, 1  wartości ujemnej. mantysa=1+1/8+1/32+1/64(20+2 3 rze nadajnika i odbiornika oraz o
Wykładnik potęgi o podstawie 2 +2 5+2 6)=75/64 (doliczamy domyśl- jednakowej interpretacji (deklaracji)
jest zakodowany w 8 bitowym polu ne 20). liczby w obu programach.
(30  23) jako wartość binarna tego Ostateczny wynik= 256*75/64= Bardzo uniwersalne i wygodne
pola pomniejszona o stałe przesu-  300  zgodnie z naszą instrukcją od strony programowej liczby flo-
nięcie 127 (czyli np. 0000 0010=2 w kodzie. at mają jednak w świecie małych
oznacza wykładnik  125, 1000 Nietrudno teraz zauważyć, że mikrokontrolerów jedną zasadniczą
0000=128 oznacza 1 itd.). Wartości najmniejszą możliwą do zapisania w wadę  pochłaniają dużo ograni-
0000 0000 i 1111 1111 są zarezer- ten sposób liczbą będzie 2 126 (mini- czonych zasobów pamięci. Zróbmy
wowane (o czym za chwilę) więc malny wykładnik  126 i minimalna znów szybki eksperyment wpisując
zakres wykładnika wynosi od  126 mantysa 20). A co z liczbami mniej- do naszego testowego programu de-
(0000 0001=1 127) do 127 (1111 szymi oraz zerem? Dla nich przewi- klaracjÄ™:
1110=254 127). dziano właśnie wartość 0000 0000
#ifdef FLOAT
double li1 = 2500;
Trochę więcej uwagi musimy w polu wykładnika. Obowiązuje
double li2 = 400;
poświęcić mantysie. Zgodnie z po- wtedy oddzielna reguła przeliczania:
double wynik;
#else
przednimi informacjami powinna wykładnik jest nadal równy  126
long li1 = 2500;
być ona zapisana jako C.UUUU... natomiast w mantysie uwzględniamy
long li2 = 400;
gdzie część całkowita C zawiera się tylko część ułamkową, zaś 20 zostaje long wynik;
#endif
pomiędzy 1, a podstawą potęgi zaś pominięte.
U jest częścią ułamkową. W zapisie Z kolei druga zarezerwowana i wykonajmy gdzieś w main()
binarnym podstawą jest 2, a więc: wartość pola wykładnika: 1111 1111 prostą operację:
1<=C<2 co jak widać jest równo- służy nie do przedstawiania konkret- wynik=li1*li2;
znaczne z warunkiem C=1. Dlate- nej liczby ale stanowi sygnał, że w Po skompilowaniu sprawdzmy
go w powyższej bitowej reprezenta- procesie obliczeń przekroczone zosta- wielkość kodu  nie jest zbyt duża
cji C zostało całkowicie pominięte ły możliwe do zapisu zakresy. Spró- (w przykładowym teście wynosiła
(jest domyślnie traktowane jako 1) i bujmy wykonać eksperyment dzieląc 4% pojemności Flasha Atmega 8). A
wszystkie 23 bity mantysy są uży- liczbę dodatnią i ujemną przez 0. teraz przed powyższą deklaracją zde-
te do określenia części ułamkowej. Uzyskamy właśnie takie rezultaty, finiujmy makro FLOAT:
Kolejne bity  ułamkowe odpowiada- interpretowane przez AvrStudio jako #define FLOAT
ją potęgom 2 n gdzie n jest pozycją 1.#INF oraz  1.#INF (czyli + i i spróbujmy jeszcze raz. Kod
bitu za kropką dziesiętną. Pierwszy  nieskończoność), a więc wartości gwałtownie rozrósł się do 21%!! Tyle
bit za kropką, (czyli pierwszy w nieokreślone. Dla ścisłości: nie jest kosztuje dolinkowanie potrzebnych
opisywanej mantysie, co odpowia- to do końca zgodne ze standardem funkcji obsługujących liczby zmien-
da bitowi nr 22 w całej 4 bajtowej przewidującym dla takiego przypad- noprzecinkowe (możemy je sobie
paczce) ma, więc wartość (wagę) 2 1 ku oddzielny sygnał NaN (Not a przejrzeć w podglądzie CTRL + F7).
(½), nastÄ™pny 2 2 (ź) itd. Dla okre-  Number  to nie jest liczba), ale w Wniosek jest prosty: typ float pozo-
ślenia całej wartości należy zsumo- przeważajacej większości typowych stanie zarezerwowany dla większych
wać wagi wszystkich bitów mantysy zastosowań mikrokontrolerów nie ma kostek, w małych trzeba sobie radzić
równych jeden oraz domyślny bit z to praktycznie żadnego znaczenia. za pomocą liczb całkowitych.
wagą 20=1. Dużo istotniejszym praktycznym Jerzy Szczesiul, EP
Sprawdzmy jak to działa w prak- aspektem stosowania liczb rzeczy- jerzy.szczesiul@ep.com.pl
tyce. Zadeklarujmy w naszym pro- wistych jest zdawanie sobie sprawy,
Elektronika Praktyczna 5/2005
104


Wyszukiwarka

Podobne podstrony:
AVR GCC kompilator C dla mikrokontrolerów AVR, część 12
AVR GCC kompilator C dla mikrokontrolerów AVR, część 11
AVR GCC kompilator C dla mikrokontrolerów AVR, część 4
Płytka testowa dla mikrokontrolerów AT89S oraz AVR

więcej podobnych podstron