Vous êtes sur la page 1sur 41

Mikrokontrolery AVR, jzyk C, podstawy programowania

Niniejsza darmowa publikacja zawiera jedynie fragment penej wersji caej publikacji.

Aby przeczyta ten tytu w penej wersji kliknij tutaj.


Niniejsza publikacja moe by kopiowana, oraz dowolnie rozprowadzana tylko i wycznie w formie dostarczonej przez Wydawnictwo ATNEL. Zabronione s jakiekolwiek zmiany w zawartoci publikacji bez pisemnej zgody Wydawnictwa ATNEL - wydawcy niniejszej publikacji. Zabrania si jej odsprzeday.

Pena wersja niniejszej publikacji jest do nabycia w sklepie internetowym

http://witmir.pl

Stycze 2011

ATNEL
WYDAWNICTWO

Mikrokontrolery AVr
jzyk

podstAwy progrAMowAniA

Mirosaw Karda

Mojej onie Kasi

Ksika przeznaczona jest dla elektronikw i hobbystw, ktrzy chc szybko, w oparciu o interesujce przykady, pozna jzyk C przeznaczony dla mikrokontrolerw AVR i nauczy si pisa dla nich programy. Jest to jzyk wysokiego poziomu o nieograniczonych moliwociach, pozwala rwnie atwo i wygodnie dokonywa pocze z jzykiem maszynowym asembler. W sposb przystpny opisana zostaa take architektura oraz moliwoci samych mikrokontrolerw AVR wchodzcych w skad dwch rodzin: ATmega i ATtiny. Prezentowany materia podzielony jest na trzy czci. Pierwsza obejmuje zagadnienia zwizane z budow mikrokontrolerw, druga to wykad na temat podstaw samego jzyka, a trzecia zawiera szereg wicze wraz z kodami rdowymi, komentarzami i bogatymi opisami.

Opracowanie graficzne: Redakcja:

Mirosaw Karda Magorzata Koczaska

Copyright by Wydawnictwo Atnel Szczecin 2011


ISBN 978-83-931797-0-1

Wydawnictwo ATNEL ul. Jasna 15/38 70-777 Szczecin fax: 91 4635 683 http://www.atnel.pl e-mail: biuro@atnel.pl Wydanie I
Wszystkie znaki wystpujce w tekcie s zastrzeonymi znakami firmowymi bd towarowymi ich wacicieli. Autor oraz wydawnictwo Atnel dooyli wszelkich stara, by publikowane tu informacje byy kompletne i rzetelne. Nie bior jednak adnej odpowiedzialnoci ani za ich wykorzystanie, ani za zwizane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz wydawnictwo Atnel nie ponosz take adnej odpowiedzialnoci za ewentualne szkody wynike z wykorzystania informacji zawartych w ksice. Wszelkie prawa zastrzeone. Nieautoryzowane rozpowszechnianie caoci lub fragmentw niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii caoci lub fragmentw ksiki bd doczonej pyty DVD metod kserograficzn, fotograficzn, a take kopiowanie ksiki lub pyty DVD na nonikach filmowych, magnetycznych, elektronicznych lub na nieutoryzowanych stronach internetowych powoduje naruszenie praw autorskich niniejszej publikacji.

