plik


ÿþXYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 1 of 38 ArtykuB pochodzi ze strony XYZ HOBBY ROBOT (xyz.isgreat.org) Kurs AVR-GCC cz.3 17.03.2009 ABXYZ W poprzedniej cz[ci kursu obja[niaBem jak programowa równolegBe porty we/wy ukBadów AVR, bo porty równolegBe to najprostszy i podstawowy sposób komunikacji mikrokontrolera z otoczeniem. W tej i dwóch kolejnych cz[ciach kursu postaram si przedstawi podstawy jzyka C, oczywi[cie w du|ym skrócie, gdy| trudno byBoby opisa szczegóBowo caBo[ jzyka C w trzech krótkich artykuBach. Ale nie ma si czego obawia, na szcz[cie jzyk C nie jest zbyt obszerny, szybko mo|na opanowa jego postawy, które pozwol samodzielnie pisa programy. Tematem tej cz[ci kursu bd: zmienne i staBe liczbowe, operatory oraz instrukcje sterujce. Wpierw omówi kolejno wymienione tematy, a dalej, jako wiczenie, uruchomimy kilka przykBadowych programów. Zmienne i typy danych ZakBadam, |e nie ma potrzeby obja[nia czym s zmienne w programie, wiadomo, zmienne przechowuj dane. Ka|da zmienna posiada wBasn nazw (identyfikator) oraz przypisany jeden z dostpnych w jzyku C typów. Typ zmiennej okre[la rodzaj przechowywanej danej, np. znak, liczba caBkowita, liczba rzeczywista oraz wielko[ obszaru pamici zajmowanego przez zmienn, np. 8, 16, 32 bity. Podstawowe typy danych w jzyku C to: " char - jeden znak (8-bitowa liczba caBkowita); " int - liczba caBkowita; " short int - liczba caBkowita krótka; " long int - liczba caBkowita dBuga; " long long int - liczba caBkowita bardzo dBuga; " float - liczba rzeczywista (typ zmiennopozycyjny); " double - typ zmiennopozycyjny podwójnej precyzji; " long double - typ zmiennopozycyjny rozszerzonej precyzji. W jzyku C nale|y ka|d zmienn przed u|yciem zdefiniowa, definicj zmiennej mo|na rozumie jako tworzenie zmiennej. Zmienne definiuje si wpisujc w linii typ zmiennej, a po nim nazw zmiennej lub nazwy kilku zmiennych rozdzielone przecinkami; definicj koDczymy [rednikiem. Definiujc zmienn mo|na jednocze[nie j zainicjowa umieszczajc zaraz po nazwie zmiennej znak "=", a po nim warto[ pocztkow dla zmiennej. Znaczenie ma miejsce definicji zmiennych, dokBadnie obja[ni to przy temacie funkcji. W programach z tej cz[ci kursu bdziemy definiowa zmienne na pocztku funkcji main. PrzykBady: int main(void) { /* Definicja zmiennej 'temperatura' typu char */ http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 2 of 38 char temperatura; /* Definicja zmiennej 'wysoko[' typu unsigned int */ unsigned int wysokosc; /* Definicja z inicjacj zmiennej 'napicie' typu float */ float napiecie = 3.36; /* Definicja z inicjacj zmiennej 'prdko[' typu int */ int predkosc = 0; /* Definicja trzech zmiennych typu unsigned char */ unsigned char bieg, poziom = 1, stan; Nazwy zmiennych mog skBada si z liter, z cyfr i znaku "_", ale nie mog zaczyna si od cyfry; wielko[ liter ma znaczenie, np. "temp" i "Temp" to dwie ró|ne zmienne. Nie mo|na u|ywa w nazwach zmiennych polskich liter: BDó[z| ACÓZy{. W nazwach typów: short int, long int, long long int mo|na pomin sBówko int, np. typ long oznacza typ long int. Dodajc przed nazw typu caBkowitego sBówko signed(unsigned) informujemy kompilator, |e powinien traktowa warto[ci w zmiennej jako liczby ze znakiem (bez znaku). Liczby ze znakiem (signed) zapisywane s na bitach w kodzie uzupeBnieD do dwóch U2(two's complement). Zale|nie od u|ywanego kompilatora jzyka C, rozmiary poszczególnych typów zmiennych mog si ró|ni. PrzykBadowo na procesorach 16-bitowych typ caBkowity int zwykle ma rozmiar 16 bitów, na procesorach 32-bitowych - 32 bity. W przypadku mikroprocesorów 8-bitowych typ int ma zwykle rozmiar 16 bitów, tak te| jest w AVR-GCC; zgodnie ze standardem jzyka C typ int nie mo|e mie mniej ni| 16 bitów. W AVR-GCC zmienne wszystkich typów zmiennopozycyjnych: float, double, long double kodowane s na 32 bitach, czyli faktycznie jest dostpny jedynie typ zmiennopozycyjny pojedynczej precyzji (zgodny ze standardem IEEE754). Zapewne wynika to z faktu, |e operacje na liczbach zmiennopozycyjnych wikszej precyzji byByby zbyt du|ym obci|eniem dla 8-bitowych mikroprocesorów. W tabeli poni|ej wypisaBem rozmiary podstawowych typów zmiennych w kompilatorze AVR-GCC. Rozmiar Warto[ Warto[ Typ (bitów) minimalna maksymalna char 8 signed char 8 -128 127 unsigned char 8 0 255 short int 16 -32768 32767 unsigned short 16 0 65535 int int 16 -32768 32767 unsigned int 16 0 65535 long int 32 -231 231-1 unsigned long 32 0 232-1 int long long int 64 -263 263-1 unsigned long 64 0 264-1 long int http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 3 of 38 Rozmiar Warto[ Warto[ Typ (bitów) minimalna maksymalna float 32 ±1.18·10-38 ±3.4·1038 double 32 ±1.18·10-38 ±3.4·1038 long double 32 ±1.18·10-38 ±3.4·1038 Podstawowe typy zmiennych w C, rozmiary typów w kompilatorze AVR-GCC W jzyku C nie istnieje specjalny typ zmiennych dla warto[ci logicznych, zwyczajnie je[li warto[ jakiej[ zmiennej równa si zeru, to zmienna posiada warto[ logiczn FAASZ, w przeciwnym przypadku zmienna posiada warto[ logiczn PRAWDA. PrzykBad: if( jakas_zmienna ) { /* Instrukcje wykonywane je[li zawarto[ zmiennej "jakas_zmienna" bdzie ró|na od zera */ } Ogólna zasada. W jzyku C je[li warto[ liczbowa staBej, zmiennej lub dowolnego wyra|enia jest ró|na od zera, wtedy staBa, zmienna, wyra|enie ma warto[ logiczn PRAWDA, w przeciwnym przypadku ma warto[ logiczn FAASZ. Chwilowo tyle informacji o zmiennych wystarczy. StaBe liczbowe W programie mo|na u|ywa staBych liczbowych caBkowitych w postaci dziesitnej, szesnastkowej i ósemkowej; mo|na te| u|ywa staBych typu zmiennopozycyjnego. Posta szesnastkow tworzymy wstawiajc przed liczb par znaków 0x lub 0X (np. 0xFF); staBe ósemkowe rozpoczynaj si od cyfry 0 (np. 077); a staBe caBkowite w systemie dziesitkowym piszemy zwyczajnie (np. 123). StaBe zmiennopozycyjne zawieraj dziesitn kropk (np. 3.14), mog te| zawiera wykBadnik (np. 123.45E3= 123450) Domy[lnie staBe caBkowite s typu int, je[li warto[ staBej nie mie[ci si w typie int, wtedy staBa otrzymuje typ long int lub long long int. Mo|na nadawa staBym typ long int dopisujc na ich koDcu liter L lub l; a dopisujc litery LL lub ll, typ long long int. Podobnie dopisujc na koDcu staBych caBkowitych liter U lub u mo|na nada staBym typ bez znaku. StaBe zmiennopozycyjne s domy[lnie typu double. Dopisujc na koDcu staBych zmiennopozycyjnych literk F lub f mo|na nada im typ float; a dopisujc literk L lub l mo|na nada typ long double. PrzykBady: /* staBa 0xff jest typu int */ DDRD = 0xff; /* staBa 255 jest typu int */ PORTD = 255; /* staBa 12345U jest typu unsigned int */ uz = 12345U; /* staBa 12.0 jest typu double */ liczba = 12.0; /* staBa 123456L jest typu long int */ 123456L * zy; http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 4 of 38 /* staBa -1UL jest typu unsigned long int */ zz = -1UL; /* staBa 3.17f jest typu float */ 3.17f * yz; Rejestry I/O A czym s nazwy rejestrów I/O, jak np.: PORTB, PINB, DDRB ? Przecie| jzyk C nic nie wie o rejestrach mikrokontrolerów AVR. W poprzedniej cz[ci napisaBem kilka sBów na temat preprocesora jzyka C, który mo|e wykonywa ró|ne operacje na tek[cie zródBowym programu jeszcze przed wBa[ciw kompilacj. To wBa[nie preprocesor, przed kompilacj, zmienia w tek[cie programu nazwy rejestrów I/O na wBa[ciwy kod w jzyku C; na przykBad instrukcja: PORTB = 0x02; zostanie zmieniona przez preprocesor na kod: (*(volatile uint8_t *)((0x18) + 0x20)) = 0x02; Ale tylko, je[li doBczy si do kodu programu pliki z definicjami rejestrów I/O, wstawiajc gdzie[ na pocztku programu lini: #include <avr/io.h> A co oznacza ten fragment kodu ? Rejestry I/O ukBadów AVR ulokowane s w przestrzeni adresowej pamici danych, zaczynajc od adresu 0x20, rejestr PORTB mie[ci si pod numerem 0x18 wzgldem adresu 0x20 (patrz datasheet AVR-a) W AVR-GCC dostp do rejestrów I/O jest za po[rednictwem wskaznika do zmiennej typu uint8_t (unsigned char). Je[li ostatnie dwa zdania s niezrozumiaBe, to absolutnie prosz si tym nie przejmowa i czyta dalej. Z tego trzeba zapamita, |e rejestry IO, jak na przykBad: PORTB, PINB, DDRB, posiadaj typ "unsigned char". Kodowanie U2. Liczby caBkowite ze znakiem (signed) zapisywane s w pamici w kodzie uzupeBnieD do dwóch U2 (two's complement), liczby bez znaku (unsigned) w naturalnym kodzie binarnym NKB. Prosz spojrze na wzory i tablice. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 5 of 38 bity warto[ci w kodzie NKB warto[ci w kodzie U2 0000 0 0 0001 1 1 0010 2 2 0011 3 3 0100 4 4 0101 5 5 0110 6 6 0111 7 7 1000 8 -8 1001 9 -7 1010 10 -6 1011 11 -5 1100 12 -4 1101 13 -3 1110 14 -2 1111 15 -1 Kodowanie liczb na 4 bitach http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 6 of 38 Kodowanie U2 na 4 bitach. Na kole lepiej wida ni| w tabelce. bity warto[ci w kodzie NKB warto[ci w kodzie U2 0000 0000 0 0 0000 0001 1 1 0000 0010 2 2 0000 0011 3 3 : : : 0111 1101 125 125 0111 1110 126 126 0111 1111 127 127 1000 0000 128 -128 1000 0001 129 -127 1000 0010 130 -126 : : : 1111 1101 253 -3 1111 1110 254 -2 1111 1111 255 -1 Kodowanie liczb na 8 bitach W naturalnym kodzie binarnym na n bitach mo|na zapisa warto[ci z zakresu [0,2n-1]; czyli dla 4 bitów [0,15], dla 8 bitów [0,255], dla 16 bitów [0,65535]. Natomiast w kodzie U2 na n bitach mo|na zapisa warto[ci z zakresu [-2n-1,2n-1-1]; czyli dla 4 bitów [-8,7], dla 8 bitów [- 128 ,127], dla 16 bitów [-32768,32767]. W kodzie U2 najstarszy(pierwszy od lewej) bit liczby mówi o znaku, dla zera i warto[ci dodatnich najstarszy bit jest zerem, dla warto[ci ujemnych - jedynk. Aby zmieni znak liczby zapisanej w kodzie U2 mo|na "odwróci" warto[ci wszystkich bitów liczby (jedynki zmieni na zera, a zera na jedynki) i do uzyskanej warto[ci doda jeden. ~ 0001 0011 (19) 1110 1100 + 0000 0001 http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 7 of 38 ----------------- 1110 1101 (-19) ~ 1110 1101 (-19) 0001 0010 + 0000 0001 ----------------- 0001 0011 (19) Przy dodawania/odejmowania liczb zapisanych w kodzie U2 przeprowadza si jednakowe operacje na bitach jak przy dodawaniu/odejmowaniu liczb zapisanych w NKB. Operatory przypisania Now warto[ mo|na zapisa w zmiennej u|ywajc operatora przypisania "="; instrukcj przypisania nale|y zakoDczy [rednikiem. PrzykBady: int main(void) { /* definicja zmiennych */ unsigned int wynik; unsigned char a,b; /* Zapisuje w zmiennej 'a' zawarto[ rejestru PINC */ a = PINC; /* Zapisuje w zmiennej 'b' zawarto[ rejestru PIND */ b = PIND; /* Oblicza i zapisuje w zmiennej 'wynik' warto[ wyra|enia a*b+312 */ wynik = a * b + 312; /* Do PORTA traf bity 0..7 zmiennej 'wynik' */ PORTA = wynik; /* Do PORTB traf bity 8..15 zmiennej 'wynik' */ PORTB = wynik >> 8 ; Ta sama zmienna mo|e sta po obu stronach operatora przypisania, przykBad: h = h + 10; Nowicjuszom w programowaniu taki zapis mo|e si wyda dziwny. Ale jest to instrukcja przypisania a nie równanie; w tym przykBadzie w zmiennej h zostanie zapisana nowa warto[, która jest równa aktualnej warto[ci tej zmiennej powikszonej o 10. Tutaj lepiej byBoby posBu|y si operatorem przypisania +=, przykBad: /* Zawarto[ zmiennej 'h' zostanie zwikszona o 10 */ h += 10; Obok operatora += s do dyspozycji podobnie dziaBajce operatory przypisania: -=, *=, /=, %=, ^=, |=, &=, <<=, >>=. a -= 17; // a = a - 17 a *= 2; // a = a * 2 a /= 4; // a = a / 4 a %= 4; // a = a % 4 http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 8 of 38 a ^= 0xaaaa; // a = a ^ 0xaaaa a |= 0x5555; // a = a | 0x5555 a &= 0xaaaa; // a = a & 0xaaaa a <<= 8; // a = a << 8 a >>= 4; // a = a >> 4 Operatory arytmetyczne W jzyku C istniej operatory arytmetyczne: + dodawania - odejmowania * mno|enia / dzielenia % dzielenia modulo (reszta z dzielenia caBkowitego) Je[li oba argumenty operatora dzielenia / bd typu caBkowitego, wtedy wynik operacji dzielenia bdzie typu caBkowitego i cz[ uBamkowa wyniku bdzie tracona. Reszt z dzielenia liczb caBkowitych mo|na wyliczy posBugujc si operatorem % (dzielenia modulo). Inaczej jest, je[li dzielna lub dzielnik albo oba argumenty operatora dzielenia / bd typu zmiennopozycyjnego (float, double), wtedy wynik dzielenia tak|e bdzie typu zmiennopozycyjnego. PrzykBady: int reszta, x; double wynik; x = 15; /* Zmienna 'wynik' bdzie zawiera warto[ 7 */ wynik = x / 2; /* W zmiennej 'reszta' bdzie 1 */ reszta = x % 2; /* W zmiennej 'wynik' bdzie 7.5, bo staBa 2.0 jest typu double */ wynik = x / 2.0; Istniej jeszcze jednoargumentowe operatory + , -, sBu|ce do zmiany znaku liczb; jednoargumentowy plus wBa[ciwie nic nie robi, jest tylko do pary :). int a, b; a = 15; /* now warto[ci zmiennej 'b' bdzie -15 */ b = - a ; Operatory zwikszania i zmiejszania. W jzyku C istniej operatory zwikszajce lub zmniejszajce o jeden warto[ci zmiennych. ++ zwiksz -- zmniejsz http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 9 of 38 Sposób dziaBania tych operatorów zale|y od tego, czy ++(--) znajduj si po lewej, czy po prawej stronie zmiennej. Je[li operator ++(--) stoi po lewej stronie zmiennej, warto[ zmiennej zwiksza (zmniejsza) si o jeden przed u|yciem warto[ci zmiennej. Je[li operator ++(--) stoi po prawej stronie zmiennej, warto[ zmiennej zwiksza(zmniejsza) si o jeden po u|yciu warto[ci tej zmiennej. PrzykBady: int a, b; b = 5; /* 'a' i 'b' bd równe 6 */ a = ++b ; /* 'a' bdzie równe 6, 'b' bdzie równe 7 */ a = b++ ; /* 'a' i 'b' bd równe 6 */ a = --b ; /* 'a' bdzie równe 6, 'b' bdzie równe 5 */ a = b-- ; Operatory logiczne, relacji i porównania W jzyku C dostpne s operatory relacji: > wikszy >= wikszy równy < mniejszy <= mniejszy równy Operatory przyrównania: == równy != ró|ny Operatory logiczne: && AND || OR ! operator negacji Wynikiem dziaBania operatorów: relacji, przyrównania i logicznych s warto[ci liczbowe: 0 - gdy faBsz, 1 - gdy prawda. W jzyku C warto[ liczbowa 0 oznacza jednocze[nie warto[ logiczn FAASZ, a warto[ 1 i ka|da inna warto[ liczbowa ró|na od zera oznacza warto[ logiczn PRAWDA int a, b, c, d; a = 3; b = 5; c = 0; /* w zmiennej 'd' zostanie zapisana warto[ 0 */ d = a == b ; /* w zmiennej 'd' bdzie 1 */ d = a != b ; /* w zmiennej 'd' bdzie 1 */ http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 10 of 38 d = a < b ; /* w zmiennej 'd' bdzie 0 */ d = a > b ; /* w zmienne 'd' bdzie 1 */ d = a && b ; /* w zmiennej 'd' bdzie 0 */ d = a && c ; /* w zmiennej 'd' bdzie 1 */ d = a || c ; /* w zmiennej 'd' bdzie 0 */ d = 0 || c ; /* w zmiennej 'd' bdzie 1 */ d = !0; int a, b; a = 2; /* w 'b' bdzie 1 */ b = -3 < a && a <= 3; /* w 'b' bdzie 0 */ b = a <= -3 || a > 3; /* teraz w 'b' bdzie !0 czyli 1 */ b = !(a <= -3 || a > 3); Opisane w tym punkcie operatory zwykle wykorzystuje si w instrukcjach z warunkiem, jak np. if-else, while, for. int a, b; if( a == b ) { /* Instrukcje do wykonania je[li a' jest równe 'b' */ } int a, b; while( a > b ) { /* Instrukcje które bd si wykonywa wielokrotnie w ptli dopóki 'a' jest wiksze od 'b' */ } Szczególnie nale|y uwa|a, by zamiast operatora przyrównania == nie wpisa operatora przypisania = . Operatory bitowe W jzyku C istnieje sze[ operatorów bitowych: | bitowe OR & bitowe AND ^ bitowe XOR >> przesunicie w prawo << przesunicie w lewo ~ dopeBnienie jednykowe Operacje bitowe dziaBaj na warto[ciach caBkowitych i sBu| do manipulowania bitami, wic s szczególnie u|yteczne przy programowaniu sprztu - przy zabawie z bitami rejestrów I/O. Operatory bitowe & i | mog si myli z opisanymi wcze[niej operatorami logicznymi && i ||, dlatego szczegóBowo, na http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 11 of 38 przykBadach, wyja[ni ró|nice w dziaBaniu operatorów bitowych i logicznych. W poni|szych przykBadach liczby wypisane s w postaci dwójkowej. operator bitowy "|" - alternatywa (OR) 0 1 0 1 0 1 0 1 | 0 0 1 1 0 0 1 1 = 0 1 1 1 0 1 1 1 operator logiczny OR "||" 0 1 0 1 0 1 0 1(PRAWDA bo warto[ ró|na od zera) | 0 0 1 1 0 0 1 1(PRAWDA) = 0 0 0 0 0 0 0 1(PRAWDA) operator "&" - bitowa koniunkcja (AND) 0 1 0 1 0 1 0 1 & 0 0 1 1 0 0 1 1 = 0 0 0 1 0 0 0 1 operator logiczny AND "&&" 0 1 0 1 0 1 0 1(PRAWDA) & 0 0 1 1 0 0 1 1(PRAWDA) = 0 0 0 0 0 0 0 1(PRAWDA) operator "~" - dopeBnienie jedynkowe ~ 1 0 0 1 1 0 0 1 = 0 1 1 0 0 1 1 0 operator logiczny negacja "!" ! 1 0 0 1 1 0 0 1(PRAWDA) = 0 0 0 0 0 0 0 0(FAASZ) operator "^" - bitowa alternatywa wykluczajca (XOR) 0 1 0 1 0 1 0 1 ^ 0 0 1 1 0 0 1 1 = 0 1 1 0 0 1 1 0 operator "<<" - przesunicie w lewo 1 0 0 1 1 0 0 1 << 3 = 1 1 0 0 1 0 0 0 operator ">>" - przesunicie w prawo liczby bez znaku (unsigned) 1 0 0 1 1 0 0 1 >> 5 = 0 0 0 0 0 1 0 0 liczby ze znakiem (signed) 1 0 0 1 1 0 0 1 >> 5 = 1 1 1 1 1 1 0 0 Prosz zauwa|y |e, przesuwajc bity liczby o jedn pozycj w lewo mno|ymy warto[ liczby razy dwa; a przesuwajc o jedno pozycj w prawo, dzielimy liczb przez dwa. Je[li trzeba mno|y(dzieli) liczby caBkowite razy(przez) 2,4,8,2n, to mo|na przesuwa bity. A http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 12 of 38 po co? Przecie| s operatory arytmetyczne mno|enia i dzielenia: *, /. Na przykBad, |eby zoptymalizowa program pod ktem szybko[ci. Przesuwanie bitów liczby jest o wiele prostsz operacj w porównaniu z mno|eniem i dzieleniem. Dla 8 bitowych mikroprocesorów operacje mno|enia i dzielenia mog by znaczcym obci|eniem. 2 * 2 = 4 00000010 << 1 = 00000100 3 * 4 = 12 00000011 << 2 = 00001100 9 * 8 = 72 00001001 << 3 = 01001000 67 / 16 = 4 (dzielenie caBkowite) 01000011 >> 4 = 00000100 W liczbach ze znakiem(signed) najstarszy bit decyduje o znaku, wic w operacji przesuwania bitów w prawo liczb ze znakiem najstarszy bit pozostanie bez zmian. W przypadku przesuwania w prawo liczb bez znaku(unsigned) najstarszy bit otrzymuje warto[ 0. PrzykBad: Przesuwanie w prawo bitów liczb ze znakiem 85 / 8 = 10 01010101 >> 3 = 00001010 -125 / 16 = -8 10000011 >> 4 = 11111000 Trójargumentowy operator warunkowy. Trójargumentowy operator warunkowy ?: ma posta: wyr1 ? wyr2 : wyr3 I dziaBa w nastpujcy sposób: Je[li warto[ wyra|enia wyr1 ró|ni si od zera (logiczna warto[ PRAWDA), wtedy zwraca warto[ wyra|enia wyr2 (caBo[ jest równa warto[ci wyr2), w przeciwnym razie zwraca warto[ wyr3. PrzykBady: int a, b, c; /* Je[li 'b' jest równe 7, w zmiennej 'a' zostanie zapisana warto[ zmiennej 'c', w przeciwnym razie w 'a' zostanie zapisana warto[ wyra|enia c+3 */ a = (b == 07) ? c : c + 3; /* Je[li bit nr 2 w rejestrze PINC jest równy 1, w rejestrze PORTB bit nr 0 otrzyma warto[ 1, w przeciwnym razie ustawiony zostanie bit nr 7 */ PORTB |= (PINC & 0x04) ? 0x01 : 0x80; W przykBadach warunek umieszczony jest w okrgBych nawiasach, podobnie jak w instrukcji if-else, nie jest to konieczne, ale poprawia czytelno[ kodu. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 13 of 38 Priorytety i Bczno[ operatorów Priorytety i Bczno[ operatorów decyduj o kolejno[ci wykonywania operacji przy obliczaniu warto[ci wyra|eD PrzykBadowo, operacje mno|enia i dzielenia maj wy|szy priorytet ni| dodawanie i odejmowanie (tak, jak w matematyce), a operatory przypisania maj ni|szy priorytet ni| wikszo[ operatorów; wic w poni|szym przykBadzie wpierw wykona si mno|enie, nastpnie dodawanie i na koDcu obliczona warto[ wyra|enia zostanie zapisana w zmiennej 'wynik'. wynik = a + b * 2; Kolejno[ci wykonywanych dziaBaD mo|na sterowa u|ywajc okrgBych nawiasów (jak w matematyce). wynik = (a + b) * 2; W tabelce poni|ej zestawione zostaBy wszystkie operatory jzyka C wedBug malejcych priorytetów. Operatory w jednym wierszu tabelki maj ten sam piorytet. Uwaga, w jzyku C jeden symbol (np.: +, -, *, &) mo|e oznacza dwa ró|ne operatory, zale|nie od kontekstu. Czytajc tabelk nale|y wiedzie, |e jednoargumentowe operatory zmiany znaku: + , - posiadaj wy|szy priorytet ni| dwuargumentowe operatory dodawania i odejmowania. Podobnie jednoargumentowe operatory & (adres obiektu) i * (dostp za po[rednictwem wskaznika) maj wy|szy priorytet ni| dwuargumentowe operatory & (bitowe AND) i * (mno|enie). Operatory Aczno[ () [] -> . lewostronna ! ~ ++ -- + - * & (typ) sizeof prawostronna * / % lewostronna + - lewostronna << >> lewostronna <= < > >= lewostronna == != lewostronna & lewostronna ^ lewostronna | lewostronna && lewostronna || lewostronna ?: lewostronna = += -= *= /= %= ^= &= |= <<= >>= prawostronna , lewostronna Priorytety i Bczno[ operatorów Prawostronna Bczno[ operatorów jednoargumentowych mówi, |e argument stoi po prawej stronie operatora. PrzykBad: ~ 0x01; ! a http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 14 of 38 Lewostronna (prawostronna) Bczno[ dwuargumentowych operatorów oznacza, |e je|eli w wyra|eniu wystpuje wicej ni| jeden operatorów o jednakowych priorytetach, wtedy wpierw wykonywany jest ten najbardziej z lewej(prawej). Na przykBad operatory mno|enia(*), dzielenia(/) i operator obliczania reszty z dzielenia(%) maj jednakowy priorytet i s lewostronnie Bczne, wic wyra|enie poni|ej: 36 / 3 * 2 % 4 jest równoznaczne wyra|eniu: ((36 / 3) * 2) / 4 Z kolei operatory przypisania s prawostronnie Bczne i na przykBad instrukcja w postaci: a = b = c = d ; jest równowa|na instrukcji a = (b = (c = d)); Warto z tego zapamita, |e caBe wyra|enie przypisania, jak np: c = 1; te| posiada warto[ liczbow, równ warto[ci argumentu stojcego po prawej stronie operatora przypisania. Instrukcje wyboru Instrukcj wyboru if-else u|ywali[my ju| w przykBadach z poprzedniej cz[ci kursu, if-else ma posta: if( wyra|enie ) instrukcja_uruchamiana_je[li_wyra|enie_jest_ró|ne_od_zera; else instrukcja_uruchamiana_je[li_wyra|enie_jest_równe_zero; /* LUB */ if( wyra|enie ) { /* Instrukcje wykonywane je[li warto[ wyra|enia jest ró|na od zera */ } else { /* Instrukcje wykonywane je[li warto[ wyra|enia jest równa zero */ } Instrukcja if-else sprawdza czy warunek jest speBniony, tzn. czy warto[ wyra|enia w nawiasach okrgBych po sBówku if jest ró|na od zera. Je[li tak, to zostanie wykonana instrukja znajdujca si zaraz za nawiasem ")"; w przeciwnym razie zostanie wykonana instrukcja po sBówku else, cz[ else mo|na pomin. Obejmujc fragment kodu par klamrowych nawiasów "{","}" tworzymy blok http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 15 of 38 instrukcji, blok w "if-else" jest traktowany jako pojedyncza instrukcja. PrzykBad: signed char a,b; /* Je[li warto[ zmiennej 'a' jest równa warto[ci zmiennej 'b', w rejestrze PORTA zostanie zapisana warto[ 0x01, w przeciwnym razie w PORTB zostanie zapisana warto[ 0x0F */ if(a==b) PORTA = 0x01; else PORTB = 0x0F; Je[li potrzebna jest instrukcja if-else, ale z wicej ni| dwoma wariantami kodu, to mo|na u|y dwóch lub wicej instrukcji if-else zagnie|d|onych kaskadowo, jak w przykBadzie poni|ej. signed char a; if( a <= 3 ) { /* Je[li 'a' jest mniejsze równe 3 */ } else if( a <= 7 ) { /* Je[li 'a' jest mniejsze od 7 */ } else if( a <= 9 ) { /* Je[li 'a' mniejsze równe od 9 */ } else { /* 'a' jest wiksze od 9 */ } Kolejna instrukcja wyboru switch ma posta: switch(wyra|enie) { case wyra|enie_staBe_1: /* Instrukcje - wariant 1*/ break; case wyra|enie_staBe_2: /* Instrukcje - wariant 2 */ break; case wyra|enie_staBe_3: /* Instrukcje - wariant 3 */ break; .................... case wyra|enie_staBe_n: /* Instrukcje - wariant n */ break; default: /* Instrukcje - je[li |aden z wcze[niejszych wariantów */ } Instrukcja switch dziaBa w nastpujcy sposób: Je[li wyra|enie w nawiasach okrgBych, po sBówku switch, jest równe warto[ci staBej po którym[ wystpieniu sBówka case, wtedy wykonuj si instrukcje wypisane po dwukropku, a| do wystpienia instrukcji break, która koDczy dziaBanie caBej instrukcji switch. Je[li brak instrukcji break, wtedy wykonane zostan instrukcje kolejnego wariantu, a| do momentu napotkania instrukcji break lub nawiasu klamrowego } koDczcego caB instrukcj switch. Je[li warto[ wyra|enia nie pasuje(nie równa si) do |adnej staBej, wtedy wykonuaj si http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 16 of 38 instrukcje po sBówku default, cz[ default mo|na w instrukcji switch pomin. PrzykBad: unsigned char a; switch(a) { case 3: /* Instrukcje wykonywane je[li 'a' równe jest 3 */ break; case 7: /* je[li a = 7 */ break; case 5: /* je[li a = 5 */ break; case 5 + 4: /* je[li a = 9 */ break; default: /* je[li |aden z wcze[niejszych wariantów */ } Kolejny przykBad u|ycia switch: switch(PINB & 0x07) { case 0x00: /* Instrukcje wykonywane je[li 0 */ case 0x01: /* je[li 0 lub 1 */ case 0x02: /* je[li 0 lub 1 lub 2 */ break; case 0x03: /* je[li 3 */ case 0x04: /* je[li 3 lub 4 */ default: /* je[li 3 lub 4 lub 5 lub 6 lub 7 */ } Instrukcje ptli W jzyku C ptle tworzy si instrukcjami: " while, " do-while, " for. Instrukcja while ma posta: while( wyra|enie ) instrukcja_w_ptli; /* LUB */ while( wyra|enie ) { /* Obejmujc fragment kodu par nawisów klamrowych { } tworzy si blok instrukcji, który jest traktowany jako pojedyncza instrukcja - instrukcja zBo|ona. */ } I dziaBa w nastpujcy sposób: 1. Oblicza warto[ wyra|enia w nawiasach okrgBych. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 17 of 38 2. Je[li warto[ liczbowa wyra|enia jest ró|na od zera, wykonuje instrukcje wewntrz ptli, po czym przechodzi do punkut 1; w przeciwnym przypadku dziaBanie instrukcji ptli jest zakoDczone. Instrukcja do-while ma posta: do instrukcja_w_ptli; while( wyra|enie ); /* LUB */ do { /* Instrukcje w ptli. */ } while( wyra|enie ); I dziaBa w nastpujcy sposób: 1. Wykonuje instrukcje wewntrz ptli. 2. Oblicza wyra|enie w nawisach okrgBych. Je[li warto[ liczbowa wyra|enia jest ró|na od zera, przechodzi do punkut 1; w przeciwnym przypadku dziaBanie instrukcji ptli jest zakoDczone. PrzykBady: /* Ptla nieskoDczona utworzona instrukcj 'while' */ while(1) { /* Instrukcje w nieskoDczonej ptli */ } int a; while( a <= 17 ) { /* Instrukcje które bd si wykonywa wielokrotnie w ptli dopóki 'a' bdzie mniejsze lub równe 17 */ } Instrukcja for ma posta: for(wyra|enie_1; wyra|enie_2; wyra|enie_3) instrukcja_w_ptli; /* LUB */ for(wyra|enie_1; wyra|enie_2; wyra|enie_3) { /* Instrukcje wykonywane w ptli */ } I dziaBa w nastpujcy sposób: 1. Oblicza wyra|enie_1. 2. Oblicza wyra|enie_2. 3. Je[li warto[ liczbowa wyra|enia_2 jest ró|na od zera (warto[ logiczna PRAWDA), wykonuje instrukcj w ptli i przechodzi do punktu 4; w przeciwnym przypadku dziaBanie instrukcji ptli jest zakoDczone. 4. Oblicza wyra|enie_3 i przechodzi do punktu 2. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 18 of 38 Na przykBad, je[li jest potrzeba, |eby jaki[ fragment kodu wykonaB si okre[lon ilo[ razy, mo|na wtedy zbudowa ptl z u|yciem instrukcji for. unsigned char i; for(i = 0; i < 7; i++) { /* Instrukcje w ptli wykonane zostan 7 razy */ } W tym przykBadzie u|yto zmiennej "i" jako licznika iteracji ptli; przykBad dziaBa w nastpujcy sposób: 1. Zapisuje do zmiennej "i" warto[ 0. 2. Sprawdza czy warto[ w zmiennej "i" jest mniejsza od 7; je[li tak, przechodzi do nastpnego punktu, w przeciwnym wypadku koDczy dziaBanie ptli. 3. Wykonuje instrukcje w ptli. 4. Zwiksza warto[ w zmiennej "i" o jeden. 5. Przechodzi do punktu 2. Kolejny przykBad z instrukcj for. Instrukcje w ptli bd wykonywane dopóki warto[ zmiennej "i" bdzie mniejsza od warto[ci zmiennej "n" i jednocze[nie bit numer 2 rejestru PINC bdzie miaB warto[ 1. Zmienna "i" pracuje jako licznik iteracji ptli. unsigned char i, j, n=10; for(i=0, j=0; i < n && PINC & 04; i++, j+=i) { /* Instrukcje w ptli */ } DziaBanie instrukcji ptli: while, do-while i for mo|na wcze[niej zakoDczy u|ywajc instrukcji break, po "break" wstawiamy [rednik. PrzykBad: while(1) { /* Je[li w PINC bit nr 0 jest jedynk, to wy[cie z ptli */ if( PINC & 0x01) break; } Istnieje jeszcze instrukcja continue, która powoduje pominicie dalszych instrukcji w ptli i przej[cie do pocztku kolejnej iteracji ptli; po continue wstawiamy [rednik. unsigned char i; for(i = 0; i < 99; i++) { /* Instrukcje w ptli */ /* Je[li reszta z dzielenia warto[ci zmiennej 'i' przez 5 bdzie równa 0, dalsze instrukcje zostan pominite i nastpi przej[cie do pocztku kolejnej iteracji ptli. */ if(i % 5 == 0) continue; /* Dalsze instrukcje w ptli, pomijane, gdy zadziaBa 'continue' */ } http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 19 of 38 Z wielokrotnie zagnie|d|onej ptli, jak w przykBadzie poni|ej, porcznie jest "wyskoczy" wykorzystuj instrukcj goto. PrzykBad: unsigned char i, j; while(1) { for(i = 0; i < 7; i++) { for(j = 10; j >= 0; j--) { /* Je[li bit nr 2 w rejestrze PIND ma warto[ 1, to skok do etykiety 'dalej' */ if( PIND & 0x02) goto dalej; /* Dalsze instrukcje */ } { } /* etykieta 'dalej' */ dalej: /* Dalsza cz[ programu */ Instrukcja goto ma posta: goto nazwa_etykiety; . . . nazwa_etykiety: Po napotkaniu instrukcji goto nastpuje skok do miejsca w programie oznaczonego etykiet, etykiet powinna koDczy si dwukropkiem. Z pomoc instrukcji goto mo|na skaka w obrbie caBej funkcji, a nawet tworzy ptl. Jednak nadu|ywanie goto prowadzi to powstania nieczytelnych, zagmatwanych kodów, wic zaleca si u|ywania instrukcji goto tylko w tych sytuacjach, gdy w inny sposób nie da si tego napisa. Teoretycznie zawsze mo|na si obej[ bez u|ycia goto. PrzykBadowe programy PrzygotowaBem kilka przykBadowych programów, bardzo prostych i chyba zabawnych :) . Proponuje, jako wiczenie i zabaw, uruchomi wszystkie. Jak poprzednio, wszystkie te przykBadowe programy napisane s wedBug jednego, prostego schematu: CaBo[ algorytmu zapisana jest w funkcji 'main', wpierw wykonuj si instrukcje inicjujce (definicja zmiennych, konfiguracja portów we/wy itp.), a nastpnie program przechodzi do wykonania instrukcji umieszczonych w nieskoDczonej ptli - nazw j gBówn ptl programu. /* Szkielet prostego programu dla avr-gcc */ #define F_CPU 1000000L #include <avr/io.h> /* Je[li bd u|ywanie funkcje w rodzaju _delay_ms, _delay_us */ #include <util/delay.h> http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 20 of 38 int main(void) { /* Instrukcje - wstpne ustawienia, konfiguracje, inicjowanie itp. */ /* GBówna ptla programu */ while(1) { /* Instrukcje w ptli */ } } Schematy poBczeD W poprzedniej cz[ci kursu przykBady uruchamiane byBy na ukBadzie atmaga8, teraz, dla odmiany, bdziemy wykorzystywa mikrokontroler atmega16. Jak wida na ilustracji poni|ej, wybierajc ukBad atmega16, mamy do dyspozycji cztery 8 bitowe porty we/wy (A,B,C,D). Ale w fabrycznie nowym atmega16 domy[lnie jest wBczony interfejs JTAG i w tej konfiguracji nie mo|na wykorzystywa pinów PC2-PC5 jako cyfrowych wej[/wyj[. UkBad atmega16 http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 21 of 38 Schemat 3.1 - sposób przyBczenia do ukBadu atmega16 zasilania, resetu i zBcza programatora. Kliknij w obrazek, |eby powikszy. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 22 of 38 Schemat 3.2 - sposób przyBczenia do AVRa siedmiosegmentowego wy[wietlacza LED. Poszczególne segmenty LED wBczane s niskim stanem napicia na portach mikrokontrolera. Taki, bezpo[redni sposób przyBczenia wy[wietlacza nie jest najlepszym rozwizaniem (zale|aBo mi na maksymalnym uproszczeniu schematu). Przez porty AVRa mo|e przepBywa jedynie niewielki prd, a segmenty wy[wietlacza zwykle zu|ywaj znacznie wicej prdu ni| maBe diody LED, wic wy[wietlane cyfry mog by ledwie widoczne. Uwaga! W sprzeda|y spotka mo|na dwa rodzaje siedmiosegmentowych wy[wietlaczy led: o wspólnej anodzie i o wspólnej katodzie. Podobnie jak w poprzednio, bdziemy bawi si przyBczajc do portów mikrokontrolera diody LED, przyciski, przeBczniki, buzzer. Poprzednio mikrokontroler oraz wszystkie wykorzystywane elementy elektroniczne umieszczaBem na pBytce stykowej, lecz montowanie za ka|dym razem wszystkiego od nowa przy zmianie schematu okazaBo si by uci|liwe, wic zdecydowaBem dalej ukBada na pBytce stykowej jedynie mikrokontroler i ewentualnie inne ukBady scalone wspóBpracujce z mikrokontrolerem. A na osobnych, niewielkich kawaBkach pBytki drukowanej umie[ciBem takie czsto wykorzystywane cz[ci, jak: " osiem diod LED; " siedmiosegmentowy wskaznik LED; " cztery miniaturowe przyciski monostabilne; " buzer(z generatorem); " dwa przeBczniki typu piano dip switch 8; " stabilizator napicia 5V. A w dalszej cz[ci kursu, na osobnych pBytkach umieszczane bd klawiatura, ró|nego typu wy[wietlacze oraz inne ciekawsze podzespoBy. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 23 of 38 Osiem diod LED wraz z rezystorami ograniczajcymi prd wlutowaBem na osobnym kawaBku pBytki drukowanej. Diody bd przyBczane do wyprowadzeD mikrokontrolera na pBytce stykowej gitkimi przewodami; do koDców przewodów przylutowane s kawaBki drutu (odcite, fragmenty dBugich wyprowadzeD tranzystorów, rezystorów itp.) zabezpieczone przed oberwaniem elastyczn termokurczliw koszulk. WykorzystaBem gitkie przewody ze starego kabla do drukarki, przewody ze skrtki komputerowej, którymi robi poBczenia na pBytce stykowej, tutaj si nie nadaj, s zbyt sztywne. Siedmiosegmentowy wy[wietlacz LED - te| na osobnej pBytce. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 24 of 38 Przyciski na osobnej pBytce. PrzeBczniki typu dip piano 2*8 te| na osobnej pBytce. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 25 of 38 Buzzer z generatorem na osobnej pBytce Na osobnej pBytce stabilizator 5V http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 26 of 38 PrzyBczenie kilku diod LED, przycisków czy buzzera do dowolnych wyprowadzeD mikrokontrolera na pBytce stykowej zajmuje jedynie chwilk. Kliknij w obrazek, aby powikszy. PrzykBad pierwszy. 4 bitowy kalkulator. Program wykonuje podstawowe operacje arytmetyczne na czterobitowych liczbach ze znakiem. Warto uruchomi ten programik |eby powiczy kodowanie U2, je[li kto[ jeszcze nie jest w tym biegBy. Pierwsza liczba odczytywana jest z linii PD0..PD3, druga z PD4..PD7, wynik wy[wietlany jest na o[miu diodach LED przyBczonych do portu A. Rodzaj operacji wybiera si na liniach PB0..P3: 1-dodawanie, 2-odejmowanie, 3-mno|enie, 4-dzielenie caBkowite, 5-obliczanie reszty z dzielenia liczb caBkowitych. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 27 of 38 Ilustracja dziaBania programu "4 bitowy kalkulator". Dla wygody, do wej[ mikrokontrolera podBczyBem przeBczniki typu piano_dip_switch, które zwieraj poszczególne wej[cia uC z GND; oczywi[cie mo|na zwiera wej[cia uC na pBytce stykowej do masy zwyczajnie, przewodami. Osiem diod LED podBczone zostaBy do wyprowadzeD portu A atmega16 na sposób: VCC->R->LED- >PAx, czyli [wiec si gdy odpowiedni bit w rejestrze PORTA ma warto[ 0. UkBad do uruchomienia programu "4-bitowy kalkulator" zmontowany na pBytce stykowej. Kliknij w obrazek, aby powikszy. /* KURS AVRGCC, przykBad 031 4 bitowy kalkulator Progam wykonuje operacje artymetyczne (+,-,*,/) http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 28 of 38 na 4 bitowych liczbach ze znakiem. UkBad ATmega16 Wej[cia: PD..PD3 - pierwsza liczba, PD4..PD7 - druga liczba, PB0..PB3 - wybór operacji Wyj[cia PA0..PA7 - wynik operacji Do PA0..PA7 podBczone s diody LED na sposób: VCC->R->LED->PAx */ #include <avr/io.h> int main(void) { /* Definicja zmiennych */ signed char a,b; /* Wszystkie linie portu A wyj[ciami */ DDRA = 0xFF; /* Wszystkie linie portu D wej[ciami */ DDRD = 0x00; PORTD = 0XFF; /* PB0..PB3 wej[ciami z podcigniciem do Vcc */ DDRB = 0x00; PORTB = 0X0F; /* GBówna ptla programu */ while(1) { /* W zmiennej 'a' zapisuje bity 0..3 z rejestru PIND */ a = PIND & 0x0f; /* w zmiennej 'b' bity 4..7 */ b = PIND >> 4; /* Rozszerza 4 bitowe liczby ze znakiem do 8 bitów. Je[li bit nr 3 zmiennej 'a' ma warto[ 1, czyli odczytano liczb ujemn,to bity 4..7 zmiennej 'a' te| ustawiane s na warto[ 1 */ if(a & 0x08) a |= 0xf0; if(b & 0x08) b |= 0xf0; /* Wybiera rodzaj operacji odczytujc bity 0..3 portu B */ switch(PINB & 0x0f) { case 1: //dodaje //PORTA = a+b; // PAx->R->LED->GND PORTA = ~(a+b); // VCC->R->LED->PAx break; case 2: //odejmuje //PORTA = a-b; PORTA = ~(a-b); break; case 3: //mno|y //PORTA = a*b; PORTA = ~(a*b); break; case 4: //dzieli //PORTA = a/b; PORTA = ~(a/b); break; case 5: //oblicza reszt z dzielenia //PORTA = a%b; PORTA = ~(a%b); http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 29 of 38 break; default: // inne //PORTA = 0; PORTA = ~(0); } } } Listing 3.1 4-bitowy kalkulator PrzykBad 2. Sygnalizacja [wietlna Po prostu sygnalizacja [wietlna. Zwiec si kolejno [wiatBa: zielone, |óBte, czerwone, czerwone i |óBte , i ponownie zielone; a w przypadku podania na wyprowadzenie PD0 napicia GND, [wiatBo |óBte pulsujce. Ilustracja dziaBania programu "Sygnalizacja [wietlna". /* KURS AVRGCC przykBad 032 Sygnalizacja [wietlna ATmega16 1MHz Wyj[cia: PA0 - czerwone, PA1 - zóBte, PA2 - zielone Do PA0..PA2 podBczone s diody LED na sposób: VCC->R->LED->PAx wej[cia PD0 - GND na PD0 wBcza pulsujce |óBte */ #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> int main(void) { /* Deklaracja zmiennych */ unsigned char i; /* PA0..PA2 - wyj[cia */ DDRA = 0x07; PORTA = 0x07; /* PD0 wej[cie */ DDRD = 0x00; http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 30 of 38 PORTD = 0x01; /* GBówna ptla programu */ while(1) { /* Cztery fazy: zielone, |óBte, czerwone, czerwone_|óBte */ for (i= 1;i <= 4; i++) { /* Je[li na PD0 GND */ if(!(PIND & 0x01)) i = 0; /* Wybór jednego z 5 wariantów */ switch(i) { case 1: // Je[li i=1, zapala si zielone PORTA |= 0x03; // ustawia bity nr. 0,1 PORTA &= ~0x04; // kasuje bit nr. 2 _delay_ms(6000); // czeka 6 sekund break; case 2: // Je[li i=2, zóBte PORTA |= 0x05; // ustawia bity nr. 2,0 PORTA &= ~0x02; // kasuje bit nr. 1 _delay_ms(6000); // 6 sek break; case 3: // Je[li i=3, czerwone PORTA |= 0x06; // ustawia bity nr. 2,1 PORTA &= ~0x01; // kasuje bit nr. 0 _delay_ms(6000); break; case 4: // Je[li i=4, czerowne,zóBte PORTA |= 0x01; // ustawia bit nr. 0 PORTA &= ~0x03; // kasuje bity nr. 0,1 _delay_ms(6000); break; default: //w innym razie, |óBte pulsujce PORTA |= 0x07; // ustawia bity nr. 0,1,2 PORTA ^= 0x02; // odwraca bit nr. 1 _delay_ms(600); // 0.6 sek PORTA ^= 0x02; // odwraca bit nr. 1 _delay_ms(600); // 0.6 sek } } } } Listing 3.2 Synglizacja [wietlna PrzykBad 3. Elektroniczna ko[ do gry Elektroniczna ko[ do gry. Po wci[niciu i zwolnieniu przycisku na siedmio-segmentowym wy[wietlaczu LED pokazuj si cyfry: program liczy od 1 do losowo wybranej liczby z zakresu 1..6, animacja poni|ej. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 31 of 38 Ilustracja dziaBania programu "Elektroniczna ko[ do gry". /* Kurs AVRGCC, przykBad 033 Elektroniczna ko[ do gry ATmega16 1MHz Wyj[cia: PA0..PA7 - wy[wietlacz siedmiosegmentowy LED VCC->LED->R->PAx PB4 - buzzer z generatorem Wej[cia: PC0 - przycisk zwierajcy do GND */ #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> /* Instrukcje zaczynaj si znakiem hash "#", to polecenia preprocesora. Preprocesor jzyka C przeprowadza rozmaite operacje na tek[cie programu jeszcze przed rozpoczciem wBa[ciwej kompilacji programu. PrzykBadowo pierwsze z poni|szych poleceD zmienia w tek[cie programu wszystkie wystpienia cigu znaków LED_1 na 0x06, identycznie jak opcja "replace" w edytorze teksu. */ // -- A -- // | | // F B // | | // -- G -- // | | // E C // | | // -- D -- #define LED_1 0x06; // 0000 0110 #define LED_2 0x5b; // 0101 1011 #define LED_3 0x4f; // 0100 1111 #define LED_4 0x66; // 0110 0110 #define LED_5 0x6d; // 0110 1101 #define LED_6 0x7d; // 0111 1101 int main(void) { http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 32 of 38 /* Definicja zmiennych */ unsigned char i,n,l; /* Port A - wyj[cia */ DDRA = 0xFF; PORTA = 0xFF; /* PC0 - wej[cie z podcigniciem do VCC */ DDRC = 0x00; PORTC = 0X01; /* PB4 - Wyj[cie */ DDRB = 0x10; PORTB = 0x00; /* GBówna ptla programu*/ while(1) { /* Czeka na wci[nicie przycisku */ /* Zmienna 'l' posBu|y do uzyskania liczb losowych */ while(PINC & 0x01) ++l; /* Czas na wyga[nicie drgaD styków przycisku */ _delay_ms(140); /* Czeka na zwolnienie przycisku*/ while(!(PINC & 0x01)) l+=2; /* Czas na wyga[nicie drgaD styków przycisku */ _delay_ms(140); /* Pozyskanie liczby losowej z zakresu 1..6 */ n = l % 6 + 1; /* Liczy od 1 do n */ for(i=1; i <= n; i++) { /* Wybór jednej z sze[ciu mo|liwo[ci */ switch(i) { case 1: /* Wy[wietla cyfr 1. Uwaga, poszczególne segmenty LED wy[wietlacza [wiec si przy niskim stanie napicia na portach uC, dlatego u|yto tu operatora "~" */ PORTA = ~LED_1 break; case 2: PORTA = ~LED_2; // wy[wietli 2 break; case 3: PORTA = ~LED_3; // 3 break; case 4: PORTA = ~LED_4; // 4 break; case 5: PORTA = ~LED_5; // 5 break; case 6: PORTA = ~LED_6; // 6 } /* Krótki sygnaB dzwikowy */ PORTB |= 0X10; // WBcza buzzer _delay_ms(50); PORTB &= ~0X10; // WyBcza buzzer _delay_ms(450); } } } Listing 3.3 Elektroniczna ko[ do gry. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 33 of 38 PrzykBad 4. Kogut policyjny Program steruje nat|eniem [wiecenia dwóch kolorowych |aróweczek, powstaje efekt przypominajcy [wiatBo policyjnego koguta, animacja poni|ej. Tym razem, dla wikszego efektu, zamiast diód LED, zastosowaBem |aróweczki od latarki (4,5V 0.3A) przyBczone do portów we/wy mikrokontrolera za po[rednictwem ukBadu scalonego ULN2803A. {arówki zasilane s napiciem impulsowym (PWM), program zmieniajc szeroko[ impulsu steruje nat|eniem [wiecenia |aróweczek. Programik nie dziaBa caBkiem zgodnie z oczekiwaniem, lampki nie gasn caBkowicie, gdy powinny, po prostu mikroprocesor atmega 1MHz jest zbyt wolny od tego kodu. SygnaB PWM lepiej generowa sprztowo wykorzystujc ukBady czasowe mikrokrokotrolera albo pisa w asemblerze, oczywi[cie bdziemy si tym tematem w dalszej cz[ci kursu. Ilustracja dziaBania programu "Kogut policyjny". /* Kurs AVRGCC, przykBad 034 Kogut policyjny Do linii PA0,PA1, za po[rednictwem ukBadu ULN2803A, przyBczone s dwie kolorowe |aróweczki (4,5V 0.3A). {arówki zasilane s napiciem impulsowym (ok 1KHz), program, sterujc szeroko[ci impulsów zmienia pBynnie nat|eniem [wiatBa |aróweczek. ATmega16 1MHz Wyj[cia: PA0,PA1 */ #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> int main(void) { /* Definicja zmiennych */ int t; /* P0,P1 - wyj[cia */ DDRA = 0x03; PORTA = 0x00; /* GBówna ptla */ while(1) { /* Pierwsza lampka stopniowo rozja[nia si, http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 34 of 38 druga stopniowo ga[nie */ for(t=0; t<=768; t+=2) { PORTA |= 0x01; // ustawia bit nr 0 PORTA &= ~0x02; // kasuje bit nr 1 _delay_us(t); // opóznienie w mikrosekundach PORTA &= ~0x01; // kasuje bit nr 0 PORTA |= 0x02; // ustawia bit nr1 _delay_us(768-t); } /* Pierwsza lampka stopniowo ga[nie, druga stopniowo rozja[nia si */ for(t=768; t>=0; t-=2) { PORTA |= 0x01; PORTA &= ~0x02; _delay_us(t); PORTA &= ~0x01; PORTA |= 0x02; _delay_us(768-t); } } } Listing 3.4 Kogut policyjny PrzykBad 5. Kluczyk - zabawka zrczno[ciowa Zabawa polega na prowadzeniu klucza nawleczonego na ptl z drutu, trzeba tak przeprowadzi klucz na drugi koniec ptli by nie dotknB ani razu ptli. Wci[nicie przycisku rozpoczyna zabaw. Ka|de zwarcie klucza z ptl sygnalizowanie jest krótkim dzwikiem z buzzera i przyga[niciem jednej diody LED. Pocztkowo [wiec si cztery diody LED, mo|na popeBni cztery bBdy, pite zwarcie koDczy zabaw co sygnalizowane jest dBugim dziwikiem przerywanym. Ilustracja dziaBania programu "Kluczyk zabawka zrczno[ciowa". Ptl wykonaBem z kawaBka miedzianego drutu o [rednicy ok 2,5mm, klucz te|, prawdziwe klucze raczej si nie nadaj. Klucz przyBczyBem gitkim przewodem do masy, a ptl do wyprowadzenia PB0 mikrokontrolera skonfigurowanego jako http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 35 of 38 wej[cie. Dodatkowo ptla zostaBa podcignita przez rezystor 1k do napicia zasilania. Przy zetkniciu klucza z ptl na wyprowadzeniu PB0 powinno pojawi si napicie GND i warto[ bitu nr. 0 odczytana z rejestru PORTB bdzie 0. Przycisk rozpoczynajcy gr przyBczony zostaB midzy GND a wyprowadzenie PB1 skonfigurowane jako wej[cie z wewntrzny podcigniciem do VCC, czyli przy wci[nitym przycisku warto[ bitu nr. 1 odczytana z rejestru PORTB bdzie 0. Diody LED zostaBy przyBczone do wyprowadzeD PD3..PD0 na sposób: VCC->R->LED->PDx, czyli [wiec si gdy odpowiedni bit w rejestrze PORTD ma warto[ 0. Buzzer zostaB przyBczony poprzez tranzystor npn do wyprowadzenia PC0 i dziaBa, gdy w rejestrze PORTC bit nr. 0 zosanie ustawiony na warto[ 1. Ptla z miedzianego drutu umocowania na kawaBku deski. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 36 of 38 Kluczyk, te| wykonany z miedzianego drutu. /* Kurs AVRGCC PrzykBad 035 Klucz - zabawka zrczno[ciowa Zabawa polega na prowadzeniu klucza nawleczonego na ptl z drutu, trzeba tak przeprowadzi klucz na drugi koniec ptli by nie dotknB ani razu ptli. UkBad ATmega16 1MHz wej[cia: PB0 - ptla z drutu Dodatkowo ptla ma by podcignita przez rezystor 1k do Vcc; a klucz - poBczony z GND. PB1 - przycisk wyj[cia: PC0 - buzzer PD0..PD3 - diody LED przyBczone na sposób: VCC->R->LED->PDx */ #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> int main(void) { /* Definicja zmiennych */ unsigned char m ; /* Konfiguracja portów we/wy */ DDRB = 0x00; PORTB = 0x02; DDRC = 0x01; PORTC = 0x00; DDRD = 0x0F; PORTD = 0x0F; http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 37 of 38 /* GBóna ptla programu */ while(1) { /* Oczekiwanie na wci[nicie przycisku, wci[nicie przycisku rozpoczyna zabaw*/ while(PINB & 0X02); /* Pocztkowa warto[ zmiennej 'm' dwójkowo 0001 0000 */ m = 0x10; /* Kasujc bity nr 0..3 rejestru PORTD zapala wszystkie 4 diody LED */ PORTD &= 0XF0; /* Ptla wykonuje si dopóki m bdzie ró|ne od 0 */ while(m) { /* Je[li nastpi zwarcie klucza z ptl */ if(!(PINB & 0X01)) { /* Krótki sygnaB dzwikowy */ PORTC |= 0x01; // wBcza buzzer _delay_ms(100); // czeka 0.1s PORTC &= ~0x01; // wyBcza buzzer /* Dodatkowy czas na odsunicie klucza */ _delay_ms(300); /* Za ka|dym przej[ciem przesuwa bity w zmiennej 'm' o jedn pozycje w prawo */ m>>=1; /* 0001 0000 pocztkowa warto[ zmiennej 'm' */ /* 0000 1000 warto[ 'm' po pierwszym przej[ciu */ /* 0000 0100 po drugim przej[ciu */ /* 0000 0010 po trzecim przej[ciu */ /* 0000 0001 po drugim przej[ciu */ /* 0000 0000 po pitym przej[ciu */ /* Za ka|dym przej[ciem gasi jedn diod LED, w kolejno[ci od czwartej do pierwszej. Diody LED przyBczone s na sposób: VCC->R->LED->PDx i gasn, gdy odpowiedni bit w PORTD ma warto[ 1 */ PORTD |= m; } } /* DBugi dzwik przerywany sygnalizuje koniec zabawy */ for(m=0; m<12; m++) { PORTC |= 0x01; // wBcza buzzer _delay_ms(50); // czeka 0.05s PORTC &= ~0x01; // wyBcza buzzer _delay_ms(50); // czeka 0.05s } } } Listing 3.5 Kluczyk - zabawka zrczno[ciowa. My[l, |e zamieszczone w tej cz[ci przykBadowe programy s na tyle proste, i| nie ma potrzeby obja[nia ich dziaBania linia po linii; i |e wystarcz animacje oraz komentarze doBczone w kodzie. Ale je[li jest inaczej, to prosz da zna co jest niezrozumiaBe, wtedy dopisz obja[nienia. W nastpnej cz[ci Tematem nastpnej cz[ci kursu bd tablice i funkcje - czyli dalszy cig podstaw jzyka C. http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010 XYZ Hobby Robot-Kurs AVR-GCC, cz.3 Page 38 of 38 Kurs AVR-GCC cz.4 Copyright © 2009-2010 ABXYZ - Wszelkie prawa zastrze|one http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=4&pv 17/04/2010

Wyszukiwarka

Podobne podstrony:
Kurs AVR GCC cz 5
Kurs AVR GCC cz 2
Kurs AVR GCC cz 3
Kurs AVR GCC cz 1
Kurs AVR GCC, cz 1
Kurs AVR GCC, cz 5
Kurs AVR GCC, cz 4
Kurs AVR GCC, cz 2
Kurs AVR GCC cz 4
Kurs AVR GCC Wyświetlacz LCD od Nokii310
XYZ Hobby Robot Kurs AVR GCC Gamepad od PlayStation
Kurs AVR GCC Dekoder RC5
Using the EEPROM memory in AVR GCC
AVR GCC w Linuksie przykład instalacji ze źródeł
Zestaw uruchomieniowy do procesorow rodziny AVR i 51, cz 2

więcej podobnych podstron