FORUM

Tablice i łańcuchy cz.7

Odpowiedz

Emotikony
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :arrow: :| :mrgreen: :geek: :ugeek:

BBCode włączony
[Img] włączony
[Flash] wyłączony
[URL] włączony
Emotikony włączone

Przegląd tematu
   

Rozwiń widok Przegląd tematu: Tablice i łańcuchy cz.7

Tablice i łańcuchy cz.7

autor: Erni86 » 12 sie 2021, 11:17

Tablice służą do przechowywania zbioru zmiennych. Zmienne, które do tej pory poznałeś, przechowywały tylko jedną wartość. Zwykle była to wartość typu int. Tablica natomiast zawiera listę zmiennych. Korzystając z tej listy, możesz uzyskać dostęp do dowolnej wartości zapisanej w tablicy. W języku C, tak jak w większości języków programowania, numeracja indeksów zaczy­na się od O, a nie od 1. A więc pierwszym elementem tablicy jest element o numerze zero. W celu zademonstrowania działania tablic stworzymy przykładową aplikację, która za pomocą błysków wbudowanej w Arduino diody LED będzie generować alfabetem Morse' a sygnał „SOS". Alfabet Morse'a był stosowany do komunikacji w XIX i XX wieku. Składa się z kombi­nacji dwóch znaków - kropki i kreski. Dzięki temu mógł on być przesyłany za pośred­nictwem kabli telegraficznych i łącz radiowych. Kod ten również mógł być przekazywan
przy pomocy sygnałów świetlnych. Skrót „SOS" (od ang. save aur souls) wciąż odgrywa rolę międzynarodowego sygnału oznaczającego wołanie o pomoc. Litera Sjest reprezentowana przez trzy krótkie błyski (kropki), a litera O -przez trzy długie błyski (kreski). Utworzymy tablicę, która będzie przechowywać elementy typu int zawierające informacje o długości każdego błysku. Elementy tablicy zostaną następnie za­stosowane w pętli for w celu określenia odpowiedniego czasu trwania błysków. Najpierw przyjrzyjmy się sposobowi tworzenia tablicy elementów typu int, które mają określać czas trwania poszczególnych błysków.

int durations[] = {200, 200, 200, 500, 500, 500, 200, 200, 200};

Umieszczając nawiasy kwadratowe [] za nazwą zmiennej, wskazujemy, że zmienna ta zawiera tablicę. W zap rezentowanym przykładzie określamy wartości długości błysków w momencie tworzenia tablicy. Deklaracja tych elementów polega na zastosowaniu nawiasów klamrowych, a następnie wpisaniu wartości oddzielonych od siebie przecinkami. Nie zapomnij o umiesz­czeniu średnika na końcu linii kodu. Dostęp do dowolnego elementu tablicy możesz uzyskać przy użyciu zapisu z nawiasem kwadratowym. Jeżeli chcesz uzyskać dostęp do pierwszego elementu tablicy, zastosuj po­niższy kod: durations [O] Aby zademonstrować to w praktyce, stwórzmy tablicę, a następnie wyświetlmy wartości zapisane w tej tablicy przy użyciu monitora portu szeregowego:

Kod: Zaznacz cały

i n t l edPi n = 13; 

i n t durati ons [] { ZOO , ZOO , ZOO , 500 , 500 , 500 , ZOO , ZOO , ZOO } ; 

void setup () 

{ 
Serial.begin (9600) ; 
for (int i = O; i < 9; i ++) 
{ 
Serial.println {durations [i] ); 
}
}
void loop () 
{}

Załaduj szkic do Arduino, a następnie otwórz monitor portu szeregowego. Efekt dzia-
łania programu powinien być podobny do tego, co przedstawiono na rysunku 5. 1.
Powstał zgrabny program, który można łatwo zmodyfikować w celu dodania kolejnych
wartości długości błysków. Wystarczyłoby tylko dodać je do listy znajdującej się w nawia-
sach klamrowych, a następnie w pętli for zmienić liczbę 9 na nowy rozmiar tablicy.
Monitor portu szeregowego wyświetlający dane wyjściowe
Monitor portu szeregowego wyświetlający dane wyjściowe
Rys1.jpg (78.49 KiB) Przejrzano 1979 razy
Podczas pracy z tablicami musisz zachować pewną ostrożność. Kompilator nie po-
wstrzyma próby uzyskania dostępu do danych znajdujących się poza obszarem tablicy. Dzieje
się tak, ponieważ tablica jest tak naprawdę wskaźnikiem do adresu w pamięci, co pokazano
na rysunku 5.2.
Tablice i wskazówki
Tablice i wskazówki
Rys2.jpg (137.07 KiB) Przejrzano 1975 razy

