Kurs AVR-GCC cz.5.pdf

(796 KB) Pobierz
Kurs AVR-GCC cz.5
1 Z 40
Artykuł pochodzi ze strony XYZ HOBBY ROBOT ( xyz.isgreat.org )
Kurs AVRGCC cz.5 (v1)
29.03.2010 ABXYZ
Uwaga, to jest dopiero szkic artykułu, tekst jest wciąŜ w trakcie
edycji, wszelkie uwagi, podpowiedzi i komentarze będą bardzo
pomocne.
Ostatnio omawiane były tablice i funkcje, a jeszcze wcześniej:
zmienne, pętle i instrukcje warunkowe. W tej części kursu tematem
przewodnim będzie tekst i działania na tekście. Napiszę teŜ kilka
zdań na temat preprocesora języka C. Kolejnym omawianym
zagadnieniem będzie podział kodu źródłowego programu na
oddzielnie kompilowane pliki. W części praktycznej będziemy bawić
się alfanumerycznym wyświetlaczem LCD, przyłączymy do AVRa
termometr cyfrowy ds18b20, a dalej połączymy AVRa
z komputerem PC poprzez port szeregowy RS232C.
Programy z tekstem
Dotąd w przykładach z kursu uŜywane były jedynie zmienne
liczbowe. A co z tekstem ? Oczywiście tekst przechowuję się
w pamięci komputera równieŜ w postaci liczb. Po prostu małym i
wielkim literom alfabetu, cyfrom oraz wszystkim innym znakom
przyporządkowuje się kolejne liczby z pewnego zakresu. Zwykle
jeden znak zajmuje w pamięci komputera jeden bajt (osiem bitów),
najczęściej uŜywanym bywa kodowanie ASCII lub jego
rozszerzenia.
Tablica kodów ASCII. Literom alfabetu, cyfrom oraz wszystkim innym znakom
przyporządkowuje się kolejne liczby. Kliknij w obrazek, Ŝeby obejrzeć całość.
Inaczej inŜ jest w wielu innych językach programowania w C nie
przewidziano specjalnego typu zmiennej przeznaczonego do
przechowywania tekstu. W języku C do przechowywania tekstu
wykorzystuje się tablice typu char. Aby zapamiętać tekst kolejne
pola tablicy wypełniane są kodami ASCII znaków tworzących tekst.
Tablica wypełniona kodami ASCII kolejnych liter tworzących napis "Siemka!". W języku C
270070215.007.png 270070215.008.png 270070215.009.png 270070215.010.png 270070215.001.png 270070215.002.png
2 Z 40
tekst przechowuje się po prostu w tablicach typu char.
W kodzie źródłowym programu moŜna posługiwać się stałymi
znakowymi i stałymi napisowymi. Stała znakowa ma postać znaku
objętego pojedynczymi cudzysłowami i posiada wartość liczbową
kodu ASCII tego znaku.
int jeden_znak ;
char jakis_napis[ 7 ];
/* W zmiennej jeden_znak znajdzie się wartość
65(kod ASCII znaku A) */
jeden_znak = 'A' ;
/* Zapisujemy tekst do tablicy znak po znaku */
jakis_napis[ 0 ] = 'S' ;
jakis_napis[ 1 ] = 'i' ;
jakis_napis[ 2 ] = 'e' ;
jakis_napis[ 3 ] = 'm' ;
jakis_napis[ 4 ] = 'k' ;
jakis_napis[ 5 ] = 'a' ;
jakis_napis[ 6 ] = '!' ;
Stałe napisowe tworzy się obejmując fragment tekstu parą
podwójnych cudzysłowów. Definiując tablicę znakową moŜna ją
jednocześnie zainicjować stałą napisową. Tym sposobem tablica,
w momencie jej tworzenie, zostanie wypełniona kodami ASCII
kolejnych znaków tworzących napis.
/*Tworzona tablica zostanie wypełniona ciągiem znaków */
char jakis_napis[] = "Siemka!" ;
/* Zawartość tablicy:
jakis_napis[0] = 'S'
jakis_napis[1] = 'i'
jakis_napis[2] = 'e'
jakis_napis[3] = 'm'
jakis_napis[4] = 'k'
jakis_napis[5] = 'a'
jakis_napis[6] = '!'
jakis_napis[7] = 0x0 */
W przykładzie wyŜej, w tablicy za ostatnim znakiem napisu,
kompilator dodatkowo wstawi bajt o wartości zero. Znak o kodzie
zero pełni tu rolę znacznika końca ciągu znaków. Jest zasadą
w języku C Ŝe ciągi znaków kończą się znakiem o kodzie równym
zero. Tekst moŜe mięć dowolną długość, aby się tylko zmieścił w
tablicy wzraz z ograniczającym go bajtem zero.
JeŜeli w stałej napisowej potrzeba wstawić znak podwójnego
cudzysłowu, to naleŜy go poprzedzić znakiem backslash (\"). A jeśli
chcemy wstawić sam znak backslash, to naleŜy wpisać dwa znaki
backslash (\\). Są to tzw. sekwencje specjalne zaczynające się od
znaku backslash, dalej jeszcze będę o nich pisał.
/* Do tablicy zapisany zostanie ciąg znaków:
abcdef"gh\i\jklmnop"qrs'tuv'wxyz */
char jakis_napis[] = "abcdef\"gh\\i\\jklmnop\"qrs'tuv'wxyz" ;
Jeśli jakaś funkcja oczekuje jako argumentu tablicy typu char, to
jako argument, zamiast nazwy tablicy, moŜna wstawić stałą
napisową.
/* Definicja tablicy */
270070215.003.png
3 Z 40
char tablica[]
[]= "KURS AVRGCC" ;
/* Definicja przykładowej funkcji, która jak
argumentu oczekuje tablicy typu char */
void funkcja( char tablica[]
[])
{
}
int main( void )
{
/* Wywołanie funkcji */
funkcja(tablica);
/* Jako argument moŜna wstawić stałą napisową */
funkcja( "KURS AVRGCC" );
);
W języku C brakuje równieŜ operatorów przeznaczonych do działań
na tekście, takie operacje jak porównywanie czy łączenie napisów
pozostaje zaprogramować samemu. Nie jest to nic specjalnie
trudnego, oto kilka przykładów prostych operacji na tekstach:
Wykorzystując instrukcję pętli moŜna porównywać dwa ciągi
znaków.
/* Przyrównanie ciągu znaków */
unsigned char i;
char str1[]=
[]=
[]= "KURS AVRGCC" ;
++);
/* Jeśli warunek spełniony, to porównywane
ciągi znaków róźnią się */
if (str1[i] ||
]==str2[i] &&
&& str1[i];
]; i++);
++);
|| str2[i])
])
Podobne uŜywając instrukcji pętli moŜna połączyć dwa lub więcej
napisów w jeden tekst.
/* Łączenie ciągów znaków */
unsigned char i,j;
char str1[]=
[]=
[]= " AVRGCC" ;
char str3[]=
[]=
[]= " cz.5" ;
char buffer[ 18 ];
[]=
];
/* Łączy trzy ciągi znaków . Całość
zostanie zapisana w tablicy 'buffer[]' */
for (i= 0 ,j= 0 ; buffer[j]=
]=str1[i];
]; i++,
++,j++);
++);
for (i= 0 ; buffer[j]=
]=str2[i];
]; i++,
++,j++);
++);
for (i= 0 ; buffer[j]=
]=str3[i];
]; i++,
++,j++);
++);
A tak z pomocą instrukcji pętli for moŜna wyznaczyć długość ciągu
znaków zakończonego zerem.
/* Obliczanie długości ciągu znaków */
char s[]
[]
/* Zmienna 'i' zawierać będzie długość ciągu
znaków w tablicy 's[]' . Bajt o wartości zero
na końcu ciągu nie jest liczony.
*/
for (i= 0 ; s[i];
]; i++);
++);
JeŜeli zamierzamy na wyświetlaczu alfanumerycznym pokazać
wartość zmiennej liczbowej, to koniecznym będzie zamienić wartość
liczbową na ciąg znaków. Kawałek kodu poniŜej zmienia 16bitową
[]
[]
);
[]= "KURS AVRGCC" ;
char str2[]=
[]=
for (i= 0 ; str1[i]==
]==
&&
];
||
])
[]= "KURS" ;
char str2[]=
]=
];
++,
++);
]=
];
++,
++);
]=
];
++,
[] = "KURS AVRGCC" ;
unsigned char i;
];
270070215.004.png
4 Z 40
liczbę całkowitą bez znaku na odpowiadający jej ciąg cyfr (kodów
ASCII cyfr). Wartość liczbowa w zmiennej 'a' jest cyklicznie w pętli
dzielona przez 10, dopóki nie stanie się zerem dzielenie
całkowite. Obliczana w kaŜdej iteracji pętli reszta z dzielenia
stanowi cyfrę stojącą na kolejnej pozycji w liczbie, idąc w kierunku
od cyfry najmniej znaczącej do najbardziej znaczącej. Reszta
z dzielenia (liczba z zakresu 0..9) zmieniana jest na kod ASCII
cyfry przez dodanie do niej wartości kodu ASCII cyfry zero (48).
/* Zmiana liczby na ciąg znaków ASCII */
signed char i;
unsigned int a ;
char buffer[ 6 ];
];
a = 65535 ;
/* Wypełnia tablicę 'buffer[]' kodami ASCII cyfr
skaładających się na liczbę w zmiennej 'a' */
for (i= 4 ,buffer[ 5 ]=
]= 0 ; a; a/=
/= 10 ,i)
)
buffer[i]=
]= a% 10 + '0' ;
)
buffer[i] = ' ' ;
>= 0 ; i)
)
Opisane działania na tekstach moŜna zrealizować równieŜ
wykorzystując funkcje z biblioteki standardowej języka C.
Do przekształcenia wartości liczbowych na ciągi znaków i w ogóle
do formowania komunikatów tekstowy uŜyteczne mogą być
standardowe funkcje printf() i sprintf(); aby móc z nich skorzystać
naleŜy gdzieś na początku pliku wstawić polecenie:
#include <stdio.h>
Funkcje printf i sprintf róŜnią się od siebie tym, Ŝe sprintf zapisuje
dane do tablicy, zaś printf do standardowego wyścia. Na kilku
prostych przykładach wyjaśnię działanie funkcji sprintf.
];
int t = 21 ;
int p = 1013 ;
int v = 10 ;
/* W tablicy 'buf' zostanie zapisany ciąg znaków:
'Temperatura powietrza: 21°C' */
sprintf(buf, "Temp. powietrza: %d°C" ,t);
];
);
/* W tablicy 'buf' zostanie zapisany ciąg znaków:
'T:21°C, P:1013hPa, V:10m/s' */
sprintf(buf, "T:%d°C, P:%dhPa, V:%dm/s" ,t,p,v);
);
Pierwszym argumentem funkcji sprintf() jest tablica znakowa,
miejsce w pamięci, gdzie zostanie zapisany ciąg znaków
zakończony zerem tworzony komunikat. Drugim argumentem
sprintf() jest ciąg znaków zawierający format komunikatu. Format
zawiera stałą treść komunikatu wraz z tzw. "specyfikacjami
przekształceń". Specyfikacje przekształceń są to takie "znaczki
krzaczki":) w rodzaju: %d, %4d, %u, %x, %6.1f i podobnie
wyglądające, które zostaną w wyjściowym komunikacie zastąpione
jakąś treścią. A czym ? W naszym przykładzie, w miejscu
pierwszego wystąpienia specyfikacji %d zostanie wstawiona wartość
trzeciego argumentu funkcji sprintf, czyli wartość zmiennej
't' wypisana w postaci liczby dziesiętnej. Tak samo następne
];
]=
/=
]=
for (;
(;
(; i>=
>=
char buf[ 32 ];
);
270070215.005.png
5 Z 40
występujące w formacie specyfikacje zostaną zmienione
wartościami kolejnych argumentów funkcji sprintf. Funkcją sprintf
nie ma ustalonej liczby argumentów, więc w formacie komunikatu
moŜna umieszczać dowolną ilość specyfikacji przekształceń. Na
temat funkcji o zmiennej liczbie argumentów napiszę jak się
nadarzy okazja.
Specyfikacje przekształcenia zaczynają się od znaku
procenta % i kończą znakiem przekształcenia. Na przykład: %d
zastąpione zostanie liczbą całkowitą; %uliczbą całkowitą bez
znaku; oliczbą ósemkową; %xliczbą szesnastkową; cjednym
znakiem; $sciągiem znaków; %fliczbą
niecałkowitą(zmiennoprzecinkową) w postaci: część całkowita,
kropka, część ułamkowa (np.: 12.345). Aby wypisać sam znak
procent % wstawia się dwa znaki procent %%. Następne przykłady
przekształceń: %6d liczba całkowita zajmująca co najmniej 6
znaków (na przykład: [][][]123); %6.2f liczba zmiennopozycyjna
o długości 6 znaków i z dwiema cyframi po przecinku (na przykład:
[]12.34)
];
double l = 12.3456 ;
int valve = 80 ;
/* W tablicy 'buf' zostanie zapisany ciąg znaków:
'Valve: 80%' */
sprintf(buf, "Valve%6d%%" ,valve);
);
/* W tablicy 'buf' zostanie zapisany ciąg znaków:
'Length= 12.34' */
sprintf(buf, "Length=%6.2f" ,l);
);
Opisałem tu jedynie część moŜliwości funkcji sprintf(), po resztę
odsyłam do podręcznika języka C i do dokumentacji biblioteki
AVRLibc.
Ale uwaga, uŜycie w programie dla 8bitowego mikrokontrolera
dość rozbudowanych funkcji sprintf, printf skutkuje znaczącym
wzrostem wielkości kodu wynikowego. W AVRLibC domyślnie, celem
oszczędzania pamięci, funkcje printf, sprintf nie obsługują liczb
zmiennoprzecinkowych. Aby włączyć obsługę liczb
zmiennoprzecinkowych uruchamiamy program MFile, wczytujemy
plik makefile naszego projektu i w menu "Makefile>printf()options"
zaznaczamy opcję "floating point".
char buf[ 32 ];
];
270070215.006.png
Zgłoś jeśli naruszono regulamin