Przedmowa

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1 Wstp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2 Zaczynamy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.1 Pierwszy pusty program w C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.2 Od programu do procesora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.2.1 Kompilacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.2.2 rodowisko . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.2.3 Programator sprztowy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.2.4 Programowanie procesora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.2.5 Uruchamiamy AVR Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2.6 Platforma sprztowa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3 Procesory AVR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.1 Informacje oglne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 Programowanie ISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.3 Sposoby taktowania procesorw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.3.1 Wewntrzny oscylator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.3.2 Zewntrzny rezonator kwarcowy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.3.3 Zewntrzny oscylator RC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.3.4 Zewntrzny generator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.4 Zagadnienia zwizane z zasilaniem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.5 Ukad resetu mikrokontrolera AVR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.6 Wewntrzne moduy procesorw AVR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.6.1 Pami FLASH, RAM, EEPROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.6.2 Przerwania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.6.3 Timery sprztowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.6.3.1 Podstawowe tryby pracy Timerw . . . . . . . . . . . . . . . . . . . 42 3.6.3.1.1 Tryb zwykego LICZNIKA . . . . . . . . . . . . . . . . . . . . 42 3.6.3.1.2 Tryb CTC jeden z najwaniejszych . . . . . . . . . . 44 3.6.3.1.3 Tryb PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.6.4 Przetwornik ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.6.5 Modu komparatora analogowego . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.6.6 Modu UART/USART, (czyli RS232) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.6.7 Modu SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.6.8 Modu TWI, (czyli I2C) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.6.9 Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.6.10 Tryby oszczdzania energii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.6.11 FUSE BITS (ustawienia konfiguracji AVR) . . . . . . . . . . . . . . . . . . . . . . 54 3.6.12 LOCK BITS (zabezpieczenia AVR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

Spis treci

Strona | 3

Strona | 4
3.6.13 Bootloader niesamowite moliwoci . . . . . . . . . . . . . . . . . . . . . . . . 56 4 Podstawy jzyka C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.1 Zagadnienia oglne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.1.1 Komentarze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.1.2 Definicja a deklaracja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.1.3 Wyraenia logiczne (warunki) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4.2 Najwaniejsze instrukcje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4.2.1 Instrukcja warunkowa If , else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4.2.2 Ptla while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 4.2.3 Ptla do..while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.2.4 Ptla for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.2.5 Instrukcja break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.2.6 Instrukcja switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.2.7 Instrukcja continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 4.2.8 Nawiasy klamrowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4.2.9 Instrukcja goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4.3 Typy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.3.1 Systematyka typw jzyka C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4.3.1.1 Typy zoone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 4.3.1.2 Zakres widocznoci zmiennych . . . . . . . . . . . . . . . . . . . . . . 76 4.3.1.3 Typ void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 4.3.1.4 Specyfikator const . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 4.3.1.5 Specyfikator volatile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 4.3.1.6 Specyfikator register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.3.1.7 Instrukcja Typedef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.3.1.8 Typy wyliczeniowe enum . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 4.3.2 Stae w jzyku C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 4.3.2.1 Stae jako liczby cakowite . . . . . . . . . . . . . . . . . . . . . . . . . 85 4.3.2.2 Stae jako liczby zmiennoprzecinkowe . . . . . . . . . . . . . . . 86 4.3.2.3 Stae znakowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 4.3.2.4 Stae tekstowe, stringi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.4 Operatory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 4.4.1 Arytmetyczne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 4.4.1.1 Modulo, czyli % . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 4.4.1.2 Inkrementacja i dekrementacja ++ -- . . . . . . . . . . . . . . . . 91 4.4.1.3 Operator przypisania = . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 4.4.2 Operatory Logiczne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4.4.2.1 Operatory relacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4.4.2.2 Suma || oraz iloczyn && logiczny . . . . . . . . . . . . . . . . . . . . . 94 4.4.2.3 Negacja wykrzyknik ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 4.4.2.4 Operatory bitowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

Strona | 5
4.4.3 Pozostae operatory przypisania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 4.4.4 Operator pobierania adresu & . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 4.4.5 Wyraenie warunkowe ? : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 4.4.6 Operator sizeof() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 4.4.7 Priorytety operatorw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 4.4.8 Operatory rzutowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 4.5 Funkcje *** . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 4.5.1 Wynik dziaania funkcji jak to dziaa? . . . . . . . . . . . . . . . . . . . . . . 110 4.5.2 Stos ujarzmianie potwora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 4.5.3 Przekazywanie argumentw przez warto . . . . . . . . . . . . . . . . . . . 114 4.5.4 Funkcje typu inline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 4.5.5 Zakresy widocznoci nazw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.5.5.1 Zakres globalny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.5.5.2 Zakres lokalny i zmienne automatyczne . . . . . . . . . . . . . 123 4.5.5.3 Zmienne i funkcje statyczne . . . . . . . . . . . . . . . . . . . . . . . . . 124 4.5.6 Funkcje w rnych plikach projektu . . . . . . . . . . . . . . . . . . . . . . . . . . 126 4.6 Preprocesor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 4.6.1 Dyrektywa #define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 4.6.2 Makrodefinicje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.6.3 Dyrektywa #undef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 4.6.4 Operator ## - sklejanie nazw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.6.5 Operator zamiany na string # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.6.6 Dyrektywy kompilacji warunkowej . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.6.7 Dyrektywy #ifdef oraz #ifndef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 4.6.8 Dyrektywy #error i pozostae . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 4.6.9 Dyrektywa #include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 4.7 Tablice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 4.7.1 Tablice wielowymiarowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 4.7.2 Tablica jako argument funkcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 4.7.3 Tablice znakowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 4.8 Wskaniki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 4.9 Struktury, unie, pola bitowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 4.9.1 Struktury . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 4.9.2 Unie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 4.9.3 Poczenie struktury z uni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 4.9.4 Pola bitowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 5 Warsztaty zajcia praktyczne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 5.1 Przygotowanie procesora do pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 5.2 Migoczca dioda LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 5.3 Obsuga klawiszy typu micro-switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 5.4 Multipleksowanie LED - przerwania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

Strona | 6
5.5 5.6 5.7

7 8

Wywietlacz LCD (hd44780) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Sterowanie PWM (kolorowa dioda RGB) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Pomiar napicia za pomoc ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 5.7.1 Klawiatura analogowa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 5.7.2 Rnicowy pomiar napicia - amperomierz . . . . . . . . . . . . . . . . . . . . . 246 5.8 Komunikacja RS232 / RS485 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 5.8.1 Inicjalizacja, kalibracja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 5.8.2 UART, przerwania, bufor cykliczny . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 5.9 Odczyt-zapis magistrali I2C (RTC, EEPROM) . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 5.9.1 RTC sprztowa obsuga I2C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 5.9.2 Programowa implementacja I2C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 5.9.3 EEPROM I2C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 5.10 Modu SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 5.10.1 Sprztowa obsuga SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 5.10.2 Programowa obsuga SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 5.11 Magistrala 1Wire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 5.12 Odbir kodw RC5 w podczerwieni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 5.13 Sterowanie silnikami DC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 5.14 Silnik krokowy unipolarny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 5.15 Silnik krokowy bipolarny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 5.16 Odczyt/zapis kart pamici SD (FAT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 5.16.1 FatFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 5.16.2 PetitFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 FuseBity MkAvrCalculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 6.16.1 Fusebity, Lockbity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 6.16.2 MkAvrCalculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 Bootloader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 Projekty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 8.1 Pilot na podczerwie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 8.2 Modu Bluetooth (BTM-112/222) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 8.3 ciemniacz pynna regulacja mocy 230V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 8.4 Wstp do systemw czasu rzeczywistego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 8.5 Obsuga stosu AVR - TCP/IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 8.5.1 Karta sieciowa ethernet ENC28J60 . . . . . . . . . . . . . . . . . . . . . . . . . . 419 8.5.2 Serwer http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 8.5.3 Sterownik urzdze protok UDP . . . . . . . . . . . . . . . . . . . . . . . . . . 430 8.6 Programator USBASP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 rodowisko ECLIPSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455

Przedmowa

Strona | 7

Stale rosnce zainteresowanie jzykiem C, dla mikrokontrolerw serii AVR firmy ATMEL, powoduje due zapotrzebowanie na wszelkiego rodzaju kursy, poradniki, e-booki czy te ksiki. Z tymi ostatnimi jest niestety bardzo sabo. a to dlatego, e po prostu nie istniaa dotd adna pozycja, ktra dotyczyaby wanie jzyka C oraz rodziny AVR. Postanowiem napisa t ksik, by pomc wszystkim, chccym pozna od podstaw tajniki tego uniwersalnego jzyka programowania. Ma ona za zadanie,w moliwie najprostszy sposb wprowadzi do wiata C take te osoby, ktre do tej pory nie miay adnego kontaktu z programowaniem i stoj na rozdrou, prbujc zdecydowa si, jakiego jzyka zacz si uczy, aby efektywnie i szybko programowa mikrokontrolery. Dlaczego C? W zamierzchych czasach, gdy powstaway pierwsze mikroprocesory, rozwj oprogramowania by cile zwizany ze specyficznym jzykiem maszynowym kadego mikroprocesora. Powodowao to konieczno pisania programw dla cile okrelonych urzdze. Jzyki najniszego poziomu, asemblery bazuj na mnemonikach, ktre zastpuj prawdziwy jzyk numeryczny zrozumiay dla procesora. Jednak, aby nie trzeba byo pisa programw w postaci cigu cyfr w systemie szesnastkowym typu: 0x3A, 0x1B, 0x41, 0x05, co miaoby spowodowa zaadowanie np. liczby 22 do okrelonej komrki pamici RAM, mona posugiwa si mnemonikami takich rozkazw. Dziki czemu powyszy cig cyfr zastpi mona w asemblerze poleceniem o wieleprzyjaniejszym dla oka, np.: MOV BUFOR, 22. Kompilator asemblera przetumaczy sam tak mnemonik na cig cyfr zrozumiay dla konkretnego mikrokontrolera, ktre zostay przedstawione wyej. Reasumujc, asembler jest najnisz form kodu maszynowego, dajcego si zrozumie przez czowieka. Pisanie programw w czystym asemblerze jest jak najbardziej moliwe i jeli kto ma wieloletnie dowiadczenie, pozwala to na osiganie znacznej wydajnoci programu napisanego w ten sposb. Jak wspomniaem, aby efektywnie i dobrze pisa programy w jzyku najniszego poziomu, trzeba powici wiele lat na nauk, a pomimo to nadal pisanie wikszych programw staje si bardzo uciliwe, dugotrwae oraz wymaga czasu na przetestowanie i sprawdzenie wszelkiego rodzaju bdw. Na dodatek program napisany w specyficznym kodzie maszynowym jednego procesora bdzie bardzo trudny do przeniesienia na inny typ. Czasem bdzie to w ogle niemoliwe i spowoduje konieczno napisania programu od pocztku. W zwizku z powyszym ogromny wkad pracy w napisanie programu zostaje niejednokrotnie zniweczony, gdy przychodzi zmiana zaoe i konieczno zastosowania w urzdzeniu innego typu mikroprocesora, a czasu na modyfikacj i sprawdzenie dziaania jest niewiele. W takim momencie bardzo pomocny okazuje si jzyk C. Jest to jzyk oglnego przeznaczenia, ktry moe pracowa na kadym mikrokontrolerze, dla ktrego stworzony jest kompilator C. W dzisiejszych czasach praktycznie nie ma procesorw, ktrych nie mona byoby programowa w C, za to zdarzaj si ju takie przypadki, gdzie producent wrcz nie dostarcza asemblera do swoich produktw, w zamian dajc tylko kompilator C. Dziki C mona: szybko i atwo porusza si midzy rnymi rodzinami mikrokontrolerw, o wiele szybciej, efektywniej i wydajniej pisa i testowa programy, a take tworzy kod, ktry jest o wiele atwiejszy do nauki, zrozumienia i zapamitania.

Strona | 8

1 Wstp
Odkd poznaem jzyk C, byem oczarowany jego moliwociami, prostot i logik programowania. Obecnie zauwaam specyficzne podejcie wielu osb, ktre po pierwszych prbach samodzielnej nauki C szybko si zniechcaj z powodu rzekomej duej trudnoci i zawioci zasad tego jzyka. Tymczasem prawdziwym powodem jest nierzadko brak literatury opisujcej zasady jzyka C w oparciu o praktyczne przykady, dziki ktrym mona z marszu rozwizywa du cz swoich pocztkowo przyziemnych problemw. Rzadko, kiedy ksika na temat jzyka C, a szczeglnie w aspekcie programowania mikrokontrolerw AVR, jest pisana dla osb, ktre nie maj jeszcze adnego dowiadczenia z programowaniem w ogle. Sporo dowiadcze do napisania tej ksiki zebraem podczas prowadzenia kursw jzyka AVR GCC dla procesorw AVR. Zatem jednym z celw, do ktrych d w tej ksice, jest prba przyblienia i zainteresowania tym niezwykle przyjemnym i atwym jzykiem osb, ktre wanie stoj na rozdrou i musz podj ciki wybr. W ktr stron pj, aby w efektywny i atwy sposb programowa ca rodzin mikrokontrolerw AVR Jzyk C czsto traktowany jest jako narzdzie dla specjalistw a nie amatorw, hobbystw itp. Postaram si, wic przeama te mity i udowodni, e kady po przeczytaniu tej ksiki bdzie potrafi napisa samodzielnie przynajmniej proste programy ze zrozumieniem podstawowych zasad tego jzyka. Poniewa jednak jzyka C ciko uczy si od strony praktycznej w oderwaniu od sprztu, czyli w naszym konkretnym przypadku od mikrokontrolerw serii, AVR, dlatego konieczne bdzie take przyblienie zasad dziaania procesorw tej rodziny. Wikszo przykadw bdzie odwoywaa si do mikrokontrolerw serii ATmega, ale postaram si pokaza, e dziki temu, i korzysta bdziemy z C to zaprogramowanie mikrokontrolerw z serii ATtiny nie bdzie si praktycznie niczym rnio. Jedyne rnice, jakie wystpi w tym przypadku, to pewne ograniczenia wynikajce z moliwoci sprztowych. Dziki powyszym zaoeniom ksika ta skierowana jest do bardzo szerokiego grona czytelnikw, ktrzy usilnie poszukuj wszelkich informacji na te tematy. Bd stara si uywa prostego, czasem potocznego jzyka, aby przybliy bardziej skomplikowane zagadnienia. Na pierwszy rzut oka struktura ksiki moe wyda si nieco chaotyczna, gdy nie opisuj w niej po kolei caych zagadnie w oderwaniu od siebie. Nie znajdzie si tu pierwszej czci, w ktrej bdzie w kilku kolejnych rozdziaach opisana rodzina mikrokontrolerw AVR. Nie znajdzie si kolejnej, gdzie bdzie opisany czysty jzyk C i nie znajdzie nastpnych rozdziaw osobno traktujcych o rodowiskach programistycznych, o programatorach czy o sposobach wgrywania programw fizycznie do mikrokontrolera. Przyjem zaoenie, i ksika bdzie napisana w postaci kursu, jaki zwykle serwuj uczestnikom na zajciach, gdzie wykady z teorii przeplatane s z praktyk, czyli tzw. warsztatami, na ktrych pod okiem instruktora kady moe uczy si, pisa czy testowa wasne programy. Pozwolio mi to na pynne przechodzenie z tematu na temat tak, aby w jak najprostszy sposb wprowadzi czytelnika do wiata mikrokontrolerw AVR oraz ich programowania. Moe wic nie w osobnych dziaach, ale w pewnej logicznej kolejnoci bd stara si podawa informacje tak, aby jak najszybciej mona byo je przyswaja. W sposb, ktry sprawdzi si w praktyce. Potraktuj t ksik jak dobrego przewodnika w trakcie przeprawy przez dungl, jak mog si wydawa zakresy szczegowej wiedzy z wielu dziedzin elektroniki cyfrowej i programowania.

Strona | 58

4 Podstawy jzyka C 4.1 Zagadnienia oglne


Wreszcie dotarlimy do miejsca, gdzie bdzie mona pozna wicej informacji na temat samego jzyka C. Podobnie jak w przypadku omawiania podstawowych zagadnie dotyczcych caej rodziny mikrokontrolerw, teraz bd musia omwi skadni jzyka.

W jzyku C stosujemy tzw. wolny format jeli chodzi o pisanie kodu. Nie obowizuj tu reguy jak w innych jzykach, gdzie trzeba si ogranicza do pisania rozkazw w jednej linii. Nie ma tu adnych przymusw. Wszystko, co chcemy zapisa, moe si znale w kadym miejscu linii, a nawet mona to samo rozpisa na kilka linijek. Zwizane jest to z tym, e koniec instrukcji, jak wydajemy, jest okrelony przez rednik, ktry stawiamy na kocu, a nie przez to, e koczy si linia programu. Wewntrz instrukcji moe znajdowa si dowolna ilo tzw. biaych znakw, do ktrych zaliczamy spacje czy tabulatory. S one ignorowane przez kompilator. Z tego wzgldu nie ma rnicy w tym, jak zapiszemy ponisz lini - moemy to zrobi tak:
int main(void) {return 0;}

lub tak:
int main(void) {

// od tego miejsca zaczyna si start programu. /* komentarze */

return

// koniec programu

4.1.1 Komentarze
Biae znaki s ignorowane przez kompilator, su one jedynie programicie. Syszae zapewne przy okazji pisania kodw programu o tzw. wciciach. Dobrze napisany kod jest wtedy, gdy ma stosowane wcicia. Bez nich kod staje si mao czytelny i bardzo ciko wrci do jego analizy po duszym czasie. Zauwaye powyej w jednym z przykadw dwie charakterystyczne linie, w ktrych wida tzw. komentarze. To opisy, ktre mona wstawi do kodu w celu zwikszenia czytelnoci programowanych zagadnie. Jeli w dowolnym miejscu linii kompilator napotka dwa znaki // nastpujce po sobie, to ignoruje wszystkie kolejne a do koca tej linii. Inna forma do oznaczania caego bloku linii, w ktrych chcemy umieci opisy, moe by zawarta pomidzy dwoma znacznikami, gdzie jeden rozpoczyna blok /* natomiast drugi */ koczy taki blok. Zapamitaj, e komentarze w jzyku C s bardzo istotnym elementem. Program napisany bez adnych komentarzy czy krtkich chocia objanie, nie jest napisany w dobrym stylu programistycznym. Stosuj komentarze zawsze, gdy przygotowujesz skomplikowane procedury, funkcje czy obliczenia tak, aby stanowio to uatwienie dla ciebie, gdy po duszym czasie wrcisz do analizy kodu. Komentarze take s istotne dla innych osb, ktre bd miay moliwo zapoznania si z kodem rdowym twojego programu.

Strona | 59

4.1.2 Definicja a DeKlaracja


Zapamitaj rnice pomidzy deklaracj a definicj, ebymy pniej dobrze si rozumieli. Brak zrozumienia tego zagadnienia na samym pocztku prowadzi do wielu nieporozumie, bywa take powodem rzekomych trudnoci w nauce jzyka C.
1. 2. Deklaracja okrela pewne wasnoci identyfikatora (zmiennej czy funkcji), jednak nie rezerwuje pamici. Definicja zajmuje pami dla nowego obiektu i jednoczenie go deklaruje.

Wynika z powyszego, e definicja jest rwnoczenie deklaracj, ale nigdy na odwrt.


Przykady Deklaracji: extern int a1; extern uint8_t tab[]; int max(int a, int b); 1. 2. 3. Informuje kompilator, e identyfikator a1 oznacza zmienn typu int. Jednoczenie swko extern oznacza, e zmienna ta jest tworzona poza aktualnym plikiem rdowym. Informuje kompilator, e identyfikator tab jest tablic elementw jedno-bajtowych bez znaku. Informuje kompilator, e identyfikator max jest funkcj zwracajc warto typu int, oraz przyjmujc dwa argumenty typu int.

Przykady Definicji: int b1; int c2 = 5; uint16_t tab[20]; int max(int a, int b) { return (a>b) ? a : b; } 1. 2. 3. 4. Tworzy zmienn b1, zajmuje dla niej pami (w jzyku AVR GCC) bd to dwa bajty, oraz informuje kompilator, e identyfikator b1 oznacza zmienn typu int. Tworzy zmienn c2, zajmuje dla niej pami, zostaje ona zainicjalizowana wartoci 5, oraz informuje kompilator, e c2 oznacza zmienn typu int. Tworzy tablic tab, zajmuje dla niej pami 40 bajtw oraz informuje kompilator, e identyfikator tab jest tablic dwubajtowych elementw bez znaku. Tworzy funkcj max, zajmuje dla niej pami lecz tym razem w obszarze pamici programu FLASH, umieszcza w niej program funkcji, oraz informuje kompilator, e funkcja max jest funkcj zwracajc warto typu int a take o tym, e przyjmuje ona dwa argumenty take o typie int.

Nazwy zmiennych i funkcji mona tworzy dowolnie, ale z pewnymi ograniczeniami: nie mog one by nazwami sw kluczowych uywanych przez kompilator oraz nie mog zaczyna si od cyfry. Nazwy mog by pisane zarwno wielkimi jak i maymi literami, jednak trzeba o tym pamita, poniewa jeli zdefiniujemy zmienn o nazwie Rozmiar (zaczyna si du liter), to pniej w kodzie kompilator nie rozpozna tej nazwy, jeli napiszesz j tak: rozmiar.

Strona | 60

4.1.3 Wyraenia logiczne (Warunki)


W jzyku C wystpuje wiele instrukcji sterujcych programem (poznasz je w kolejnym rozdziale), ktre podejmuj decyzje o wykonaniu lub niewykonaniu pewnych zada w zalenoci od spenienia lub niespenienia jakiego warunku. Dokadniej mwic w zalenoci od tego, czy jakie wyraenie jest prawdziwe, czy faszywe. Najpierw jednak musisz si dowiedzie, co to jest prawda i fasz w jzyku C. Poniej kilka przykadw wyrae logicznych:
1. ( x < 50 ) 2. ( x == a ) 3. ( x != a )

Nie znajc wartoci zmiennych x lub a nie jestemy w stanie oceni czy te wyraenia s prawdziwe czy faszywe. Jeeli jednak powiem, tobie teraz, e x=7 natomiast a=10, to jeste w stanie szybko stwierdzi, e: 1. 2. 3. Wyraenie jest prawdziwe poniewa 7 jest mniejsze od 50 Wyraenie jest faszywe poniewa 7 nie rwna si 10 Wyraenie jest prawdziwe poniewa 7 jest rne od 10

Zaraz, zaraz ale skd bdzie o tym wiedzia mikrokontroler. Okazuje si, e to nie bdzie dla niego adnym problemem. Jeli mikrokontroler napotka np. taki warunek ( x < 50 ), to najpierw podobnie jak my dokona obliczenia i na tej podstawie sprawdzi, czy jest on prawdziwy, czy faszywy. Zmienna x przecie musiaa by gdzie wczeniej zdefiniowana w programie, std bdzie znana jej warto w momencie, gdy dojdzie do sprawdzania warunku. ZAPAMITAJ! Warto zero jest zawsze rozumiana, jako stan: fasz Warto inna ni zero jest zawsze rozumiana, jako stan: prawda Dziki temu w wyniku operacji a=(5<10) kompilator przydzieli zmiennej a warto jeden, natomiast w wyniku operacji a=(25<10) zmienna a przyjmie warto zero. Dziki powyszemu, zamiast w instrukcji sterujcej wpisywa warunek sprawdzajcy czy np. warto x jest wiksza od zera w tradycyjny sposb: (x>0), mona zapisa to samo w prostszy (x). Poniewa zgodnie z powyszymi definicjami prawdy i faszu w jzyku C, warunek (x) bdzie speniony (prawdziwy) tylko wtedy, gdy x bdzie wiksze od zera. Przy zaoeniu oczywicie, e korzystamy z typu liczby cakowitej bez znaku. W zwizku z tym warunek zapisany z kolei w ten sposb (1) bdzie zawsze prawdziwy (speniony).

4.2 Najwaniejsze instrukcje


4.2.1 instrukcja WarunkoWa if , else

Zaczniemy od kluczowych instrukcji, bez ktrych nie mona byoby napisa adnego programu.

W jzyku C instrukcja if (co oznacza po polsku jeli) moe wystpowa w dwch postaciach:
if(warunek) instrukcja if(warunek) instrukcja1 else instrukcja2

S to podstawowe instrukcje jzyka C. Pierwsza posta oznacza, e jeli bdzie speniony

Strona | 61
warunek, ktry moe by dowolnym wyraeniem, tylko wtedy zostanie wykonana instrukcja wystpujca w dalszej czci. Druga posta stosowana jest do tzw. rozgazie programu. Oznacza, e jeli bdzie speniony warunek to zostanie wykonana instrukcja1, a jeli warunek nie bdzie speniony, to zostanie wykonana instrukcja2. Symbolicznie oznaczona instrukcja moe stanowi zarwno jedn instrukcj programu, co mona zapisa w kodzie tak:
if(x<50) wysokosc=0; else wysokosc=1;

ale moe take oznacza kilka instrukcji, tyle e wtedy musimy je zebra pomidzy nawiasami klamrowymi {}
if(x<50) { wysokosc=0; y=0; } else { wysokosc=100; y=20; z=33; }

W pierwszej prostszej postaci w zalenoci od warunku (x<50) bya przydzielana rna warto do zmiennej o nazwie wysokosc. W drugiej postaci w zalenoci od spenionego warunku lub nie, ustawilmy pewne wartoci kilku rnym zmiennym, dlatego zastosowalimy nawiasy klamrowe ograniczajce odpowiednio pierwsz i drug (po else) sekcj warunku. Naley wspomnie take, i instrukcje if mog by zagniedone. Spjrzmy na kod poniej. Wida na nim dwie instrukcje warunkowe zagniedone, a dokadniej mwic, zagniedona jest instrukcja if(warunek_2). Zostaa ona tutaj specjalnie wyrniona szarym kolorem ramki. Kolejnym wyrnikiem, jaki wystpuje w kodzie programu, s wcicia tabulatorw. Widzimy, e cay zagniedony warunek jest przesunity w prawo. Bez takich wci analiza kodu programu byaby prawie niemoliwa, a przynajmniej bardzo, ale to bardzo utrudniona.
if(warunek_1) { if(warunek_2) { //instrukcje } } else { }
// instrukcje

Wiemy jednak, e nawiasy klamrowe nie zawsze musz wystpowa, moe doj w takich sytuacjach do sporych problemw szczeglnie, jeli nie zastosujemy w odpowiedni sposb wci w programie.

Strona | 62
if(warunek_1) if(warunek_2) instrukcja1; else { instrukcja2; }

Jak przeanalizowa taki kod? Do ktrego warunku odnosi si instrukcja else? Dla kompilatora jest to jasne jak soce, poniewa wystpuje zasada, e jeli brak nawiasw klamrowych przed instrukcj else, to odnosi si ona zawsze do najbliszej poprzedzajcej j instrukcji if. Zobaczmy jednak, jak naley to zapisa tak, abymy take my mogli to spokojnie i bez bdw analizowa. Znowu wane s wcicia.
if(warunek_1) if(warunek_2) instrukcja1; else { instrukcja2; }

Myl, e teraz take dla ciebie na pocztku drogi w C bdzie to bardzo przejrzysty zapis. Nie martw si, jeli do tej pory miae problemy ze zrozumieniem rnego rodzajw kodw programw napisanych w C przez inne osoby. Nie znae jeszcze zasad, jakie rzdz skadni, a na dodatek moge natkn si na programy pisane bez wci przez niedowiadczone osoby lub takie, ktre ju co potrafi, ale uwaaj, e wcicia nie s im potrzebne. Jednak takie podejcie, uwierz mi, zawsze prdzej czy pniej skoczy si le. Bywaj pewne formy, gdzie musi nastpi wybr wielowariantowy za pomoc wielu instrukcji if else. W takich sytuacjach mona pomin tabulatory (wcicia), o ile bdzie to np. taki prosty blok:
if(warunek_1) instrukcja1; else if(warunek_2) instrukcja2; else if(warunek_3) instrukcja3; else if(warunek_4) instrukcja4; kolejne_instrukcje;

Taki blok analizujemy nastpujco: jeli speniony jest warunek_1, wykonaj instrukcj1, zakocz dziaanie bloku i przejd do kolejnych instrukcji programu. Jeli jednak warunek_1 nie jest speniony, to sprawd warunek_2, jeli jest speniony, to zakocz dziaanie bloku i przejd do kolejnych instrukcji programu. Jeli warunek_2 nie jest speniony, to sprawd warunek_3 i tak dalej. Tego typu bloki konstrukcji wielopoziomowego wyboru od razu mog skojarzy si z pomysem zastosowania tego mechanizmu do oprogramowania wielopoziomowego MENU dla uytkownika. Rzeczywicie, przy prostej budowie menu mona z tego korzysta. Jednak niedugo poznamy specjaln instrukcj, ktra jeszcze wygodniej pozwala nam organizowa wielopoziomowe wybory w kodzie programu.

Strona | 63
Dodam jeszcze, e instrukcje warunkowe if mog sprawdza warunki zoone, tzn. skadajce si z wielu warunkw bd oblicze. Przyjrzymy si temu bliej ,gdy bdziemy omawia operatory. Wtedy lepiej zrozumiesz zapis typu:
if ( (x>50 && x<100) || (x==5) ) instrukcja1;

Na razie powiem tylko, e instrukcja1 zostanie tylko wtedy wykonana, jeli zmienna x zawiera si w przedziale od 51 do 99 lub jest rwna 5. Znaki && oraz || to wanie operatory.

4.2.2 Ptla While


Konstrukcja while (po polsku dopki) suy do realizacji jednej z podstawowych ptli programowych. Wystpuje ona w formie:
while(warunek) instrukcja(-e);

Oznacza to, e dopki warunek bdzie speniony (prawda), dopty bdzie wykonywana instrukcja. Zgodnie ze skadni jzyka, o ktrej pisalimy wyej, pojedyncz instrukcj mona zastpi dowolnym blokiem wielu instrukcji tyle, e trzeba je umieci wewntrz nawiasw klamrowych {}. Mona wic w ramach jednej ptli zapisa wiele instrukcji w ten sposb:
x=0; while(x<10) {
// // // //

instrukcja1 instrukcja2 instrukcja3 .

// instrukcjaN

x=x+1;

// kolejne instrukcje programu

Zawarto ptli bdzie wykonana dziesiciokrotnie. Zauwa, e przed rozpoczciem ptli przypisalimy zmiennej x warto zero. Zatem warunek (x<10) jest speniony i zostan wykonane kolejno instrukcje wewntrz nawiasw klamrowych. Ostatnia instrukcja spowoduje zwikszenie wartoci x o jeden, po czym znowu nastpi sprawdzenie warunku. Jako e x rwny bdzie 1, to i tym razem warunek zostanie speniony. Blok instrukcji bdzie dotd wykonywany, dopki zmienna x w wyniku zwikszania zawartoci o jeden nie osignie w kocu wartoci rwnej dziesi. W takiej sytuacji warunek (x<10) nie bdzie ju prawdziwy/ speniony i ptla nie wykona instrukcji zawartych w nawiasach klamrowych. Rozpocznie si wykonywanie kolejnych instrukcji programu. Bardzo czsto stosuje si w programach tzw. ptl nieskoczon. Chodzi o to, aby wykonywa pewien blok instrukcji bez koca. Mona wtedy posuy si konstrukcj:
while(1) { }

// instrukcje

Strona | 64
Zgodnie z tym co mwilimy o prawdzie i faszu w jzyku C, warto wiksza od zera bdzie zawsze oznacza prawd. Zatem warunek (1) bdzie zawsze speniony, poniewa liczba 1 jest wiksza od zera i symbolizuje w tym warunku prawd. Zauwa, prosz, istot dziaania tej ptli. Ot, zawsze przed jej pierwszym wykonaniem sprawdzany jest warunek. Gdyby nie by on speniony (prawdziwy), to nigdy nie doszoby do wykonania instrukcji w jej wntrzu.

4.2.3 Ptla do..While

Konstrukcja do while oznacza z angielskiego Rb Dopki i pozwala na realizacj innego rodzaju ptli programowej. Jej forma to: do instrukcja1 while(warunek);

Po analizie oznacza to, rb (wykonuj) instrukcj1, dopki bdzie speniony warunek. Jak zwykle te pojedyncz instrukcj moemy zastpi blokiem wielu instrukcji umieszczonych wewntrz nawiasw klamrowych.
do {

Instrukcja1; Instrukcja2; Instrukcja3; } while(warunek); Zauwa, e w odrnieniu od omawianej wyej zwykej ptli while, tutaj mamy do czynienia z sytuacj, w ktrej najpierw wykonywana jest instrukcja1 lub blok instrukcji, a dopiero na kocu sprawdzany warunek. Zatem w pierwszym przebiegu tej ptli zostan zawsze wykonane instrukcje w jej wntrzu.

4.2.4 Ptla for

Ten typ ptli programowej wykonywany jest zdecydowanie najczciej w rnych programach. Posiada ona posta: for( init ; wyraenie_warunkowe ; krok) tre_ptli;

init oznacza instrukcj bd grup instrukcji, ktre su do inicjalizacji pracy ptli. W praktyce najczciej bdziesz stosowa tu pojedyncz instrukcj. wyraenie_warunkowe tak jak to zwykle bywao w instrukcjach warunkowych, bdzie obliczane przed kadym wykonaniem pojedynczego obiegu ptli. Jeli wyraenie/warunek bdzie speniony, to przebieg ptli zostanie wykonany, jeli przestanie by prawdziwy, to przebieg nie zostanie wykonany. krok to instrukcja wpywajca na licznik wykonywania ptli. Jest ona realizowana za kadym razem na zakoczenie pojedynczego obiegu ptli tu przed ponownym sprawdzeniem wyraenia warunkowego na pocztku ptli. W praktyce bdzie to wygldao tak:
for(i=0;i<10;i=i+1) { instrukcja1; }

Strona | 65
W powyszym przykadzie sekcj init stanowi instrukcja i=0. Inicjalizujemy w ten sposb zmienn i, ktra bdzie odpowiedzialna za iteracj (wielokrotnie powtarzaln czynno). Sekcja wyraenie_warunkowe to w naszym przypadku warunek i<10. Zatem ptla bdzie si wykonywaa do momentu, dokd warunek bdzie prawdziwy. Jako e zmienna i zostaa zainicjalizowana wartoci zero, mona powiedzie, e pierwszy przebieg ptli zostanie na pewno wykonany, gdy warunek taki bdzie prawdziwy. Dziki sekcji krok, ktra u nas ma posta i=i+1 wiemy, e za kadym przebiegiem ptli, pod koniec wykonywania kadego jej obiegu zmienna i bdzie zwikszana o jeden. Co za tym idzie, mona miao wywnioskowa, e ptla taka wykona si 10 razy. Ile razy wykonana zostaaby ptla for zapisana w poniszy sposb?
for(i=0;i<10;i=i+2) instrukcja1;

Tylko pi razy, poniewa warto zmiennej i w sekcji krok, jest zmieniana w wikszym tempie. Tym razem i=i+2. Zatem wyraenie_warunek bdzie spenione tylko wtedy, gdy wartoci zmiennej i bd wynosiy kolejno: 0, 2, 4, 6, 8. Mam nadziej, e ten krtki opis da tobie duo do mylenia i jeli przypadkiem znasz ptle for z innych jzykw programowania, to miao stwierdzisz, e skadnia tej ptli w jzyku C jest zdecydowanie najlepsza. Daje ogrom moliwoci i nie wprowadza wielu ogranicze. Dodatkow ciekawostk jest to, e w jzyku C mona miao pomija niektre bd wszystkie czci skadowe ptli, pozostawiajc jedynie znaki rednikw, ktre je oddzielaj. Zatem poniszy zapis:
for(;;) { }

// instrukcje;

Czsto spotkasz, jako ptl nieskoczon. Opuszczenie sekcji wyraenie_warunek jest zawsze rwnoznaczne w tym przypadku z tym, jakby warunek by zawsze speniony. Mona take skorzysta z zapisu:
for(i=5;x>20;) instrukcja;

W takim przypadku mamy do czynienia z inicjalizacj zmiennej i w ptli, nastpnie zostaje sprawdzany warunek (x>20), ktry wcale nie musi by zwizany ze zmienn typu iteracyjnego, czyli i. Natomiast pominlimy w ogle sekcj krok. Oznacza to, e ptla bdzie pracowa w zalenoci od tego, co wewntrz niej bdzie si dziao z wartoci zmiennej x. Jak wspominaem wczeniej, sekcja inicjalizacji bd sekcja krok mog skada si z kilku instrukcji oddzielonych od siebie przecinkiem. Nie naduywaj jednak takich konstrukcji ze wzgldu na moliwo znacznego zmniejszenia czytelnoci kodu programu. Przykad:
for(i=0,k=10;i<10;i=i_1,k=k-1) { // instrukcje ptli }

Strona | 66
W tym przypadku dostrzeesz, i zmienna i suy do iteracji, natomiast niejako dodatkowo mona wykorzysta sekcje ptli do cyklicznych dziaa z innymi zmiennymi, ktre mog by przydatne wewntrz ptli. Kada ptla moe take zosta przerwana w dowolnym momencie za pomoc specjalnej instrukcji, o ktrej powiem za chwil.

4.2.5 instrukcja break


Instrukcja break z angielskiego oznacza w tym przypadku przerwa. Moe zosta ona uyta wewntrz dowolnej ptli programowej lub wewntrz instrukcji switch. Powoduje ona natychmiastowe i bezwarunkowe przerwanie dziaania ptli bd instrukcji switch oraz jej opuszczenie. W zwizku z czym program rozpoczyna wykonywanie kolejnych instrukcji programu, jakie znajduj si po wystpieniu ptli lub instrukcji switch. Oznacza to, e mona przerwa dziaanie kadej formy tzw. ptli nieskoczonej. Wystarczy w jej wntrzu wstawi polecenie break. Oczywicie takie polecenie najczciej w tego typu przypadkach zostaje uyte w zalenoci od zaistnienia pewnej sytuacji, czyli jednym sowem w zalenoci od spenienia jakiego warunku/wyraenia, np.
while(1) { // instrukcje if(warunek) break; // instrukcje }

Poznalimy ju wczeniej tak konstrukcj ptli nieskoczonej z uyciem ptli while, jednak rwnie dobrze moglibymy zastosowa konstrukcj for(;;) zamiast while(1). Tak czy inaczej wewntrz za kadym obiegiem sprawdzany jest jaki warunek, i jeli zostanie on speniony, wykonywanie obiegu ptli zostanie natychmiast przerwane. Nie wykona si w jej wntrzu ju adna nastpna instrukcja.

4.2.6 instrukcja sWitch


Switch z angielskiego oznacza przecznik. Tak te zachowuje si ta instrukcja. Suy ona do podejmowania wielowariantowych decyzji. To wanie za jej pomoc mona zastpi blok wielowariantowego wyboru, o jakim mwiem w rozdziale powiconym instrukcjom if else. Oto jak wyglda posta takiej instrukcji. Jest to pewna konstrukcja, spjrz poniej:
switch(wyraenie) { case wartosc1: instrukcje; [break;] case wartosc2: instrukcje; [break;] case wartosc3: instrukcje; [break;] default: instrukcje; }

Strona | 67
Wyglda to moe troszk skomplikowanie na pierwszy rzut oka, ale to tylko zudzenie, zapewniam ci. Ju wyjaniam, co to wszystko po kolei oznacza. To potne narzdzie w jzyku C. Instrukcja rozpoczyna si od sprawdzenia naszego przecznika, ktrym jest wyraenie. Oznacza to, e w nawiasach okrgych moe wystpi sama zmienna np. x, ale rwnie dobrze moe wystpi wyraenie matematyczne, ktrego wynik bdzie przecznikiem. Nastpnie wewntrz nawiasw klamrowych mamy sekcje o nazwie case lub default, dziki ktrym moemy zdecydowa, jakie instrukcje chcemy wykona w zalenoci od konkretnych wartoci naszego wyraenia/przecznika. Po swku case zawsze podajemy warto przecznika, jaka nas interesuje, co oznacza, e jeli przecznik bdzie mia w momencie wejcia w instrukcj switch tak warto, to instrukcje wystpujce w kolejnych liniach po swku case zostan wykonane, jeli inn warto, to pominite i zostanie rozpatrzona kolejna pozycja case. Po kadym pakiecie instrukcji nastpujcych po sprawdzeniu okrelonej wartoci przecznika case, moe wystpi instrukcja break. Tylko dlatego ujem j w powyszym schematycznym w przykadzie w nawiasy kwadratowe, aby zakomunikowa, e instrukcja break moe w tym miejscu wystpowa, ale nie musi. Nie jest to obligatoryjne. Jednak, jeli jej nie ma, to zostan wykonane kolejne instrukcje zawarte instrukcji nastpnych sekcji case, switch. Moe to spowodowa, e cao nie zareaguje tylko na jeden przecznik, a na kilka. Zatem jeli zaley nam na wykonaniu instrukcji dotyczcych tylko jednego przecznika, to najczciej bdziemy blok rozpoczynajcy si od swka case koczyli rozkazem break, ktry przerwie dalsze wykonywanie instrukcji zawartych w switch, poniewa uznajemy, i inne s niepotrzebne w tym momencie. W praktyce moe to wyglda tak:
x=2; switch(x) { case 0: czas=10; break; case 1: czas=23; break; case 2: czas=38; break; case 3: czas=42; break; default: czas=0;

Krciutko przeanalizujemy, co stanie si w wyniku dziaania powyszego kodu programu. Na pocztku bd rcznie, bd w wyniku wykonania jakiej funkcji, zmienna x przyjmuje warto rwn dwa. Rozpoczyna si teraz instrukcja switch sprawdzajca warto zmiennej x, penicej dla nas rol przecznika, od ktrego chcemy spowodowa, aby z kolei zmienna czas przyja pewn konkretn warto. Zakadamy take, e jeli zmienna x nie osignie

Strona | 68
adnej z zaoonych wartoci, to zmienna czas domylnie zostanie wyzerowana. Po wejciu w instrukcj switch za pomoc pierwszego swka case, sprawdzamy, czy nasz przecznik, jakim jest warto zmiennej x, nie posiada wartoci zero. Jeli nie, to zignorowane zostan kolejne linijki programu a do napotkania kolejnego momentu, w ktrym pojawi si swko case. Oznacza to bdzie, e po raz kolejny sprawdzamy, czy nasz przecznik nie posiada wartoci rwnej jeden. Jeli nie, to program przeskakuje do kolejnego swka case, ktre tym razem sprawdza, czy x rwna si dwa? Zgadza si, jak wida przed instrukcj switch, zmienna x jest rwna dwa. W takim razie, rozpoczn si wykonywa kolejne instrukcje, ktre znajduj si po tym wanie sprawdzeniu swkiem case. W naszym przypadku jest to tylko jedna instrukcja, ale mona rwnie dobrze w kolejnych liniach napisa ich wicej. Tutaj mona, ale nie trzeba, koniecznie stosowa do bloku instrukcji, nawiasw klamrowych. Zauwa jednak, e na zakoczenie tych instrukcji zostaje wykonana instrukcja break. Powoduje ona zakoczenie dziaania caoci. O to nam chodzio. Aby w zalenoci od konkretnej wartoci zmiennej x odpowiednio ustawi zmienn czas.

Dodajmy na koniec, e gdyby warto zmiennej x bya rna od 0, 1, 2, 3 (bo takie wartoci zostaj sprawdzane za pomoc swek case), to zrealizowana zostaaby sekcja instrukcji na kocu po swku default. W naszym przypadku zmienna czas zostaaby wyzerowana. Jeli taka sekcja case lub default wystpuje na samym kocu, to zbdne jest ju uycie instrukcji break.

4.2.7 instrukcja continue


Instrukcja ta bywa przydatna wewntrz kadej z omawianych ptli programowych. Moe czasem wystpi sytuacja, gdy ptla zawiera dugi blok instrukcji programu wystpujcych jedna po drugiej, e w zalenoci od jakiego czynnika chcemy pomin wykonywanie czci bloku tyche instrukcji. Jej posta przedstawia si nastpujco:
for(;;) { instrukcja1; instrukcja2; instrukcja3; if(warunek) continue; instrukcja4; instrukcja5;

Oczywicie rodzaj ptli moe by dowolny, rwnie dobrze w tym przykadzie moglibymy zastosowa while() czy te dowhile(). Jak to dziaa? Ot zakadajc, e jeli warunek nie jest speniony, to dokadnie w kadym obiegu ptli wykonywane s wszystkie instrukcje od 1 do 5. Jeli jednak w konkretnym czy te w wielu przebiegach warunek zacznie by speniony/prawdziwy, to instrukcje od 4 do 5 s cakowicie pomijane. Mona powiedzie, e instrukcja continue powoduje przejcie na sam koniec ptli. Efekt bdzie taki, jakby cao zostaa wykonana, nastpuje zakoczenie obiegu, po czym zostaje sterowanie przekazane znowu na pocztek ptli, gdzie sprawdzane s jej warunki pracy.

Strona | 69

4.2.8 nawiasy Klamrowe


Kilka praktycznych porad jak ich uywa aby unikn pomyek, o ktre szczeglnie atwo, jeli stosowa bdziemy wiele zagniedonych instrukcji if, a w nich jeszcze rozbudowanych ptli, ktre na dodatek take mog zawiera kolejne instrukcje if. Poniej przedstawi czsto spotykane trzy sposoby uywania nawiasw klamrowych w programach.
while(1) { instrukcje; } while(1) { }

I sposb

instrukcje;

II sposb

while(1) { Instrukcje; }

III sposb

Kady sposb jest generalnie prawidowy, gdy zawiera odpowiednie wcicia. Jednak warto zdecydowa si na jeden z nich taki, ktry tobie bdzie sprawia najmniej problemw. Dla mnie najlepszym sposobem, jakiego najczciej korzystam, gdy pisz wasne kody, jest ten trzeci. Powiem wicej, eby unikn pomyek zwizanych z pisaniem dugiego kodu programu i zagniedonych instrukcji, po ktrych stosuj klamry, zawsze podchodz do tego wanie tak. Po napisaniu instrukcji warunkowej czy ptli wciskam klawisz ENTER, po czym rwno pod rozpoczynajc si instrukcj stawiam otwarty nawias klamrowy, ponownie klikam klawisz ENTER (nawet dwukrotnie) i wstawiam zamknity nawias klamrowy rwniutko pod tym otwartym powyej. Dopiero wtedy przenosz kursor pomidzy oba nawiasy i zaczynam wpisywa kod programu pomidzy nimi. Dziki temu rzadko myl si, jeli chodzi o stosowanie tych nawiasw. Dodam, e niektre zaawansowane rodowiska jak np. ECLIPSE, opisane przeze mnie wyej czynnoci wykonuj za mnie automatycznie! Oznacza to, e gdy po napisaniu instrukcji warunkowej lub ptli wcisn raz klawisz ENTER, to automatycznie pod spodem umieszczone zostaj od razu dwa nawiasy klamrowe a kursor umiejscawia si wraz z poprzedzajcym go tabulatorem/wciciem w linii pomidzy nimi, dziki czemu bez uciliwych wyej opisanych czynnoci przystpuj do pisania kodu. Inne rodowiska i edytory oferuj jeszcze inne narzdzia/gadety wspomagajc prac programisty w tym zakresie. Dlatego pisanie programu w zwykym lub lekko zaawansowanym programie typu notatnik, ktry oferuje tylko kolorowanie skadni, bywa w dzisiejszych czasach bardzo uciliwe.

4.2.9 instrukcja goto


Pozostawiem t instrukcj na koniec. Najchtniej w ogle bym jej nie omawia, poniewa jej istnienie powoduje, e pocztkujcy czsto nabieraj zych nawykw programowania, gdy si przyzwyczaj zbytnio do tej instrukcji. Niemniej jednak jest kilka drobnych sytuacji, gdzie moe si ona przyda. Wtedy nie jest wstydem jej uywanie. W pozostaych przypadkach jej nadmierne stosowanie wrcz wiadczy tylko le o programicie. C to za wstydliwa instrukcja? Jej skadnia to:

Strona | 70
goto etykieta .. .. .. etykieta: instrukcje;

4.3 Typy

Etykieta to dowolna aczkolwiek niezarezerwowana nazwa, po ktrej musi wystpi znak dwukropka. Dziaanie jest banalnie proste, sprowadza si do tego, e jeli program napotka t instrukcj, to wykonuje skok do miejsca, ktre wskazywane jest przez etykiet. Wane, e etykieta musi znajdowa si w odpowiednim zakresie widocznoci. O zakresach widocznoci, wicej powiem w nastpnych rozdziaach. Wspominaem jednak, e bywaj sytuacje, gdzie moemy prawie bez adnego wstydu z niej skorzysta. Co wcale nie oznacza, e bez niej sytuacja jest bez wyjcia. Wszystko zaley od inwencji twrczej programisty jak zwykle. Zatem wyobra sobie, na razie czysto teoretycznie, e masz wielokrotnie zagniedone ptle wraz z zagniedonymi warunkami if() lub funkcjami switch() wewntrz nich. Przychodzi jednak taki moment, e bezwarunkowo musisz opuci te wszystkie ptle bez koniecznoci wielokrotnego uywania rozkazu break, ktry ju znasz. Wtedy mona sign po instrukcj goto, za pomoc ktrej jednym prostym sposobem, przenosisz sterowanie programu cakowicie na koniec takiego dugiego zagniedonego bloku instrukcji. Jednak zawsze tylko w ramach widocznoci. Napomkn tylko, e np. nie mona wykona skoku goto pomidzy rnymi funkcjami. To wanie stanowi ograniczenie zakresu jej widocznoci.

Przechodzimy do omwienia jednego z najbardziej istotnych zagadnie jzyka C, ktrego zrozumienie posiada fundamentalne znaczenie dla dalszej nauki. Traktujc to zbyt pobienie wyrzdzibym ci krzywd. Postaraj si uwanie przeczyta i dobrze zrozumie oraz zapamita podane tutaj informacje. Bez nich ani rusz w dalszej naszej drodze. Kada nazwa, jaka wystpuje w jzyku C (poza nazwami etykiet np. przy instrukcjach goto), zanim zostanie uyta w programie, musi koniecznie zosta zdeklarowana. Tak naprawd wspominalimy ju o deklaracjach i rnicach pomidzy definicjami w rozdziale Deklaracja a Definicja. Przyjrzyjmy si temu nieco bliej. Zamy, e kompilator napotka na swojej drodze zapis typu:
a = b + c;

Wystpuje tu operacja dodawania oraz podstawienie wyniku tej operacji do zmiennej a. Kompilator musi, zatem uruchomi wewntrzne procedury, ktre bd mogy dokona stosownych oblicze. Jednak dla rnych dziaa matematycznych i nie tylko matematycznych, mog wystpowa rne procedury. Poza tym nawet, jeli w tym przypadku bdzie to dziaanie matematyczne (dodawanie), to kompilator musi wiedzie, jakiego typu s te zmienne. Inaczej bdzie bowiem wykonywa dodawanie liczb cakowitych bez znaku, inaczej dodawanie liczb cakowitych ze znakiem, inaczej dodawanie liczb zmiennoprzecinkowych lub mieszanych, jeszcze inaczej liczb o rnych moliwych zakresach wielkoci. Jeli liczby a oraz b bd si mieciy np. w zakresie od 0 do 255, to bdzie oznacza, e ich wartoci mona zapisa tylko w jednym bajcie. Jednak ju wynik takiej operacji, jak si domylasz, moe by wikszy ni 255, wic bdzie musia zosta zapisany w zmiennej skadajcej si z dwch bajtw. Jednak skd nasz biedny kompilator moe wiedzie na podstawie tylko zapisu w formie pokazanej powyej, jakich operacji ma uy, skoro nie powiedzielimy mu wprost, na jakich

Strona | 71
typach danych/zmiennych ma operowa i zacza ju konkretne procedury matematyczne? Musimy wczeniej zadeklarowa, a jeli obliczenia maj by wykonane podczas dziaania programu w oparciu o pami RAM mikrokontrolera, to musimy zmienne zdefiniowa. Pamitajc, e definicja zmiennej jest rwnowana z jej deklaracj. Dobrze spjrzmy, w jakiej postaci mona poda te wszystkie informacje kompilatorowi.
int a; uint8_t b=188, c=220; a = b+c;

Prosz bardzo, po dokonaniu takiego zapisu, kompilator nie pinie ju swka o bdach podczas przeprowadzania kompilacji tak napisanego kodu programu. Wyjanijmy sobie, jakich operacji dokonujemy w kolejnych liniach. Umiejtno takiej analizy to podstawa. Aby pisa program, ktry bdzie zrozumiay dla kompilatora, musisz si nauczy myle jak kompilator, w pewnym zakresie przynajmniej. A zatem:
1. Nastpuje deklaracja zmiennej a, ktra mwi, e zmienna a bdzie oznaczaa liczb cakowit ze znakiem w rozmiarze wynoszcym dwa bajty. Jednak, poniewa jest to przede wszystkim konkretna definicja, to zostaje zarezerwowane miejsce w pamici RAM mikrokontrolera o wielkoci dwch bajtw. To w tym miejscu kompilator bdzie przetrzymywa podczas ycia caego programu zawarto zmiennej a. Definicja ta nie powoduje jednak ustawienia wstpnej wartoci tej zmiennej. Zatem moe ona by przypadkowa albo moe by automatycznie inicjalizowana wartoci zero. (Niedugo dowiesz si, kiedy przypadkowa, a kiedy automatyczna ). Nastpuje na podobnej zasadzie jak wyej definicja oraz deklaracja zmiennych o nazwie b oraz c. Jednoczenie zostaje dla nich zarezerwowana pami. Po jednym bajcie na kad, co zwizane jest z typem uint8_t specyficznym dla kompilatora AVR GCC. Jednoczenie obydwie zmienne zostaj zainicjalizowane wartociami 188 oraz 200. Ta linijka programu to ju nie deklaracja ani nie definicja. To jest ju konkretna instrukcja programu. W wyniku jej dziaania kompilator podczy procedury, ktre wykonaj najpierw dodawanie liczb cakowitych bez znaku o rozmiarze jednego bajta, a nastpnie procedur, ktra wynik tego dodawania umieci w zmiennej a. To nic, e zmienna a posiada inny typ. Wane, e typ int potrafi pomieci liczb wiksz od 255. Jak widzisz, to programista, czyli ty musi dba o to, jakimi typami danych/zmiennych si posuguje!. Pamitaj o tym na zawsze.

2.

3.

Reasumujc, jeszcze raz przypomn bardzo istotn rnic pomidzy deklaracj a definicj za pomoc nieco innych sw. Musi to do ciebie dotrze w peni.

Deklaracja tylko informuje kompilator o tym, jakiego typu moe by zmienna.

Definicja nie tylko informuje kompilator, ale rezerwuje pami mikrokontrolera.

4.3.1 systematyka tyPW jzyka c


W standardowej definicji jzyka C istniej, tzw. podstawowe typy wbudowane. Nie bd tu omawia wszystkich dokadnie i w szczegach, poniewa nas bd bardziej interesoway, specyficzne typy wbudowane w nasz wersj kompilatora AVR GCC.
short int int long int Typy do przechowywania i pracy z liczbami cakowitymi

Strona | 72
char Typy do przechowywania kodw znakw alfanumerycznych

W istocie typ char nie suy tylko do przechowywania kodw znakw alfanumerycznych, moe on przechowywa liczby cakowite podobnie jak unsigned short int. Jednak na pocztku postaraj si kojarzy go z kodami znakw alfanumerycznych. (To moja propozycja nie tylko na potrzeby tej publikacji, ale take dla uatwienia wejcia w wiat C). Wszystkie powysze typy mog wystpowa w dwch wariantach, liczby ze znakiem i bez znaku. Co oznacza, e do poszczeglnych typw mona dodawa znaczniki: signed oraz unsigned, np.:
signed int liczba cakowita ze znakiem unsigned int liczba cakowita bez znaku podobnie z typem alfanumerycznym: signed char liczba cakowita reprezentujca ze znakiem unsigned char liczba cakowita reprezentujca znak alfanumeryczny bez znaku

W przypadku typu char wyszo nam w opisie troszk takie maso malane, ale ju wyjaniam, o co chodzi. Wszdzie, gdzie mwimy o znaku czyli signed oraz unsigned mamy na myli typy, ktre mog przechowywa tylko liczby dodatnie i ujemne te oznaczone signed, natomiast te oznaczone unsigned mog przechowywa tylko liczby dodatnie.
Typy do przechowywania i pracy z liczbami zmiennoprzecinkowymi

float double

Pozwalaj one pracowa na liczbach rzeczywistych o rnej precyzji. Z tym, e ze wzgldu na ograniczenia moliwoci maych mikrokontrolerw, do jakich zalicza si rodzina AVR, pozosta wprawdzie typ double, aby bya zgodno ze standardem, jednake jego precyzja jest dokadnie taka sama jak typu float.
Typy do przechowywania i pracy z wartociami logicznymi

bool

Zmienne tego typu mog przechowywa tylko dwie wartoci, prawd lub fasz. W praktyce mona takim zmiennym przypisywa wartoci oznaczone, jako false lub true. Co z kolei i tak na kocu sprowadza si do tego, e zmienna tego typu i tak bdzie tak posiadaa warto zero albo jeden. W zwizku z czym niezbyt czsto uywa si tych typw. Tym bardziej, e wie si to z koniecznoci zaczania do programu oddzielnej biblioteki zwanej stdbool.h.

Strona | 73
Nazwa Typ char cakowity unsigned char cakowity short int cakowity unsigned short int cakowity long int cakowity unsigned long int cakowity long long int cakowity long long unsigned int cakowity int cakowity unsigned int cakowity float rzeczywisty double rzeczywisty bool logiczny Dla oznaczenia braku danych void pusty Zakres -128127 0255 -3276832767 065535 -2^312^31-1 02^32-1 -2^632^63-1 02^64-1 = short int = unsigned short int 6 znakw precyzji 10 znakw precyzji 1 logiczny 0 Bajty 1 1 2 2 4 4 8 8 2 2 4 8 2

1 Jzyk o ktrym mwimy, AVR GCC nie obsuguje formatu liczb zmiennoprzecinkowych podwjnej precyzji. Jednak ze wzgldu na zgodno ze standardem mona deklarowa zmienne typu double tyle, e kompilator potraktuje je jakby byy to zmienne typu float.

Poniej charakterystyczne typy tylko dla AVR GCC:

Typ uint8_t int8_t uint16_t int16_t uint32_t int32_t uint64_t int64_t

Wielko bity bajty 8 1 8 1 16 2 16 2 32 4 32 4 64 8 64 8

Zakres 0 to 255 -128 to 127 0 to 65535 -32768 do 32767 0 do 4294967295 -2147483648 do 2147483647 0 do 1.8*1019 -9.2*1018 do 9.2*1018

W standardowym jzyku C wystpuj jeszcze inne typy, jednak na razie nie bdziemy o nich wspomina, gdy nie wszystkie dotycz naszych mikrokontrolerw. Przedstawi raczej zestawienie typw wbudowanych, z jakimi bdziemy mieli do czynienia korzystajc z naszej wersji kompilatora AVR GCC. Bardzo istotn i pozytywn cech jzyka C jest to, e mamy moliwo definiowana zmiennych w locie. C to oznacza? Najpierw odwoam si do innych jzykw, by moe miae moliwo poznania wczeniej niektrych. Okazuje si, bowiem, e najczciej w innych

Strona | 74
jzykach, wystpuje konieczno definiowania zmiennych na pocztku bloku kodu programu czy bloku funkcji itp. Na szczcie w jzyku C nie ma takich ogranicze, co oznacza, e moemy definiowa zmienne w dowolnym miejscu kodu programu! Poniej przykad:
uint8_t a=5,b=6; uint16_t c; c=a+b; int z; z=c+a+b;

Jak wida zmienn o nazwie z typu int zdefiniowalimy niejako po drodze. Przeciwnicy jzyka C twierdz, e to wprowadza baagan w kodzie i trudnoci z jego analizowaniem. Moim zdaniem myl si. (Tak p artem, p serio) Po prostu zazdroszcz, e nie maj takich moliwoci. Wybierajc standard kompilacji na ten o nazwie ISO C99 + GNU Extensions (-std=gnu99), otrzymujemy take bardzo ciekaw moliwo definiowania np. zmiennej iteracyjnej w ptli for podczas jej inicjalizacji. Przykad:
for(uint8_t i=0;i<10;I=I+1) instrukcja;

Jak widzisz definicja zmiennej i mieci si w znanej ci ju sekcji inicjalizacyjnej ptli typu for.

4.3.1.1 Typy zoone


Typy zoone to w uproszczeniu takie typy, ktrych nazwa skada si z nazwy jednego z typw podstawowych, o jakich mowa bya wyej oraz jednego z czterech operatorw. O samych operatorach bdziemy mwi pniej, jednak poniej przedstawi list tych, dziki ktrym mona tworzy typy zoone.

[] * ()

- pozwala utworzy tablic obiektw danego typu - (gwiazdka) pozwala utworzy wskanik - pozwala utworzy funkcj zwracajc warto danego typu

Wyobra sobie, e potrzebujesz zdefiniowa 50 zmiennych jednobajtowych typu uint8_t, ktre zostan zainicjalizowane okrelonymi wartociami pocztkowymi. Musiaby napisa albo 50 linii kodu, albo co najmniej kilkanacie, gdzie w kadej zdefiniowa po kilka takich zmiennych. W przypadku pomyki szybka zmiana kodu byaby mczarni. Czy nie lepiej byoby, gdyby mia moliwo uoenia jeden po drugim w formie tablic takich elementw typu uint8_t? Na pewno tak! Ale rwnie dobrze mona zdeklarowa tablic elementw dowolnego typu. Trzeba tylko zgodnie z tym, co pisaem wyej, do nazwy typu prostego doda dwa nawiasy kwadratowe, a pomidzy nimi okreli ilo elementw, aby kompilator wiedzia, ile pamici musi zarezerwowa. W przypadku 50 elementw typu uint8_t bdzie to 50 bajtw, a jak si domylasz, w przypadku 50 elementw uint16_t bd int bdzie to 100 bajtw. Zapiszemy to tak:
uint8_t tablica1[50]; int tablica2[50];

Strona | 75
Poprzez dodanie nawiasw kwadratowych utworzylimy typ zoony, jakim s tablice, przechowujce wiele elementw jednego typu. W przypadku powyszych definicji musiae poda koniecznie liczb elementw, jednak gdy chcemy (a mamy tak moliwo) od razu zainicjalizowa je konkretnymi wartociami, to moemy, aczkolwiek nie musimy, podawa w nawiasach kwadratowych iloci elementw. Kompilator obliczy sobie t ilo na podstawie podanych wartoci, jakimi bdziesz potrzebowa zainicjalizowa takie tablice. Poniej przykady:
uint8_t tab1[] = {1,2,3,4,5}; int tab2[] = {433,1200,20,0,30,288};

Wida z powyszego, e zmienna tablicowa o nazwie tab1 bdzie posiadaa pi elementw jednobajtowych, ktre zostan zainicjalizowane po kolei wartociami od 1 do 5. Natomiast tab2 bdzie posiadaa 6 elementw dwubajtowych, zainicjalizowanych kolejno liczbami podanymi w nawiasach klamrowych. Proste, prawda? Wiesz ju, jak tworzy i inicjalizowa tablice w jzyku C. Dla jasnoci mgby take dokona zapisu:
uint8_t tab1[5] = {1,2,3,4,5};

Jednak gdyby si pomyli i w inicjalizacji wpisaby nie 5 a wicej elementw, to wtedy kompilator ostrzegby ci o tej sytuacji wyranie.
uint8_t tab1[5] = {1,2,3,4,5,6,7,8};

Taka sytuacja jak powyej spowodowaaby bd w trakcie kompilacji, dlatego najczciej, jeli inicjalizujemy tablic w momencie definiowania, pomijamy take ilo elementw w nawiasach kwadratowych. Zobacz, w jak prosty sposb definiujemy tablice acuchw przy uyciu staych tekstowych, o ktrych pisaem wyej:
char bufor[100]; char napis2[] = Nowy tekst;

Pierwsza tablica znakw o nazwie bufor zostaa zdefiniowana i zarezerwowane zostao na jej potrzeby 100 bajtw przez kompilator. Jednak nie dokonalimy inicjalizacji. Poniewa chcemy zainicjalizowa drug tablic, to nie wpisujemy iloci bajtw, gdy zostan one wyliczone na podstawie dugoci znakw tekstu plus jeden na znak null. Oznacza to, e w tym konkretnym przypadku na tablic o nazwie napis2, kompilator zarezerwuje 11 bajtw. (10 Znakw tekstu oraz jeden znak null). Zapytasz zapewne od razu, gdzie taka tablica znakw zostanie zarezerwowana, w jakiej pamici RAM, FLASH, czy EEPROM? Jeli nie zostanie podany aden dodatkowy specyfikator standardu AVR GCC, to zawsze zostanie domylnie zarezerwowane miejsce w pamici RAM. O ile czasem potrzeba nam buforw na znaki czy teksty, na ktrych bdziemy wykonywali rne operacje w pamici RAM, co oczywiste. To jednak czsto potrzebowa bdziemy, aby zdefiniowa pewne acuchy znakw, teksty na stae w pamici FLASH albo w pamici EEPROM, eby mona byo pniej programowo podmienia ich zawarto wg wasnego uznania. Np. jakie napisy na wywietlaczu LCD itd. Jak wspomniaem, aby dokona rezerwacji w innej pamici ni RAM, trzeba uy specjalnych specyfikatorw. Spowoduje to jednoczenie, e odczyt takich danych z pamici FLASH i EEPROM bdzie wyglda inaczej ni z pamici RAM. A jeszcze inaczej bdziemy dokonywali

Strona | 76
modyfikacji ich zawartoci, czyli zapisu do pamici EEPROM. Wybiegajc jednak troszeczk w przyszo, poka ci, jak prosto mona umieci napis w tych rodzajach pamici nieulotnych.
char tab1[] EEMEM = Napis w pamici EEPROM; char tab2[] PROGMEM = Tekst w pamici FLASH;

Wystarczyo posuy si pisanymi du liter specyfikatorami EEMEM lub PROGMEM. Prawda, e proste? Wprawdzie bdzie to si wizao jeszcze z podczeniem odpowiednich bibliotek za pomoc plikw nagwkowych jak: eeprom.h dla specyfikatora EEMEM i operacji na pamici EEPROM oraz pgmspace.h dla specyfikatora PROGMEM i operacji odnonie odczytu z pamici FLASH. W tej chwili tylko to sygnalizuj, za jaki czas powrcimy w szczegach do tych tematw, poniewa bd nam bardzo potrzebne. Na temat typw zoonych, jak wskaniki i funkcje, porozmawiamy dokadniej w dalszych czciach ksiki.

4.3.1.2 Zakres widocznoci zmiennych


Jest to bardzo istotne zagadnienie. Jak zwykle brak wiedzy na temat choby jego podstaw powoduje wiele problemw nie tylko ze zrozumieniem programw w jzyku C ale take z ich prawidowym pisaniem. Jak to jest? Do tej pory sporo mwilimy o definiowaniu zmiennych rnych typw. Nigdy jednak nie wspominalimy, w jaki sposb s one widoczne, w jakich czciach programu si znajduj. Wiesz ju na pewno, e program w jzyku C zawsze skada si przynajmniej z jednej funkcji tej o nazwie main. Ale w rzeczywistoci na cay kod programu skadaj si dziesitki, a czasem setki i tysice rnorodnych funkcji. Zaczn, wic od przykadu, jeli zdefiniujemy zmienne w taki sposb:
int k,w; int max(uint8_t a, uint8_t b); int main(void) { uint8_t z=5, s=20; uint8_t m=13; } k=max(z,s);
// definicja zmiennych globalnych // deklaracja funkcji max() // pocztek programu main() // definicja zmiennych lokalnych // definicja zmiennej lokalnej // wywoanie funkcji max, wynik do k

int max(uint8_t a, uint8_t b) { int z=10;


// obliczenia i zwrot wyniku

// definicja funkcji max() // definicja zmiennej lokalnej

return (a>b) ? (a*z)+w : (b*z)+w;

To w wyniku jego analizy moemy okreli po kolei, co si dzieje w nastpujcy sposb. (Pewne informacje zawarem ju, jak widzisz, w przydatnych komentarzach). Zmienne k oraz w posiada bd zakres globalny w pliku, w ktrym znajduje si ta cz kodu programu. Moe jeszcze nie wiesz, ale kod programu moe znajdowa si w wielu

Strona | 77
plikach. Jednak zasig globalny w tym momencie nie odnosi si do caego projektu, czyli wszystkich plikw programu, a tylko i wycznie do tego pliku (o ile nie zmienimy tego stanu rzeczy za pomoc specjalnych specyfikatorw, o czym pniej). Zakres globalny w ramach pliku oznacza, e zmienna taka jest widoczna i nadaje si do uycia (odczyt lub zapis, o ile nie jest typu const), we wszystkich funkcjach programu! Jak widzisz, uywamy zmiennej globalnej o nazwie k w funkcji main(), natomiast zmiennej w take wewntrz funkcji max(). Nie ma z tym najmniejszego problemu, kompilator nie zgasza adnych zastrzee. Wewntrz funkcji main()definiujemy kilka zmiennych, ktre nazywam ju w komentarzach zmiennymi lokalnymi. Oznacza to, e zakres ich widocznoci znacznie si ograniczy. Podobnie wewntrz funkcji max() zdefiniowana jest zmienna lokalna o nazwie z. Wchodzc w szczegy wyjaniam, e np. zmienne lokalne zdefiniowane wewntrz funkcji main() bd dostpne tylko i wycznie dla dowolnych instrukcji programu take tylko wewntrz funkcji main(), nigdzie poza ni. Zatem gdybymy prbowali si w jakikolwiek sposb odwoa do ktrej z nich w innej funkcji np. max() to kompilator zgosiby bd i przerwa kompilacj. Podobnie ze zmienn lokaln o nazwie z zdefiniowan wewntrz funkcji max(), nie jestemy w stanie z niej skorzysta poza t funkcj, czyli w funkcji main() albo dowolnej innej, jeli by taka jeszcze wystpowaa. Prba uycia take skoczyaby si bdem w trakcie kompilacji. Aby dokoczy analiz tego programu, dodajmy, e wida take powyej gwnej funkcji programu deklaracj funkcji max(). Dziki temu kompilator analizujc kod od gry, linia po linii, gdy natrafi na odwoanie si w kodzie (wewntrz funkcji main) do funkcji max(), bdzie wiedzia, e taka istnieje. Zadeklarowalimy j w tym celu wczeniej. Natomiast poniej funkcji main()widzimy ju definicj funkcji max(), czyli cay kod programu, jaki ona zawiera. Reasumujc: Zmienne globalne to te, ktre zdefiniujemy na pocztku kodu programu, przed ciaem funkcji main(), bd zawsze miay globalny zakres widocznoci. Kada funkcja programu bdzie miaa do nich dostp. Zmienne lokalne to te, ktre zdefiniowane zostan wewntrz kadej z funkcji,w tym take funkcji main(). Bd one widoczne tylko dla instrukcji kodu programu zawartych wewntrz funkcji, w ktrych s zdefiniowane. Wystpuj jeszcze inne typy zmiennych, jak np. takie ze specyfikatorem static, ale o tym pniej.

4.3.1.3 Typ void


Ten typ, void, wie si cile z typami zoonymi, o ktrych pisaem wyej. Praktycznie samodzielnie, w pojedynk nigdy nie wystpuje. Natomiast w poczeniu z typami zoonymi moe mie nieco rne znaczenia, cho zwykle mwi o tym, e mamy do czynienia z czym nieznanym. Jest to tak naprawd jeden z fundamentalnych typw jzyka C. Poniej kilka przykadw, chocia ich szczegowym wyjanianiem take zajmiemy si pniej:
void *wsk; void *p; void fun(void);

Strona | 78
Teraz krtkie wyjanienie do powyszych linii kodu programu. W pierwszej i drugiej wykonalimy definicj wskanika o nazwie wsk oraz p, ktre pokazuj nam na obiekt nieznanego typu. Napisaem obiekt, poniewa rwnie dobrze taki wskanik bdzie mg pniej posuy do pokazywania na zmienn dowolnego typu podstawowego lub zoonego albo nawet na funkcj programu. W trzeciej linijce pierwszy specyfikator void ten przez nazw funkcji mwi o tym, e zdefiniowana w ten sposb funkcja nie bdzie zwraca adnego wyniku. Natomiast specyfikator void pomidzy nawiasami okrgymi mwi, e do tej funkcji nie bd przekazywane adne argumenty.

4.3.1.4 Specyfikator const


Czasem zdarza si bdzie, e w programie zechcesz uywa niektrych zmiennych, ktre bd przechowyway przez cae ycie programu pewne stae wartoci. Powiem wicej, chciaby mie moliwo, eby przez przypadek aden fragment rozbudowanego programu nie zniszczy przypadkiem tej staej. Wtedy przyjdzie ci z pomoc specyfikator const. Zamy, e w jednej zmiennej dla caego programu chcesz przechowywa warto jakiego wspczynnika podziau. Niech posiada on sta warto rwn np. 45. Inna zmienna bdzie przechowywaa do pewnych oblicze liczb PI. Moemy zatem uywajc specyfikatora const napisa:
const uint8_t wspolczynnik = 45; const float PI = 3.14;

Od tej pory moesz uywa zmiennej wspczynnik oraz PI ale tylko i wycznie w trybie do odczytu. Gdy tylko sprbujesz nawet przez pomyk zmieni zawarto jednej z tych zmiennych, od razu kompilator zareaguje bdem w trakcie przeprowadzania kompilacji. Zwrc uwag na dodatkow kwesti. Wprawdzie nie znasz jeszcze zagadnie zwizanych z preprocesorem. Jednak istnieje pewna dyrektywa tego preprocesora o nazwie #define. Dziki niej moglibymy uzyska bardzo podobny efekt, jeli chodzi o moliwo zdefiniowana pewnych staych wartoci, o jakich mwiem powyej. Oznacza to, e uywajc zapisu z przykadu poniej:
#define wspolczynnik 45 #define PI 3.14

otrzymujemy pozornie identyczn sytuacj. Od tej pory moemy si posugiwa identyfikatorami wspolczynnik oraz PI na podobnej zasadzie. Istniej jednak podstawowe rnice, o ktrych warto wiedzie, gdy moe to si okaza bardzo przydatne w trakcie pisania rnych programw. Czasem warto bdzie skorzysta ze specyfikatora const, a czasem wystarczy #define. Oceni si to samemu, kiedy posidzie si odpowiedni wiedz i praktyk w tym zakresie. Czym jednak z praktycznego punktu widzenia rni si dla nas deklaracja zmiennej za pomoc #define od definicji ze specyfikatorem const? W oparciu o informacje podane wczeniej na temat rnic pomidzy deklaracj a definicj zmiennej ju powiniene dostrzec podstawow rnic. Ot definicja zmiennej/staej ze specyfikatorem const od razu rezerwuje miejsce w pamici na t zmienn. Natomiast sama deklaracja za pomoc dyrektywy #define tego nie czyni. Dyrektywa #define powoduje z punktu widzenia kompilatora zadeklarowanie staej dosownej, zatem kompilacja odbywa si w ten sposb, e w kadym miejscu, gdzie kompilator napotka nazw zadeklarowan za pomoc dyrektywy #define po prostu podstawi w to miejsce konkretn sta warto, ktra widnieje w tej deklaracji.

Strona | 79
Kolejna rnica w tym, e stae definiowane przy uyciu const bd mogy uzyskiwa rne zakresy widocznoci, w zalenoci od tego, w jakim miejscu zostan zdefiniowane. Natomiast stae zdeklarowane z uyciem #define bd zawsze widoczne dla kompilatora w caym programie. Jeeli spotkasz si z sytuacjami, kiedy warto bdzie ukrywa zasig swoich staych, wtedy signiesz po const. Kolejna rnica polega na tym, e staa zdefiniowana za pomoc const ma swoje odzwierciedlenie w pamici mikrokontrolera, a co za tym idzie, mona do niej odwoa si za pomoc wskanika. Tymczasem staa zadeklarowana poprzez #define, jako e nie rezyduje w pamici, nigdy nie bdzie dostpna poprzez wskanik. Czasem moe to by bardzo potrzebne. Mam tylko nadziej, e starasz si ledzi dokadnie, w jakich momentach uywam sowa deklaracja, a w jakich definicja. Nie robi tego przypadkowo i zamiennie, poniewa kade z tych okrele ma swoje istotne znaczenie. Teraz widzisz, jak wane jest i ile rzeczy si wie z dobrym zrozumieniem tego zagadnienia.

4.3.1.5 Specyfikator volatile


Z angielskiego sowo volatile oznacza ulotny. Tak te kompilator traktuje zmienne, ktre zostay zaopatrzone w trakcie definicji w przydomek volatile. Przykad definicji zmiennej z tym specyfikatorem/przydomkiem:
volatile int a;

Kiedy powinnimy go stosowa? Zawsze w takich sytuacjach, gdy chcemy, aby kompilator nie optymalizowa dostpu do takiej zmiennej. Co si takiego wie z optymalizacj zmiennych bez przydomka volatile? Kompilator nie widzc tego przydomku zakada, e taka zmienna nigdy nie bdzie moga si zmieni bez wiedzy kompilatora. Zaoenie to czyni ju na etapie kompilacji i w wyniku tego czsto, jeli np. w jakiej funkcji ma wykonywa operacje na teje zmiennej, pozwala sobie na optymalizacj, majc na celu przypieszenie dziaania programu. W mikrokontrolerach jest to szczeglnie istotne. Optymalizacja taka polega najczciej na tym, e bezporednio po wejciu do funkcji main() czy jakiejkolwiek innej, kompilator zapamituje sobie zawarto komrki tej pamici w podrcznym i wolnym rejestrze mikrokontrolera. Zwykle ma spory zapas takich wolnych rejestrw. Dziki temu w dalszej czci funkcji ju nigdy nie odwouje si do zawartoci tej komrki pamici, tylko operuje na zawartoci rejestru. Dopiero przy wyjciu z funkcji oczywicie przy wyjciu z innej funkcji ni main() dokona zapisu aktualizowanej w rejestrze zawartoci bezporednio do tej komrki. A poniewa ptla gwna programu main() nigdy si nie koczy to mona przypuszcza, e cay czas bdzie program si odwoywa i pracowa tylko w oparciu o ten rejestr, eby szybciej wykonywa dziaania. Jest to z jednej strony bardzo poyteczne i podane. Jednak czasami wprowadzasz do programu procedur obsugi jakiego przerwania, ktra take bdzie miaa za zadanie wykonywa operacje na tej samej zmiennej. I jeli nie bdzie ona opatrzona przydomkiem volatile, to kompilator spowoduje, e w trakcie wejcia w przerwanie, zmienna trafi do innego rejestru, na nim dokonane zostan stosowne aktualizacje a przy wyjciu z procedury obsugi przerwania, zawarto rejestru trafi znowu do komrki pamici tej zmiennej. No i katastrofa! Bo przecie w ptli gwnej main() program nigdy nie zajrzy, jak wspomniaem wyej, do tej komrki w zwizku z umieszczeniem jej zawartoci w podrcznym rejestrze. W takiej sytuacji zawsze dziaa na podrcznym rejestrze, do ktrego raz wczyta t zmienn. Zatem ptla gwna nigdy si nie dowie o tym, e w co (np. procedura przerwania) podmienio zawarto tej komrki i zacznie dochodzi do przedziwnych bdw w programie, ktrych przyczyny trudno bdzie si od razu domyli.

Strona | 80
Dlatego, jeli wiesz, e niektre zmienne bd zapisywane i odczytywane zarwno w funkcjach, ale i procedurach przerwa mikrokontrolera, czyli mog si zmienia w rnym czasie, to trzeba wymusi, aby kompilator nie optymalizowa dostpu do takich zmiennych. Musi za kadym razem, gdy chce wykona na nich operacj, odwoa si bezporednio do zawartoci komrek pamici, gdzie te zmienne rezyduj i to ich zawarto modyfikowa wedle potrzeb, a nie jaki podrczny rejestr penicy rol bufora. Brak takiej optymalizacji wpynie wprawdzie na to, e dostp do zmiennej bdzie nieco wolniejszy ni do rejestru (co mogoby by w wielu przypadkach spor wad), ale dlatego nie wszystkie zmienne definiujemy jako volatile. Tylko te, ktrych jak byo powiedziane na pocztku, zawarto moe by ulotna, czyli zmienia si bez wiedzy kompilatora, np. w procedurach obsugi przerwa.

4.3.1.6 Specyfikator register


Pamitasz? W poprzednim rozdziale wspominalimy, e kompilator tam, gdzie mona, dokonuje optymalizacji dostpu do zmiennych. Jednym ze sposobw optymalizacji jest umieszczanie wartoci zmiennej w rejestrze, a poniewa w kodzie maszynowym dostp do rejestru jest o wiele szybszy ni do pamici RAM, to optymalizacja taka zawsze zdecydowanie przypiesza dziaanie programu, co bywa bardzo istotne w procedurach krytycznych czasowo. Zdarza si jednak czasami, e niekoniecznie kad zmienn kompilator zaaduje do rejestru wewntrz funkcji. Czasem wczy inny rodzaj optymalizacji. My jednak, jako programici, moemy prbowa wymusi na kompilatorze, aby niejako na si zastosowa ten wariant, i prbowa umieci w rejestrze. Mog by czasem procedury/funkcje, gdzie z naszego punktu widzenia czas ich wykonywania jest bardzo krytyczny. S to zwykle krtkie funkcje i jeli szczeglnie zaley nam na szybkoci ich wykonywania, to moemy zaopatrzy zmienn w przydomek register. Kompilator bdzie si wtedy stara jak moe, aby tylko wykona dla nas t operacj. Przykad takiej definicji zmiennej:
register uint8_t licznik;

Z uwagi jednak na to, e wszystkie rejestry mikrokontrolerw AVR maj posta jednego bajtu. Tylko niektre mog by traktowane w poczeniu, jako rejestry indeksowe, nie ma wikszego sensu, aby dodawa przydomek register zmiennym, ktre posiadaj rozmiar wikszy ni jeden bajt ostatecznie dwa bajty.

4.3.1.7 Instrukcja Typedef


Wspomniaem ju chyba wczeniej krciutko, e ogromn zalet jzyka C jest moliwo definiowania nowych, nawet wasnych typw danych. Mona powiedzie, e pozwala to pynnie rozszerza moliwoci podstawowego standardu jzyka. I to stanowi m.in. o olbrzymiej przewadze jzyka C nad innymi jzykami wyszego rzdu. Do tych celw przydatna bdzie wanie instrukcja o nazwie Typedef. Za jej pomoc mona np. nada now nazw istniejcemu ju typowi. Dlatego czsto w cudzych programach napisanych dla mikrokontrolerw AVR spotka si takie definicje zmiennych:
u08 a; u16 z; u32 g;

Strona | 81
Bardzo czsto programistom nie chce si wpisywa specyficznych typw dla AVR GCC i mikrokontrolerw AVR jak: uint8_t, uint16_t czy te uint32_t. Dlatego te czsto w tych programach znajdziesz uyt instrukcj typedef w celu utworzenia nowych typw o nazwach jak wyej: u08, u16 czy u32. Dziki temu nie trzeba tyle pisa za kadym razem przy definicji zmiennej. Wystarczy na pocztku programu napisa:
typedef uint8_t u08; typedef uint16_t u16; typedef uint32_t u32;

Oznacza to, e wanie zdefiniowalimy na wasne potrzeby trzy nowe typy o nazwach jak w przykadzie, dziki czemu jeli w dalszej czci kodu programu zdefiniujemy zmienne korzystajc z tych typw, zostan one potraktowane dokadnie jak zmienne typu, od ktrego pochodzi nasz nowo utworzony typ. Jednym sowem zmienna typu u08 bdzie tak naprawd zmienn typu uint8_t i analogicznie nastpne. Nie tylko w taki celach przydatne bywa definiowane nowych typw. Np. bdziesz w programie bardzo czsto posugiwa si zmiennymi, ktra bd miay np. za zadanie przechowywa warto poziomu oleju. Definicje takich zmiennych bd si pojawiay w wielu funkcjach i miejscach programu. Charakterystyczne dla nich bdzie to, e zawsze zawieraj liczb cakowit ze znakiem z zakresu int. Ciko bdzie jednak pniej analizowa program, ktry posiada zdefiniowan spor ilo zmiennych, nazwy s rne i jak na pierwszy rzut oka, szybko wyapa, ktre z nich przechowuj ten poziom oleju? Odpowied jest prosta, wystarczy zdefiniowa nowy typ:
typedef int P_olej;

Od tej pory bdziesz mg spokojnie w rnych czciach programu definiowa rne zmienne a patrzc na ich typ bdziesz w mig wiedzia, do jakiego celu je utworzye.
P_olej poziom1; P_olej poziom2; P_olej wskaznik3; P_olej miarka2;

Przyznaj, e to bardzo przydatna rzecz. Naturalnie tego polecenia mona take uywa w zwizku z typami zoonymi, jak np. wskaniki. Przykady:
typedef int * wskaznik_do _int; typedef char * napis;

pniej definicje
wskanik_do_int p1; napis komunikat;
// czyli: int * p1 // czyli: char * komunikat

Bardziej docenisz to zagadnienie z powyszego przykadu, gdy dowiesz si duo wicej na temat samych wskanikw oraz moliwoci ich stosowania. Zapewniam ci wyprzedajc fakty, e wskaniki to jedno z najlepszych narzdzi jzyka C,

Strona | 82
cho trzeba przyzna, e take nieco skomplikowane i na pocztku ciko je zrozumie bez dobrego wytumaczenia i przykadw. Nie martw si, postaram si, aby jak najszybciej i jak najwicej zrozumia te zagadnienia w dalszych rozdziaach.

4.3.1.8 Typy wyliczeniowe enum


To kolejne pikne narzdzie programistyczne. Praktycznie w innych popularnych jzykach dla mikrokontrolerw nieosigalne. Jest tak bardzo przydatne, e niekorzystanie z niego w swoich programach mgbym artobliwie okreli jako ciki grzech. Typ wyliczeniowy to cakiem osobny typ, za pomoc ktrego moemy szybko utworzy zestaw staych cakowitych. Nagminnym przypadkiem jest, e w programach czsto trzeba przechowywa nie liczby, lecz pewien rodzaj informacji. Wprawdzie bdziemy te informacje przechowywa w postaci liczb, chyba e mamy moliwo skorzystania z typu wyliczeniowego. Wtedy sama liczba nie bdzie dla nas a tak istotna. Pewnym istotnym dla nas wartociom bdziemy mogli nada nazwy i to nimi si posugiwa zamiast liczbami. Wyobra sobie zmienn, ktra normalnie, gdy nie znasz tego mechanizmu, przechowuje w postaci liczb poziom menu, na jakim znajduje si aktualnie uytkownik. Musisz pamita w kadym miejscu programu, e warto 0 oznacza poziom gwny, ale ju jaka liczba wyrwana z kontekstu np. 23 oznacza trzeci poziom podmenu o nazwie Ustawienia. O ile pamitanie o tym, e poziom zerowy to menu gwne, nie nastrcza problemw, to ju kada kolejna liczba, jeli tych poziomw jest duo, powoduje, e czasem si w tym gubimy. Bardzo czsto w takiej sytuacji bierzemy zwyk kartk papieru lub w kodzie programu tworzymy w jakim miejscu specjaln tabelk, gdzie opisujemy na wasne potrzeby, co oznacza kada liczba, tzn. ktry poziom menu ona reprezentuje. Gorzej, gdy karteczka si zgubi albo, gdy program skada si z wielu plikw i musimy przecza si midzy nimi, aby odnale te swoje zapiski w tabelce. Jeszcze gorzej, jeli w trakcie programu potrzebujemy czsto tworzy nowe poziomy pomidzy ju istniejcymi. Wtedy caa tabelka bierze w eb i trzeba j mudnie przepisywa od nowa i dokonywa mnstwo zmian w kodzie. Po co jednak tak si mczy? To bardzo blisko jest od takiej tabelki, ktra przyporzdkowuje kad liczb do konkretnego poziomu menu, do zastosowania typu wyliczeniowego enum! Wystarczy, e zastosujesz si do takiej skadni:
enum nazwa_typu {wartosc1, wartosc2,, wartoscN};

Gdzie w miejsce nazwa typu w naszym konkretnym przypadku wprowadzimy nazw np. menu_poz a w nawiasach klamrowych podasz tylko wartoci opisowe dla poszczeglnych poziomw menu z tradycyjnej tabelki, np. tak jak poniej. Jednak w przykadzie z oczywistych wzgldw wpisz tylko kilka wartoci. Przyjmijmy zaoenie, e zbudowalimy zegar oraz utworzylimy menu gwne, z ktrego mona przej do kolejnych poziomw aby ustawi czas, ustawi dat czy te ustawi alarm (budzik).
enum menu_poz {mglowne, mczas, mdata, malarm};

enum menu_poz idx=mglowne;

Prosz bardzo, wanie w pierwszej linii powyszego przykadu zdefiniowalimy nowy typ wyliczeniowy o nazwie menu_poz, a nastpnie w kodzie programu moemy ju zdefiniowa konkretn zmienn o nazwie w tym przypadku idx. Dokonujemy jednoczenie jej inicjalizacji (UWAGA!), nie za pomoc staej liczbowej, lecz za pomoc wartoci, ktra istnieje w

Strona | 83
naszym typie wyliczeniowym. Zatem moemy ju wyrzuci nasz karteczk z rozpisan tabelk, bd usun tabelk z opisu w pliku. Wicej si nam ona nie przyda. Ale zapytasz zapewne, co si stanie, jeli teraz zechcemy doda now pozycj w naszym menu? Ale nic prostszego, zamy, e kolejna pozycja menu powinna umoliwia ustawienia parametrw zegara. Taki nasz setup.
enum menu_poz {mglowne, msetup, mczas, mdata, malarm};

enum menu_poz idx=mglowne;

Zauwa, e specjalnie wstawiem t pozycj gdzie w rodek naszych wartoci typw, bo zaoenie jest takie, i kolejn pozycj po menu gwnym ma by wanie setup. Jednak istnieje w tym przypadku zupena dowolno, mona doda na kocu bez adnych konsekwencji, tak jak to byo, gdy prowadzilimy swoje tabelki z opisami.
enum menu_poz {mglowne, mczas, mdata, malarm, msetup};

Mam nadziej, e dostrzegasz teraz ogromne moliwoci tego mechanizmu? Moesz si jednak zastanawia, co tak naprawd bdzie zawiera zmienna idx, jeli przypiszemy do niej dowoln warto typu wyliczeniowego. Ju wyjaniam. Zasada jest prosta, domylnie, jeeli sami nie wprowadzimy zmian, rozpoczyna si numerowanie wartoci od zera. W zwizku z tym pozycja mglowne=0, mczas=1, mdata=2, malarm=3, setup=4. Jednak programista ma moliwo wpywu na t numeracj. Wystarczy dokona takiego zapisu:
enum menu_poz {mglowne, mczas=7, mdata, malarm=43, msetup};

Spowoduje to, e teraz: mglowne mczas mdata malarm setup = 0 (domylnie gdy nie przydzielilimy rcznie adnej wartoci) = 7 (wida wyej dlaczego) = 8 (poniewa numeracja bdzie dalej biega od poprzedniego numeru) = 43 = 44

Pamitaj, e zmienn naszego nowego typu moesz posugiwa si take, jak zwyk liczb. Dozwolone s ponisze dziaania:
enum menu_poz idx; uint8_t a,b=10; idx = malarm; a = b + idx;

W wyniku takiego dziaania zmienna a bdzie miaa warto 53. Poniewa do zmiennej idx przypisalimy malarm, ktry zgodnie z przykadem wyej posiada zdefiniowan warto = 43. Natomiast zmienn b zainicjalizowalimy liczb 10. Zatem wynikiem b + idx jest liczba 53. Okazuje si take, e kompilator AVR GCC zezwala na przypisanie do zmiennej idx take innych wartoci tzn. czysto liczbowych za pomoc staych

Strona | 84
lub zmiennych. Niektre inne kompilatory nie zezwalaj na tak operacj generujc bd w trakcie kompilacji. Czy taki mechanizm bdzie ci potrzebny ocenisz ju sam. W kadym razie mona zastosowa ponisze dziaania:
enum menu_poz idx; uint8_t a=10; idx = 122; idx = a + 87;

Wykorzystanie tego zaley ju tylko od twojej inwencji twrczej. Podam jednak jeszcze jeden przykad popularnego zastosowania dla typu enum. Pniej w czci praktycznej, gdy zajmiemy si oprogramowaniem ukadu scalonego, RTC, ktry jest zegarem czasu rzeczywistego, okae si, e mona z niego odczyta, jaki mamy aktualnie numer dnia tygodnia. Jak si dowiesz, wystpuje tam taka zaleno, e odczytana liczba 0 odpowiada poniedziakowi, 1 to wtorek, 2 roda, 3 to czwartek, 4 pitek, 5 sobota oraz 6 niedziela. Gdy napiszesz program do obsugi takiego zegarka, zapewne bdziesz chcia atwo i szybko pokazywa nazwy dni tygodnia na wasnym wywietlaczu LCD. Jednak za kadym razem bdziesz musia pamita powysze przypisania w rnych procedurach, gdzie bdzie trzeba sprawdza, jaki jest aktualnie dzie tygodnia. Aby sobie uatwi ycie, zastosujesz jednak typ wyliczeniowy enum.
enum t_dzien {pon, wto, sro, czw, pia, sob, nie};

pniej utworzysz zmienn bd zmienne, w ktrych bdziesz przetrzymywa dni tygodnia, ale nie bdziesz musia si ju posugiwa na pami cyframi kolejnych dni. Teraz bdziesz uywa ju wygodnych i atwych do zapamitania nazw.
enum t_dzien dzien = sro;

nastpnie gdzie dalej w programie sprawdzanie, jaki jest dzie w zmiennej:


if (dzien == pia) instrukcja;
// wycz filtr w akwarium

lub z instrukcj switch:


switch(dzien) { case sro: instrukcja1; instrukcja2; break; case pia; instrukcja3; instrukcja4; break; case nie: instrukcja5;

Strona | 85
Jak wida w zalenoci od dnia tygodnia mona wykona rne czynnoci w programie, symbolizuj to rne numery instrukcji w przykadzie. Mam nadziej, e wyczerpujco przedstawiem to wane narzdzie, jakim jest typ wyliczeniowy.

4.3.2 stae W jzyku c


Brzmi gronie, ale to na szczcie banalny, chocia istotny temat w naszych rozwaaniach i nauce jzyka C. Ze staymi bdziesz mia wci do czynienia. Nazywa si je staymi dosownymi. Wyrniamy nastpujce rodzaje staych:
1. 2. 3. 4. Liczbowe cakowite Liczbowe zmiennoprzecinkowe Znakowe Tekstowe

Przypomn, e ju w wielu przykadach powyej skorzystalimy ze staych dosownych. Byy to jak do tej pory stae liczbowe cakowite. Gdy pisalimy np. definicj zmiennej int a=122; to liczba 122, ktr zainicjalizowalimy zmienn, jest wanie pierwszym przykadem staej dosownej.

4.3.2.1 Stae jako liczby cakowite


Mog to by liczby zapisywane w taki sposb, jaki nam najbardziej odpowiada. Moemy przy tym korzysta z postaci dziesitnej liczb, z postaci szesnastkowej czy semkowej. Mog to by liczby ze znakiem, czyli take ujemne, i bez znaku. Przykad:
Dziesitnie: 22 8 71 -15 0 455 1024 itd.

Szesnastkowo: 0x10 0xf2 0x00 0x045 0x01 0xffff itd.

Nie musz chyba przypomina, jak stosowa zapis szesnastkowy, licz na to, e ju wiesz dokadnie, o co w tym chodzi. Zwrc jedynie uwag, e jzyku C, jeli chcemy przedstawi liczb w postaci szesnastkowej, to w odrnieniu od postaci dziesitnej musimy j poprzedzi znakami 0x (zero oraz x). Dodam jeszcze, e mona w zapisie szesnastkowym inaczej zwanym hexadecymalnym uywa zarwno duych jak i maych liter. Dla kompilatora bdzie to zupenie obojtne. Trzeba sobie jednak zdawa spraw, do jakiego typu konkretnie kompilator zalicza domylnie stae bdce liczbami cakowitymi. Domylnie, jeli napiszemy np. liczb 200, zostanie ona zakwalifikowana jakby bya typu int. Jeli oczywicie chcemy poda, jako sta liczb, ktra wykracza poza zakres int (patrz Tabela.1), to wtedy zostanie uznana, oczywicie automatycznie, za kolejny wikszy typ, czyli np. long int. Mamy jednak moliwo aby wiadomie da zna, aby np. liczb 200 traktowa od razu jako typ long int. Wystarczy, e na kocu takiej liczby postawimy literk L. Moe to by maa lub dua litera, jednak ze wzgldu na czytelno lepiej posugiwa si du. Wtedy zapis bdzie wyglda tak 200L, 0L, 33L itd.

Strona | 86
Mamy take wpyw na to, czy kompilator ma przyjmowa sta, jako liczb bez znaku, (jako unsigned). Wtedy musimy na kocu zastosowa literk u. Przykad: 223u, 10u, 1234u itd. Mona take czy literk u z literk L, wtedy okrelamy, e chodzi nam o typ unsigned long int, przykady: 200uL, 1000000uL, 855uL itd.

4.3.2.2 Stae jako liczby zmiennoprzecinkowe


Przykady staych liczb zmiennoprzecinkowych:
18.3 24.99 0.167 -44.82 itd.

W naszym standardzie jzyka AVR GCC ze wzgldu na opisane wyej ograniczenia bd zawsze traktowane jako typ float z nalen mu precyzj. Generalnie, musisz pamita, eby jak najrzadziej korzysta w ogle z typw zmiennoprzecinkowych. Wie si to z tym, e mikrokontrolery AVR nie posiadaj rozkazw na poziomie kodu maszynowego, ktre mogyby dokonywa oblicze bezporednio na takich liczbach. Zatem wszelkie operacje wymagaj zastosowania przez kompilator dosy sporych objtociowo bibliotek programowych, ktre zajmuj spore iloci pamici programu, a take pamici RAM mikrokontrolera. Dlatego czsto pocztkujcy adepci jzyka AVR GCC s bardzo zdziwieni, e jeli na pewnym etapie tworzenia programu zastosuj chocia jedn zmienn typu float, na ktrej zechc wykona operacje matematyczne, to od razu po kompilacji okazuje si, e drastycznie wzroso zuycie pamici programu FLASH oraz czsto take pamici RAM naszego mikrokontrolera. O tym, jak sobie z tym radzi i jak unika typu float bdzie pniej, szczeglnie w trakcie wicze.

4.3.2.3 Stae znakowe


Tego typu stae, jak sama nazwa wskazuje, su do reprezentacji pojedynczych znakw alfanumerycznych. Zapisuje si je podajc znak wewntrz dwch apostrofw. Przykady:
a B Z 9 0 + # itd.

W pierwszych trzech przypadkach mamy do czynienia z literami, a w kolejnych dwch ze znakami cyfr, jeszcze w kolejnych dwch stae reprezentujce znak plus oraz hash. Wykorzystujemy je wtedy, gdy chcemy zainicjalizowa jak nowo zdefiniowan zmienn, np.:
char znak = A; char p = a;

Oczywicie mikrokontroler nie potrafi przechowywa znaku A czy te znaku cyfry 6. Za to potrafi podstawi do tych zmiennych kody ASCII tych znakw. W tym przypadku zmienna znak bdzie zawieraa tak naprawd liczb 65 a zmienna p liczb 97. S to dokadne kody znakw z tabeli ASCII. Ale to nie wszystko, poniewa nie wszystkie znaki ASCII jestemy w stanie wpisa w postaci znaku w jakimkolwiek edytorze. Wemy na przykad znany ci dobrze znak ASCII o nazwie ENTER. Posiada on kod = 13. Ale s take inne niedrukowalne na ekranie znaki. Okrela

Strona | 87
si je mianem znakw specjalnych i w jzyku C mamy do nich dostp w prosty sposb. Poniej krtkie zestawienie niektrych znakw specjalnych.
\b \f \n \r \t \v \a Backspace Form feed New line carriage Return Tabulator Vertical tabulator Alarm

Posuyem si nazwami angielskimi, poniewa i tak najczciej takimi si posugujemy. Bardzo czsto bdziemy uywa znakw \r czyli nasz znak ENTER (kod 13) oraz \n, czyli znak nowej linii (kod 10). eby przypisa do zmiennej taki znak posuymy si take apostrofami w ktrych zamkniemy taki znak specjalny:
char znak = \r;

Od tej pory zmienna znak bdzie przechowywaa kod, czyli liczb 13. Poniewa jednak do zapisu znakw specjalnych musimy uywa ukonika \ oraz apostrofw, to pojawi si pewien kopot, jeli bdziemy chcieli podstawi do zmiennej czy dokona porwnania w warunku, znaku apostrofa, ukonika, ale te jeszcze kilku innych znakw. Dlatego podam jeszcze kolejn krtk list znakw specjalnych, tzn. jak naley je zapisywa w kodzie.
\\ \ \ \? \0 ukonik apostrof cudzysw znak zapytania null, czyli znak o kodzie zero

Oczywicie takie znaki take musimy otoczy apostrofami, wic czasem wyjd dziwne konstrukcje np. w przypadku znaku apostrofa, bdziemy musieli napisa tak: char znak=\. Jednak to jest jedyny prawidowy zapis z uyciem znaku specjalnego. Mamy do dyspozycji jednak jeszcze jeden sposb przedstawiania konkretnego znaku ASCII wewntrz apostrofw. Moemy go poda bezporednio jako liczb, ale tylko w zapisie hexadecymalnym lub semkowym. Najczciej bdziemy si posugiwa jeli ju zapisem hexadecymalnym. Pozwala on nam na reprezentacj kadego znaku ASCII bez wyjtku. Aby mc zaprezentowa znak w postaci hexadecymalnej, musimy uy prefixu/zapisu: \x, ktry bdzie poprzedza warto szesnastkow. Przykad:
char = \x41; co jest rwnoznaczne char = A; poniewa liczba 0x41 to dziesitnie 65, natomiast 65 jest kodem ASCII duej literky A.

Strona | 88 4.3.2.4 Stae tekstowe, stringi


Bardzo czsto w programach bdziesz zmuszony posugiwa si staymi w postaci rnego rodzaju tekstw. Temat ten zwizany jest zagadnieniem zwanym C-string. Jest to staa tekstowa w postaci cigu znakw ujtych w cudzysowy. Przykady:
jaki tekst Napis na wywietlacz LCD Pomiar napicia

W skrcie mwimy na takie cigi znakw po prostu stringi. Wewntrz takiego cigu znakw moemy bez problemu wstawi znaki specjalne opisane powyej, np.:
Pierwsza linia tekstu \r\n Druga linia tekstu

Jak widzisz wstawiem dwa znaki po sobie jeden to znak ENTER \r a drugi to znak nowej linii \n. Dziki temu, gdybymy taki cig znakw przesali np. do terminala, spowodowaby to, e pojawiyby si na jego ekranie dwie linie tekstu zamiast jednej. Tekst Pierwsza linia tekstu wywietlony zostaby w pierwszej linii, nastpnie znaki specjalne spowodowayby przejcie do pocztku nowej linii oraz wywietlenia w niej kolejnej czci tekstu Druga linia tekstu. Jak widzisz na pocztku pozostaaby spacja, ktr wstawiem specjalnie w tekcie stringa aby wyranie uwidoczni znaki specjalne. Nie trzeba oczywicie stosowa takich spacji. Stringi moemy zapisywa na wiele rnych sposobw. Jeden ju znamy, mona wstawia do rodka znaki specjalne. Jeli na przykad chcemy zapisa bardzo dugi cig znakw, ktry nie mieci nam si w jednej linii w oknie edytora, moemy go rozbi na czci w poniszy sposb, stawiajc rednik na samym kocu:
char tab[] = Przykad linii, w ktrej wystpuje bardzo dugi tekst i nie mieci si w jednej linii;

Wprawdzie jeszcze nie wiesz co oznacza zapis tab[], ale wane, aby pamita, e rednik postawiony dopiero na kocu trzeciej linii spowoduje, i kompilator poczy wszystkie wystpujce w kadej linii acuchy w jeden dugi. Teraz najwaniejsza rzecz: jakiego typu s stae typu C-string? Rozpatrzmy to na kolejnym krciutkim przykadzie:
Procesor

Bdzie typem const char[9]. Zapewne zdziwi ciebie bardzo skd wzia si tutaj liczba 9, skoro nasz acuch ma tylko 8 znakw? Ju wyjaniam. Rzeczywicie tekst w cudzysowach posiada tylko 8 znakw, jednak po nich zgodnie ze standardem C-string, musi wystpi znak null (fizycznie liczba zero). Zatem cznie taki string musi zawiera 9 znakw. Oczywicie, jeli wpiszemy inny tekst, to zawsze w nawiasie kwadratowym pojawi si liczba znakw tekstu plus jeden. Mam nadziej, e pamitasz, i specyfikator const mwi o tym, i zmienna taka nie moe by pniej w kodzie w aden sposb modyfikowana. Jeli sprbujesz tego dokona, to kompilator wywietli bd i uniemoliwi przeprowadzenie kompilacji. Oznacza to tak naprawd, e kompilator musi gdzie umieci w pamici takie stae. Zarezerwowa na nie miejsce. Mamy oczywicie moliwo zdecydowania, w jakiej pamici stae te maj by umieszczone. Jednak odpowiednie specyfikatory wskazujce na pami FLASH, pami RAM lub EEPROM poznamy pniej. Wane jest, e raz zarezerwowany obszar na dowoln sta nie moe by w pniejszym terminie zmieniany przez program. Std specyfikator const.

Mikrokontrolery AVR, jzyk C, podstawy programowania

Niniejsza darmowa publikacja zawiera jedynie fragment penej wersji caej publikacji.

Aby przeczyta ten tytu w penej wersji kliknij tutaj.


Niniejsza publikacja moe by kopiowana, oraz dowolnie rozprowadzana tylko i wycznie w formie dostarczonej przez Wydawnictwo ATNEL. Zabronione s jakiekolwiek zmiany w zawartoci publikacji bez pisemnej zgody Wydawnictwa ATNEL - wydawcy niniejszej publikacji. Zabrania si jej odsprzeday.

Pena wersja niniejszej publikacji jest do nabycia w sklepie internetowym

http://witmir.pl

Vous aimerez peut-être aussi