Programy przechowują dane (zarówno zwyczajne zmienne, jak i tablice) w pamięci.
Pamięć komputera jest zorganizowana w sposób mniej elastyczny od pamięci człowieka.
Pamięć Arduino można porównać do zbioru szuflad. Podczas definiowania dziewięcioele-
mentowej tablicy rezerwowana jest przestrzeń kolejnych dziewięciu szuflad. Zmienna tabli-
cowa jest wskaźnikiem pierwszej szuflady, zwanej pierwszym elementem tablicy.
Wróćmy do zagadnienia uzyskania dostępu do obszaru pamięci znajdującego się poza
obszarem tablicy. Gdybyś zdecydował się uzyskać dostęp do elementu du rat i on [10] , zo-
stałaby Ci zwrócona jakaś wartość typu i nt. Ta wartość może być jednakże dosłownie
wszystkim. Uzyskanie dostępu do obszaru pamięci znajdującego się poza tablicą nie jest niczym
groźnym. Uzyskasz po prostu dostęp do jakiejś przypadkowej wartości niebędącej elemen-
tem tablicy. Może to spowodować nieprawidłowe wyniki działania Twojego programu.
O wiele gorsze skutki może spowodować próba zmiany wartości znajdującej się poza
obszarem tablicy. Na przykład gdybyś zamieścił w swoim programie poniższy zapis, mógłbyś
poważnie zakłócić działanie programu.

durations [10] = O;

Szuflada, w której chcemy dokonać zapisu, może już zawierać jakąś inną zmienną. A więc
powinieneś bardzo uważać, żeby nie dokonać zapisu poza granicami tablicy. Jeżeli Twój
szkic działa w dziwny sposób, powinieneś sprawdzić, czy nie występuje w nim problem
tego typu.
Zastosowanie tablic do alfabetu Morse' a i sygnału SOS
W szkicu 05.02. zaprezentowano zastosowanie tablic w celu wygenerowania sygnału SOS.

Kod: Zaznacz cały

int ledPin = 13; 

int durations [] { 200 , 200 , 200 , 500, 500 , 500 , 200, 200 , 200 } ; 
void setup () 
{ 
pinMode ( ledPin, OUTPUT) ; 
}
void loop () 
{ 
for (int i = 0; i < 9; i ++) 
{ 
flash(durations [i] ); 
} 
delay (1000) ; 
void flash ( int duration) 
{ 
digi tal Wri te ( ledPin, HIGH) ; 
delay (duration ) ;

}
digitalWrite ( ledPin, LOW ) ; 
delay (duration ) ;
}
Oczywistą zaletą tej techniki jest to, że treść wiadomości można zmienić bardzo łatwo.
Wystarczy po prostu zmodyfikować tablicę durati ans. W szkicu 05.05. zastosujemy tablice
w sposób bardziej zaawansowany - stworzymy generator alfabetu Morse' a ogólnego prze-
znaczenia.

Tablice łańcuchów
W programowaniu łańcuch nie ma nic wspólnego z długim cienkim przedmiotem składa-
jącym się z ogniw. Łańcuch jest sekwencj ą znaków. Dzięki łańcuchom Arduino może ob-
sługiwać teksty. Szkic 05.03. będzie cyklicznie, co sekundę, przesyłał wiadomość tekstową
o treści „Witaj" do monitora portu szeregowego:

Kod: Zaznacz cały

void setup () 

{ 
Serial.begin(9600 ) ; 

}
void loop () 
{ 
Seri al . printl n(" Wi taj"); 
delay (lOOO) ;
}
Literały łańcuchowe
Literały łańcuchowe są zapisywane w podwójnych cudzysłowach. Literały to łańcuchy, które
są stałe, w przeciwieństwie do np. zmiennej typu i nt, którą chcemy później modyfikować.
Tak jak zapewne się tego spodziewasz, łańcuchy można umieszczać w zmiennych. Ist-
nieje również zaawansowana biblioteka obsługująca łańcuchy. Na razie będziemy jednakże uży-
wać standardowych łańcuchów języka C - takich jak ten, który znajduje się w szkicu 05.03.
W języku C literał łańcuchowy jest tak naprawdę tablicą elementów typu char. Element
typu char jest trochę podobny do elementu typu i nt - jest to również cyfra - jednakże
mieści się ona w zakresie od O do 127 i reprezentuje jeden znak. Tym znakiem może być
litera alfabetu, cyfra, znak interpunkcyjny lub znak specjalny, taki jak np. znak tabulacji lub
znak przesuwu o wiersz. Kody numeryczne zawarte w łańcuchach są oparte na standardzie
o nazwie ASCII. N aj częściej stosowane kody ASCII przedstawiono w tabeli 5.1.

