Kurs AVR-GCC cz.4.pdf

(334 KB) Pobierz
XYZ Hobby Robot-Kurs AVR-GC...
1 Z 23
Artykuł pochodzi ze strony XYZ HOBBY ROBOT ( xyz.isgreat.org )
Kurs AVRGCC cz.4(v1)
17.08.2009 ABXYZ
Artykuł jest wciąŜ jeszcze w trakcie edycji, więc wszelkie uwagi,
podpowiedzi i komentarze będą bardzo pomocne.
DuŜo wody upłynęło Wisłą do morza
od czasu ukazania się trzeciej część
niniejszego kursu i wreszcie jest
część czwarta. Ostatnio omawiane
były: zmienne, operatory, pętle
i instrukcje sterujące jak: if, switch.
W tej części kursu przerobimy
tablice i funkcje, czyli dalszy ciąg
podstaw języka C. Jak poprzednio,
wpierw omówię wymienione tematy,
a następnie zestawimy układ
z AVRem i uruchomimy kilka przykładowych programów. W tej
części kursu będziemy bawić się przyłączając do AVRa klawiaturę
telefoniczną i piezobuzzer(bez generatora).
Tablice
Gdy w programie mamy większą ilość danych jednego typu, to
zamiast tworzyć wiele pojedynczych zmiennych, lepiej będzie
utworzyć tablicę. W tablicy moŜna przechowywać jednocześnie
wiele zmiennych jednakowego typu. Wszystkie elementy tablicy są
ponumerowane, dostęp do dowolnej zmiennej w tablicy uzyskuje
się podając nazwę tablicy i numer elementu.
W języku C tablicę przed pierwszym uŜyciem naleŜy wcześniej
zdefiniować. Tablicę definiuje się pisząc kolejno: typ danych, nazwę
tablicy i objętą parą nawiasów kwadratowych [] liczbę elementów
tablicy. Definicję naleŜy zakończyć średnikiem.
int main( void )
{
/* Definicja tablicy 'pomiar' o 64 elementach typu char */
char pomiar[ 64 ];
/* Definicja tablicy 'wysokosc' o 32 elementach typu int */
int wysokosc[ 32 ];
/* Definicja tablicy 'temperatura' o 16 elementach typu
double */
double temperatura[ 16 ];
Elementami tablic mogą być wartości typów: char, int, float, double
oraz: struktury, unie, pola bitowe i wskaźniki o których będzie
mowa w następnej części kursu. Elementami tablicy mogą być teŜ
same tablice; w taki sposób tworzy się w języku C tablice
wielowymiarowe.
/* 2 elementowa tablica 40 elementach tablic typu char */
char bufor[ 2 ][ 40 ];
/* Tablica trójwymiarowa */
char jakas_tablica[ 4 ][ 8 ][ 3 ];
Definiując tablicę moŜna jednocześnie tablicę inicjalizować
wartościami początkowymi. W tym celu dopisuje się na końcu
214668305.005.png 214668305.006.png 214668305.007.png
2 Z 23
definicji: operator = , a po nim, objęte parą nawiasów klamrowych
{}, wartości początkowe kolejnych elementów tablicy rozdzielone
przecinkami.
/* Definicja tablicy z jednoczesną inicjalizacją wartościami
początkowymi dwóch pierwszych elementów tablicy */
char tablica[ 4 ] = { 0x01 , 0x02 };
/* Definicja tablicy z jednoczesną inicjalizacją wartościami
początkowymi wszystkich czterech elementów. W takim przypadku
moŜna nie wpisywać w definicji ilości elementów tablicy,
kompilator sam to wyliczy. */
char tablica[] = { 0x01 , 0x02 , 0x04 , 0x08 };
/* Definicja z inicjalizacją tablicy dwuwymiarowej */
char inna_tablica[][ 2 ] = { 0x31 , 0x02 ,
0xf1 , 0x02 ,
0x41 , 0xf2 ,
0xf1 , 0xc2 ,
0x11 , 0xa2 };
W programie elementami tablicy posługujemy się w identyczny
sposób jak pojedynczymi zmiennymi. KaŜdy element tablicy ma
nazwę składającą się z nazwy tablicy oraz objętego parą nawiasów
kwadratowych indeksu(numeru elementu). Elementy tablicy
numerowane są zaczynając od zera, a nie od jedynki, naleŜy to
koniecznie zapamiętać.
/* Przypisanie pierwszemu elementowi tablicy wartości 23.5 */
temperatura[ 0 ] = 23.5 ;
/* Przypisanie drugiemu elementowi tablicy wartości 22.0 */
temperatura[ 1 ] = 22.0 ;
/* Przypisanie ósmemu elementowi tablicy wartości 17.5 */
temperatura[ 7 ] = 17.5 ;
/* Przypisanie jakiejs_zmiennej wartości czwartego elementu
tablicy */
jakas_zmienna = temperatura[ 3 ];
Trzeba teŜ pamiętać, Ŝe jeŜeli zdefiniujemy tablicę n elementową
i spróbujemy zapisać coś pod indeksem równym lub większym n to
kompilator nie zgłosi błędu, ale skutkować to moŜe nieprawidłowym
działaniem programu.
Przy operacjach na tablicach szczególnie uŜyteczna moŜe być
instrukcja pętli for, gdzie licznik pętli będzie indeksem tablicy.
unsigned char i,j;
int tablica_1[ 16 ];
int tablica_2[ 16 ];
int tablica_3[ 10 ][ 10 ];
/* Kolejnym elementom tablicy przypisane zostaną wartości:
0,10,20,30..150 */
for (i = 0 ; i < 16 ; i++)
tablica_1[i] = i * 10 ;
/* Kopiowanie zawartości tablica_1 do tablica_2 */
for (i = 0 ; i < 16 ; i++)
tablica_2[i] = tablica_1[i];
/* Wypełnienie tablicy dwuwymiarowej */
for (i = 0 ; i < 9 ; i++)
for (j = 0 ; j < 9 ; j++)
tablica_3[i][j] = i * j;
214668305.008.png
3 Z 23
Na tym etapie nauki, te informacje na temat tablic mam wystarczą.
Funkcje
Program składa się z ciągu instrukcji zapisanych w pamięci
i wykonywanych jedna po drugiej. Obok instrukcji, które realizują
konkretne zadania, na przykład włączają i wyłączają diodę LED,
istnieją teŜ specjalne instrukcje sterujące przebiegiem programu
jak np.: ifelse, switch, for, while; które były tematem poprzedniej
części kursu.
Obok wspomnianych instrukcji sterujących istnieje moŜliwość
tworzenia podprogramów. Zwykle dłuŜsze programy dzielone są na
odrębne fragmenty, nazywane podprogramami lub procedurami.
Spośród podprogramów wyróŜnić moŜna podprogram pierwszy
(główny), od którego pierwszej instrukcji rozpoczyna się działanie
całego programu. Umieszczając w programie specjalną instrukcję
instrukcję wywołania podprogramu moŜna wykonać wybrany
podprogram.
Przebieg przykładowego programu składającego się z podprogramu głównego i dwóch
podprogramów. Cały program zaczyna się od pierwszej instrukcji podprogramu głównego.
A jaki moŜe być poŜytek z podziału programu na podprogramy ? Na
przykład, jeśli jakiś dłuŜszy fragment kodu powtarza się w wielu
miejscach programu, oczywistym rozwiązaniem będzie umieścić ten
fragment w odrębnym podprogramie. W wyniku otrzymamy
znacznie krótszy program o przejrzystej strukturze. W tak
napisanym programie łatwiej jest wprowadzać zmiany. Oczywiście
sposób podziału programu nie bywa przypadkowy, podprogramy
zwykle realizują konkretne zadania np. odczyt czujnika
temperatury, włączenie sygnalizacji albo uruchomienie
serwomechanizmu.
W języku C podprogramy nazywa się funkcjami. KaŜdy program
w języku C musi zawierać funkcje o nazwie "main" kaŜda funkcja
ma nadaną nazwę (identyfikator). Funkcja main jest wspomnianym
wcześniej podprogramem pierwszym(głównym), od którego
214668305.001.png 214668305.002.png
4 Z 23
pierwszej instrukcji zaczyna się wykonanie całego programu.
/* Najprostszy programcałość umieszczona w funkcji main */
#define F_CPU 1000000L
#include <avr/io.h>
/* Definicja funkcji main */
int main( void )
{
/* Instrukcje naszego programu */
}
Obok funkcji main programista moŜe tworzyć(definiować) własne
funkcje, moŜna teŜ wykorzystywać gotowe funkcje z biblioteki
standardowej języka C, dostarczonej razem z kompilatorem. Razem
z kompilatorem avrgcc wykorzystuje się bibliotekę AVR Libc, która
pełni rolę biblioteki standardowej, dopasowanej do moŜliwości
8bitowych mikrokontrolerów AVR. W przykładach z kursu często
uŜywana jest funkcja z biblioteki AVR Libc o nazwie _delay_ms.
Funkcja ta wprowadza do programu opóźnienie o zadanym
w milisekundach okresie czasu; w avrlibc dostępna jest takŜe
podobna funkcja _delay_us, dla której długość opóźnienia podaje
się w mikrosekundach.
Instrukcja wywołania funkcji składa się z nazwy funkcji i objętej
parą nawiasów okrągłych listy argumentów, i kończy się
średnikiem. Argumenty funkcji to dane przekazywane do funkcji,
jak na przykład wartość opóźnienia w funkcji _delay_ms. Jeśli
funkcja oczekuje kilku argumentów, kolejne argumenty oddziela się
przecinkami. Gdy funkcja nie oczekuje Ŝadnego argumentu, to
uruchamiając ją, po nazwie funkcji wstawiamy "pustą" parę
nawiasów okrągłych ().
/* Funkcje _delay_ms, _delay_us oczekują przy wywołaniu
jednego argumentu typu double wartości opóźnienia */
/* Argumentem funkcji jest wartość stała 80 */
_delay_ms( 80 );
);
/* Argumentem funkcji będzie wartość wyraŜenia
jakas_zmienna+20 */
_delay_us(jakas_zmienna + 20 );
);
/* Funkcje mogą oczekiwać jednego lub większej
liczby argumentów albo Ŝadnego */
/* Jeśli jakaś funkcja oczekuje kilku argumentów, kolejne
argumenty oddziela się przecinkiem. */
jakas_funkcja( 10 , 17.3 , jakas_zmienna);
);
/* Inna funkcja nie oczekuje Ŝadnego argumentu */
inna_funkcja();
);
Po zakończeniu działania funkcje mogą zwracać dane. Na przykład
funkcja rand z biblioteki standardowej zwraca wartość typu int,
wartością tą jest liczba pseudolosowa z przedziału od 0 do
RAND_MAX(0x7FFF). JeŜeli funkcja zwraca wartość, wtedy całe
wyraŜenie: nazwa_funkcji(argumenty_funkcji) posiada wartość
i typ, podobnie zmienne. Wtedy, przykładowo, moŜna instrukcję
wywołania funkcji "nazwa_funkcji(argumenty_funkcji)" postawić po
prawej stronie operatora przypisania, Ŝeby zwróconą przez funkcję
wartość przypisać od zmiennej; albo umieścić w warunku instrukcji
ifelse.
);
);
214668305.003.png
5 Z 23
/* Funkcja rand, obliczająca liczbę losową, zwraca
wartość typu int */
jakas_ zmienna = rand() + 100 ;
/* Jeśli wartość zwrócona przez funkcje rand będzie większa
od 10, wtedy warunek w instrukcji if będzie spełniony */
if ( rand() > 10 )
{
Funkcja moŜe zwracać tylko wartość jednej zmiennej lub nie
zwracać niczego.
Własną funkcję tworzy(definiuje) się wpisując kolejno: typ
zwracanej wartości, nazwę nowej funkcji, listę parametrów funkcji
objętą parą nawiasów okrągłych (); deklaracje kolejnych
parametrów oddziela się przecinkami. W definicji funkcji
argumenty nazywa się parametrami. Następnie, między parą
nawiasów klamrowych {}, umieszcza się instrukcja po instrukcji
kod funkcji.
/* Definicja funkcji */
typ nazwa_funkcji(parametry)
{
/* Instrukcje wewnątrz funkcji */
}
Jeśli w definicji funkcji jako zwracany typ wstawi się słówko void,
oznaczać to, Ŝe funkcja nie będzie niczego zwracać; a jeśli
wstawimy void w miejsce listy parametrów, to funkcja nie będzie
oczekiwać Ŝadnych argumentów. W naszych krótkich programach
definicje funkcji będą umieszczane w pliku przed funkcją main.
/* Definicja funkcji które niczego nie zwraca i nie oczekuje
Ŝadnych argumentów */
void io_init( void )
{
DDRD = 0x0f ;
PORTD = 0xf0 ;
DDRB = 0x0f ;
}
/* Definicja funkcji main */
int main( void )
{
/* Wywołanie funkcji io_init */
io_init();
PoniŜej znajduje się przykład definicji funkcji, która przyjmuje dwa
argumenty typu unsigned int i nie zwraca niczego. Wartości
argumentów dostępne są wewnątrz funkcji w specjalnie tworzonych
zmiennych. W chwili wywołania funkcji, tworzone są zmienne
o typach i nazwach jakie znajdują się na liście parametrów.
Zmienne te są inicjalizowane wartościami argumentów podanych
przy wywołaniu funkcji. W przykładzie poniŜej, w funkcji beep
dostępne są dwie zmienne o nazwach: frequency i duration
zawierające wartości wysłanych do funkcji argumentów.
/* Definicja funkcji beep */
void beep( unsigned int frequency, unsigned int duration)
{
unsigned int i,t,n;
t = 125000 /frequency;
214668305.004.png
Zgłoś jeśli naruszono regulamin