_________________________________________________
Tabela 5.1. Najczęściej stosowane kody ASCII
_________________________________________________
Znak Kod ASCII (dziesiętny)
a-z 97 - 112
A-Z 65 - 90
0-9 48 - 57
spacja 32
_________________________________________________

Zmienne łańcuchowe
Zmienne łańcuchowe są bardzo podobne do zmiennych tablicowych. Różnicą jest to, że ich
wartość początkową można zdefiniować w bardzo prosty sposób:
char n ame [J = "Wi taj";
Zapis ten definiuje tablicę znaków i inicjalizuje ją łańcuchem znaków o treści „Witaj".
Automatycznie zostanie dodana wartość zerowa (O w kodzie ASCII) oznaczająca koniec
łańcucha.
Wcześniejszy przykład był co prawda zgodny z posiadanymi przez Ciebie wiadomo-
ściami dotyczącymi łańcuchów, jednakże częściej spotykany jest następujący zapis:
char *name = " Wi taj";
Jest to zapis równoznaczny z zapisem omówionym wcześniej. Znak * symbolizuje, że
mamy do czynienia ze wskaźnikiem. Wskaźnik name wskazuje na pierwszy element typu
char tablicy elementów typu char. Jest to miejsce w pamięci, gdzie zapisana jest litera W.
Możesz zmodyfikować szkic 05.03. tak, aby zastosować w nim zarówno zmienne, jak i stałe
łańcuchowe:

Kod: Zaznacz cały

char message [] = "Witaj"; 
void setup() 
{ 
Serial . beg i n (9600) ; 
}
void loop ()
{
Seri a l . pri ntl n (message) ; 

del ay (1000) ;
}
Tłumacz alfabetu Morse'a

TABLICE I ŁAŃCUCHY 73

Zastosujmy naszą wiedzę dotyczącą tablic i łańcuchów w celu napisania bardziej złożonego
szkicu, który będzie odbierał komunikaty przesłane za pośrednictwem monitora portu sze-
regowego, a następnie przekazywał je w formie alfabetu Morse'a przy użyciu wbudowanej
diody LED.
Tabela 5.2. zawiera litery i cyfry stosowane w alfabecie Morse' a.
alfabet_Morse (2).jpg
alfabet_Morse (2).jpg (59.18 KiB) Przejrzano 1960 razy
Jedna z zasad tego kodu mówi, że kreska powinna być trzy razy dłuższa od kropki.

Odstęp pomiędzy każdą kreską lub kropką jest równy długości kropki. Przerwa pomiędzy dwoma
literami trwa tyle samo czasu co kreska. Odstęp pomiędzy dwoma słowami powinien trwać
tyle samo co siedem kropek.
W tym projekcie nie będziemy dbali o interpunkcję. Samodzielne dodanie do szkicu ob-
sługi interpunkcji byłoby jednakże bardzo ciekawym ćwiczeniem. Pełną listę znaków stosowa-
nych w alfabecie Morse' a znaj dziesz pod adresem http://pl.wikipedia.org/wiki!Kod_Morse'a.

Dane
Nasz szkic będziemy budować krok po kroku. Zaczniemy od struktury danych, którą będziesz
stosować do reprezentacji kodów.

Warto zrozumieć, że każdy problem natury programistycznej ma więcej niż jedno roz-
wiązanie. Różni programiści tworzą różne rozwiązania tych samych problemów. Nie warto
jest więc myśleć, że „nigdy bym na to nie wpadł". Prawdopodobnie wpadłbyś na coś inne-
go, a być może lepszego. Każdy myśli według innych schematów, a zaprezentowane przeze
mnie rozwiązania po prostu wpadły mi do głowy jako pierwsze.
Reprezentacja danych sprowadza się do przełożenia na język C zawartości tabeli 5.2.
Utworzymy dwa oddzielne łańcuchy - jeden na litery, a drugi na liczby. Struktura danych
obsługująca litery ma następuj ącą postać:



Zmienne globalne i funkcja setup
Musisz zdefiniować parę zmiennych globalnych. Jedna z nich będzie określała czas trwania
kropki w alfabecie Morse' a, a druga będzie definiowała złącze, do którego podłączona będzie
dioda LED:

int dotDelay = 200 ;
int ledPi n = 13;

Funkcja setup jest dosyć prosta. Musisz tylko zaprogramować złącze tak, żeby działało
jako wyjście, a także uruchomić port szeregowy:

Kod: Zaznacz cały

void setup() 
{ 
pinMode ( led Pin, OUTPUT) ; 
Serial . begin (9600) ;
}

Na górę