Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
Przedstawia on kanał transmisyjny (ang. transmission chanel). Transmisja odbywa się w ośrodku, który umożliwia przesył sygnałów wybranych do przenoszenia informacji. Ośrodkiem może być np. przestrzeń (fale elektromagnetyczne, światło lasera, promieniowanie podczerwone, itp.), przewód (prąd elektryczny), powietrze (fala akustyczna, ultradźwięki). Sygnał jest wytwarzany przez nadajnik (ang. transmitter), a następnie przemieszcza się przez ośrodek i dociera do odbiornika (ang. receiver). Nadajnik i odbiornik tworzą dopasowaną parę, tzn. odbiornik musi być w stanie odbierać i odpowiednio zinterpretować sygnały wytwarzane przez nadajnik.
Nadajnik otrzymuje informację w postaci bitów, następnie zamienia ją w odpowiednią postać sygnału i wysyła do ośrodka. Sygnał poprzez ośrodek dociera do odbiornika, zostaje odebrany i z powrotem zamieniony w bity. W ten sposób odbywa się transmisja cyfrowa. Zasada jest prosta, diabeł tkwi w szczegółach.
Pierwszy problem polega na doborze właściwego sygnału, który łatwo (czytaj tanio) będzie można wytworzyć, a który skutecznie przeniesie pożądaną informację przez dany ośrodek.
Następny problem pojawia się przy wyborze sposobu przesyłania bitów. Możemy to robić na dwa sposoby: równocześnie przesyłając zadaną liczbę bitów – transmisja równoległa (ang. parallel transmission) lub przesyłając bity pojedynczo jeden za drugim – transmisja szeregowa (ang. serial transmission).
Transmisja równoległa jest szybsza, gdyż naraz przesyła się kilka bitów, jednak wymaga rozdzielnych kanałów transmisyjnych lub skomplikowanego kodowania danych.
Transmisja szeregowa jest wolniejsza, lecz prostsza do zrealizowania. Wymaga pojedynczego kanału transmisji.
Zanim dane będą mogły być przesłane przez ośrodek, muszą zostać odpowiednio ukształtowane w sygnał, który przeniesie je w danym ośrodku. Przy transmisji cyfrowej przesyłamy bity. Bit może występować w dwóch różnych postaciach, które tutaj oznaczamy cyframi 0 i 1. Oczywiście zamiast cyfr mogą to być dwa poziomy napięć, np. w technice TTL bit o stanie 1 reprezentowany jest napięciem 2,4...5V, a bit o stanie 0 reprezentuje napięcie 0...0,8V. Napięcia te są wykorzystywane przez bramki, przerzutniki i sieci logiczne do przetwarzania informacji binarnej. Jeśli chcemy przesyłać bity przez ośrodek, to musimy określić postać sygnału dla bitu o stanie 1 i dla bitu o stanie 0. Przykładowo załóżmy, że będziemy przesyłać informację przewodem elektrycznym za pomocą prądu. Możemy wtedy umówić się, że bit o stanie 1 będzie przesyłany, jeśli w przewodzie płynie prąd, a bit o stanie 0 jest przesyłany, jeśli prąd nie płynie lub ma bardzo małą wartość.
Kształtowanie sygnału na podstawie bitu, który sygnał ma przenosić, nazywamy modulacją (ang. modulation).
Istnieje wiele typów modulacji. Najpierw przyjrzyjmy się parametrom fali sinusoidalnej, która jest najbardziej naturalną postacią sygnału przemieszczającego się przez ośrodek.
Powyższy rysunek przedstawia wykres dwóch funkcji sinusoidalnych w czasie. Czerwoną linią zaznaczyliśmy wykres podstawowy, a zieloną wykres przesunięty w czasie. Na wykresie zaznaczono:
A | – | amplituda, czyli największa wartość funkcji (na moduł) |
T | – | okres, czas, po upływie którego funkcja przyjmuje te same wartości |
φ | – | przesunięcie fazowe |
Funkcja podstawowa ma postać:
Prędkość kątowa ω dana jest wzorem:
Jednostka prędkości kątowej to radiany na sekundę. Po wstawieniu prędkości kątowej do wzoru funkcji otrzymujemy:
Wzór dla funkcji przesuniętej fazowo przyjmuje teraz postać:
Te trzy parametry wykorzystuje się do modulacji sygnału:
Modulacja amplitudy (ang. AM – Amplitude Modulation):
Dla stanów bitów przyjmuje się różne wartości amplitudy:
Jeśli dane są przesyłane szeregowo bit po bicie, to każdy bit
jest przesyłany przez ściśle określony czas i w tym czasie,
zwanym oknem bitowym, sygnał ma stałą amplitudę. Załóżmy, że
przesyłamy w ten sposób daną
Nadajnik przesyłając bit o stanie 0 wysyła w oknie bitowym sygnał o małej amplitudzie (amplituda raczej nie wynosi zero, ponieważ wtedy odbiornik nie może stwierdzić, czy w ogóle odbiera sygnał, zatem nawet dla bitu 0 wybiera się małą amplitudę). Gdy nadajnik przesyła bit o stanie 1, w oknie bitowym transmituje sygnał o dużej amplitudzie. Odbiornik odczytuje amplitudę sygnału w oknie bitowym. Jeśli jest niska, odbiornik "wie", że przesyłany jest bit o wartości 0. Jeśli jest wysoka, odbiornik interpretuje ją jako bit o wartości 1.
Modulacja amplitudy jest prosta w realizacji, jednak jest ona mało odporna na zakłócenia w kanale transmisyjnym.
Przez zakłócenie rozumiemy obcy sygnał (nie wysłany przez nadajnik), który może losowo się pojawić w ośrodku transmisyjnym. Skąd się biorą takie zakłócenia? To zależy od ośrodka oraz rodzaju przesyłanego sygnału. Na przykład przesyłanie za pomocą fal radiowych może być zakłócane przez warunki atmosferyczne, urządzenia elektryczne lub inne nadajniki pracujące w pobliżu. Zakłócenia sumują się z sygnałem i mogą powodować błąd w transmisji. Dla transmisji cyfrowej przez błąd transmisji rozumiemy odebranie bitu o stanie przeciwnym do nadanego. Na przykład:
Kolorem niebieskim zaznaczony jest sygnał zakłócający transmisję. W efekcie sygnał nadajnika zostaje zniekształcony i odbiornik odbiera dwa bity (zaznaczone na czerwono) o stanie przeciwnym do nadanego. Powstaje błąd transmisji. Błędami zajmiemy się w dalszej części rozdziału.
Modulacja częstotliwości (ang. FM – frequency modulation):
Częstotliwość jest liczbą okresów sygnału w ciągu sekundy. Jednostką częstotliwości jest herc Hz. 1Hz jest częstotliwością sygnału, którego okres wynosi 1 sekundę. W praktyce stosowane są większe częstotliwości:
1kHz | kiloherc | = 1000Hz |
1MHz | megaherc | = 1000kHz = 1000.000Hz |
1GHz | gigaherc | = 1000MHz = 1000.000kHz = 1000.000.000Hz |
W tej modulacji przydziela się różne częstotliwości sygnału dla bitu o stanie 0 i dla bitu o stanie 1, które są przesyłane w oknie bitowym. Amplituda sygnału nie jest wykorzystywana:
Transmisja z modulacją częstotliwości jest bardziej odporna na zakłócenia od transmisji z modulacją amplitudy. O ile zakłócenie nie zmieni częstotliwości przesyłanego sygnału, nie wpłynie na odbiór danych. Odbiornik w oknie bitowym bada częstotliwość odebranej fali (można to robić za pomocą odpowiednio dostrojonych filtrów) i na tej podstawie rozróżnia bit o stanie 0 i bit o stanie 1.
Modulacja fazy (ang. PM Phase Modulation):
Stany bitów kodowane są przesunięciem fazowym:
Szybkość transmisji sygnału wyrażamy za pomocą bodów (ang. bauds). Body określają liczbę zmian postaci fali niosącej informację w ciągu jednej sekundy. Jeżeli zmiana oznacza przesłanie jednego bitu, to liczba bodów odpowiada liczbie przesłanych bitów w ciągu jednej sekundy. Lecz czasem stosuje się kilka modulacji jednocześnie w celu zwiększenia liczby przesyłanych bitów w danej jednostce czasu. Dla przykładu załóżmy, że stosujemy jednocześnie modulację amplitudy i modulację częstotliwości. Fala nośna będzie w takim przypadku mogła przybierać 4 różne postacie, które umożliwią jednoczesne przesyłanie dwóch bitów:
Zwróć uwagę, że stosując dwie modulacje w jednym oknie bitowym przesyłane są po dwa bity jednocześnie, zatem prędkość transmisji wzrasta dwukrotnie. Dodając kolejne modulacje można zwiększyć liczbę bitów. W ten sposób zwiększa się przepustowwość kanału transmisyjnego.
Z tego typu modulacjami spotkasz się przy przesyłaniu danych za pomocą fal radiowych, np. w telewizji cyfrowej.
Do formowania i odbioru sygnałów służą urządzenia zwane modemami (ang. modulator + demodulator). Zawierają one dwa elementy: nadajnik i odbiornik sygnału, który jest dopasowany do ośrodka transmisyjnego. Modemy współpracują z mikrokontrolerami:
W praktyce amatorskiej dane będą przesyłane najczęściej przewodem za pomocą prądu elektrycznego na nieduże odległości (do kilku metrów). W takim przypadku nadajniki i odbiorniki można wykonać w prosty sposób z kilku tranzystorów lub zastosować gotowe układy transmisyjne. Większość współczesnych mikrokontrolerów posiada tego typu elementy już wbudowane w swoją strukturę.
Przesyłanie danych na małą odległość nie wymaga zwykle skomplikowanych układów. Można nawet wykorzystać zwykłe bramki cyfrowe:
Do transmisji potrzebny jest przewód dwużyłowy. Jedną żyłą przesyłane są dane, druga podłączona jest w obu urządzeniach do masy. Przewód może mieć długość kilka metrów. jako nadajnik dobrze jest zastosować bramkę mocy.
Lepszym rozwiązaniem jest zastosowanie gotowego układu nadajnika linii. W handlu można spotkać wiele typów takich układów. Na przykład:
SN75450 |
||
SN75451 |
SN75452 |
|
SN75453 |
SN75454 |
Układy mogą pełnić rolę nadajników. W zależności od typu zawierają dwie bramki NAND (SN75450/SN75451), AND (SN75452), NOR (SN75453) lub OR (SN75454) oraz dwa tranzystory npn z otwartymi obwodami kolektorów. Takie rozwiązanie pozwala stosować różne konfiguracje nadajników (najbardziej uniwersalny jest układ SN75450):
Jeśli linia transmisyjna jest dłuższa niż kilka metrów, to problem przesyłania danych komplikuje się, ponieważ w takiej linii pojawiają się pojemności i indukcyjności pasożytnicze, które zakłócają transmitowany sygnał. Dodatkowo dłuższe przewody są czułe na zewnętrzne pola elektryczne i magnetyczne. W takich przypadkach dane przesyła się dwoma liniami w ten sposób, iż sygnały mają w nich fazy przeciwne. Zakłócenia znoszą się wzajemnie w obu przewodach. Odbiornikiem jest wzmacniacz różnicowy:
Do przesyłania i odbioru danych poprzez długą linię stosuje się zwykle gotowe układy scalone nadajników i odbiorników, np. SN75121/SN75122, SN65LVDS1, SN65LVDS2, itp.
W transmisji równoległej bity są przesyłane jednocześnie grupami, np. po 8 bitów. Transmisja wymaga osobnych kanałów dla każdego bitu grupy. W latach 90-tych ubiegłego wieku większość produkowanych wtedy komputerów posiadała złącze równoległe Centronics, które było wykorzystywane do transmisji danych do drukarki:
Gniazdo Centronics | Wtyczka Centronics |
Wraz z upowszechnieniem się standardu USB złącza Centronics zniknęły z komputerów PC, jednakże ich składniki są wciąż dostępne w sprzedaży i możesz je wykorzystywać we własnych projektach. Informację bez trudu znajdziesz w sieci.
Transmisja równoległa jest kłopotliwa przy wyższych prędkościach przesyłu, ponieważ poszczególne kanały oddziałują na siebie wzajemnie i należy je ekranować. Jeśli jednak linia przesyłu danych (zwana tutaj zwykle magistralą) nie jest zbyt długa, a szybkość transmisji nie jest zbyt duża, to do przesyłania sygnałów można wykorzystać zwykłą taśmę wieloprzewodową:
Aby uniknąć zakłóceń, żyły sygnałowe przedziela się żyłami masy.
W ten sposób możesz przesyłać dane pomiędzy różnymi elementami swojego urządzenia: wyświetlaczami, klawiaturami, pamięciami, mikrokontrolerami, itp.
W transmisji szeregowej bity są przesyłane kolejno jeden za drugim. Zaletą jest tutaj to, iż naraz przesyłany jest jeden sygnał, zatem prostsza staje się jego ochrona przed zakłóceniami. Drugą zaletą jest mała liczba linii sygnałowych niezbędnych do realizacji transmisji, co jest istotne szczególnie w przypadku mikrokontrolerów, gdzie liczba dostępnych portów wejścia/wyjścia jest ograniczona. Typowym przykładem transmisji szeregowej jest powszechnie stosowany obecnie standard USB (ang. Universal Serial Bus – uniwersalna magistrala szeregowa), który doczekał się już wersji nr 3. W użyciu są również inne standardy, które krótko opiszemy dalej. Współczesne mikrokontrolery posiadają zwykle elementy do transmisji szeregowej, co jest olbrzymim ułatwieniem dla konstruktorów.
Transmisję równoległą i szeregową dzielimy dalej na transmisję z potwierdzeniem odbioru i na transmisję bez potwierdzenia odbioru.
W przypadku transmisji z potwierdzeniem (ang. handshake transmission) odbiornik posiada dodatkowy kanał zwrotny, którym przesyła sygnał potwierdzający odebranie danych ACK (ang. acknowledgment, potwierdzenie). Nadajnik w odpowiedzi na ten sygnał może przesłać kolejną porcję danych. W tego rodzaju transmisji można łatwo zrealizować transmisję z powtórzeniem w przypadku błędu. Odbiornik po stwierdzeniu błędu w odebranych danych wysyła do nadajnika specjalny sygnał negatywnego potwierdzenia NACK (ang. negative acknoledgment). W odpowiedzi nadajnik powtarza jeszcze raz transmisję danych.
W transmisji bez potwierdzenia nadajnik wysyła dane, lecz nie sprawdza, czy zostały odebrane. Tak jest np. w przypadku telewizji cyfrowej. Dane są zwykle odpowiednio kodowane, tak aby umożliwić odbiornikowi naprawę błędów transmisji.
Kolejny podział daje nam transmisję synchroniczną i asynchroniczną.
W transmisji synchronicznej (ang. synchronous transmission) oprócz sygnału danych przesyłany jest sygnał synchronizujący, który ułatwia odbiornikowi odczyt informacji. Sygnał synchronizacji przesyłany jest zwykle osobnym kanałem transmisyjnym, zatem dla transmisji szeregowej wymagane są dwie linie przesyłowe:
Narastające zbocza impulsów zegarowych wyznaczają moment odczytu danych przez odbiornik. Ten rodzaj transmisji pozwala przesyłać dane z różnymi prędkościami.
W transmisji asynchronicznej (ang. asynchronous transmission) przesyłany jest tylko sygnał danych, lecz ustala się stałą prędkość transmisji. Dane poprzedzane są zwykle tzw. bitem startu, który nie należy do danych, lecz pozwala odbiornikowi wykryć początek transmisji. Po przesłaniu odpowiedniej liczby bitów przesyłany jest bit stopu o wartości przeciwnej do bitu startu. Gdy prędkość transmisji jest ustalona i stała, odbiornik po wykryciu bitu startu odczytuje z odpowiednią prędkością bity danych, a po odebraniu bitu stopu czeka na kolejną porcję bitów:
Transmisja asynchroniczna jest chętnie stosowana, ponieważ przy szeregowym przesyle danych wymaga tylko jednej linii transmisyjnej.
Ostatni podział daje nam transmisję duplex i simplex (pół duplex).
Transmisja duplex polega na możliwości przesyłania informacji w obu kierunkach jednocześnie. Oba urządzenia komunikujące się posiadają nadajniki i odbiorniki, które łączą się dwoma kanałami transmisyjnymi:
W transmisji simplex mamy jeden kanał transmisyjny, który jest wykorzystywany naprzemiennie przez oba urządzenia do transmisji dwukierunkowej, jednak w danej chwili transmisja jest możliwa tylko w jednym kierunku:
Transmisja cyfrowa polega na przesyłaniu bitów. Bity mogą przyjmować tylko dwa różne stany, które umownie oznaczamy tu cyframi 0 (stan niski) i 1 (stan wysoki). Błąd wystąpi wtedy, gdy odbiornik odbierze bit o stanie przeciwnym do nadanego: tzn. nadajnik wysyła bit o stanie 1, a odbiornik odbiera go jako bit o stanie 0 lub na odwrót.
Jeśli nie stosuje się żadnych zabezpieczeń przed błędami, to odbiornik nie jest w stanie stwierdzić, czy odebrana informacja jest lub nie jest poprawna. Transmisja bez zabezpieczeń stosowana jest zwykle wtedy, gdy prawdopodobieństwo wystąpienia błędów jest bardzo małe, np. wewnętrzne przesłania danych pomiędzy elementami urządzenia. Gdy błędy mogą się pojawić, a informacja jest istotna, należy zabezpieczać transmisję.
Zabezpieczenie informacji polega na jej odpowiednim kodowaniu. Wymyślono dwa rodzaje kodów zabezpieczających:
Jeden z najprostszych kodów detekcyjnych to tzw. bit parzystości (ang. parity bit). Polega to na tym, iż do przesyłanych danych dołączamy jeden dodatkowy bit. Stan bitu ustalamy, tak aby liczba jedynek w całym słowie była parzysta:
Dane | BP | Wynik |
0000 | 0 | 00000 |
0110 | 0 | 01100 |
0100 | 1 | 01001 |
1110 | 1 | 11101 |
Tak przygotowane słowo kodowe przesyłamy przez kanał transmisyjny. Jeśli nastąpi przekłamanie jednego bitu (ogólnie nieparzystej liczby bitów), to zmieni się parzystość słowa:
Jeśli bit o stanie 1 zostanie odebrany jako bit o stanie 0, to zmaleje liczba jedynek i słowo będzie posiadało ich nieparzystą liczbę:
Jeśli bit o stanie 0 zostanie odebrany jako bit o stanie 1, to wzrośnie liczba jedynej i słowo będzie zawierało ich nieparzystą liczbę:
W obu przypadkach odebrane słowo traci parzystość. Na tej podstawie odbiornik wie, że dane zawierają błąd. Kanałem zwrotnym odbiornik może zażądać powtórzenia transmisji (NACK).
Bit parzystości łatwo wygenerować za pomocą bramek EX-OR:
|
Po stronie nadajnika stosowany jest podobny układ z dodatkową bramką EX-OR:
Na wyjściu ERROR pojawia się stan 1, jeśli liczba jedynek w odebranym słowie jest nieparzysta, a zatem gdy jeden z bitów zostanie odebrany błędnie. Jeśli wyjście ERROR ma stan logiczny 0, to bity A...H zostały odebrane poprawnie lub wystąpiły błędy parzyste.
W praktyce stosowane są gotowe układy zawierające generator bitu parzystości, np. SN74180. Mikrokontrolery zwykle posiadają wbudowane elementy transmisyjne zawierające tę funkcję.
Bit parzystości pozwala wykrywać tylko błędne odebranie nieparzystej liczby bitów. Jeśli błąd wystąpi na parzystej liczbie bitów (2,4,6...), to nie zostanie wykryty, ponieważ zmiana parzystej liczby bitów na przeciwne nie zmienia parzystości słowa. Spróbuj to uzasadnić.
Bity parzystości zabezpieczają dane o niewielkiej liczbie bitów (8, 16). Spowodowane jest to tym, iż w długim ciągu bitów rośnie prawdopodobieństwo błędu podwójnego, który przez ten system nie jest rozpoznawany. Do zabezpieczania większej liczby bitów stosuje się tzw. sumy kontrolne (ang. checksums). Zasada jest następująca:
Przesyłaną informację dzieli się na słowa o stałej liczbie bitów (najczęściej 8, czyli na bajty). Słowa te przesyłane są przez kanał transmisyjny bez zabezpieczenia lub z bitem parzystości. Po przesłaniu słowa traktowane jako liczby dwójkowe dodaje się je do sumy kontrolnej, która na początku transmisji jest zerowana. Gdy cała informacja zostanie przesłana, nadajnik wysyła do odbiornika sumę kontrolną.Po stronie odbiorczej odbiornik na początku transmisji zeruje swoją sumę kontrolną, po czym odbiera poszczególne słowa bitowe, dodając je do swojej sumy. Na końcu transmisji odbiera sumę kontrolną i porównuje ją ze swoją sumą. Jeśli obie sumy są równe, to zakłada, że dane odebrano poprawnie. Jeśli nie, występuje błąd sumy kontrolnej (ang. checksum error), co sygnalizuje błąd w odebranych danych. Na tej podstawie odbiornik może zażądać powtórzenia transmisji.
Zaletą sum kontrolnych jest to, iż są krótkie bitowo w porównaniu z liczbą bitów danych. Np. 16 bitów sumy kontrolnej na 1024 bitów danych.
Sumy kontrolne mogą być tworzone w sposób sprzętowy lub programowy. Poniżej przedstawiony jest przykładowy program w języku C (Code Blocks) symulujący transmisję z 4-bitową sumą kontrolną 16 danych 4-bitowych.
/* SYMULATOR TRANSMISJI Z SUMĄ KONTROLNĄ (C)2018 mgr Jerzy Wałaszek */ #include <stdio.h> #include <stdlib.h> #include <time.h> /* Funkcja wyświetla 4 najmłodsze bity */ void print4b(int x) { int mask = 8; // maska bitowa: while(mask) { if(x & mask) printf("1"); else printf("0"); mask >>= 1; } } int main() { // Zmienne int tchksum,rchksum,i,td,rd,e; // Inicjujemy generator pseudolosowy srand((unsigned int)time(NULL)); // Przygotowujemy sumy kontrolne nadajnika i odbiornika tchksum = rchksum = 0; printf("NADAJNIK ODBIORNIK\n"); printf("dane suma dane suma\n"); printf("--------->>>>>---------\n"); printf(" 0000 0000\n"); // Transmisja --- Zakłócenie --- Odbiór for(i = 0; i < 16; i++) { td = rand() % 16; // dane nadawane tchksum += td; // uaktualniamy sumę nadajnika tchksum &= 0xf; // obcinamy sumę do 4 bitów print4b(td); printf(" "); print4b(tchksum); rd = td; // dane odbierane e = 0; while(!(rand() % 16)) // błędy transmisji { e = 1; rd ^= 1 << (rand() % 4); } if(e) printf(" (X) "); else printf(" (-) "); rchksum += rd; // uaktualniamy sumę odbiornika rchksum &= 0xf; // obcinamy sumę do 4 bitów print4b(rd); printf(" "); print4b(rchksum); printf("\n"); } // Transmisja sumy kontrolnej printf(" "); print4b(tchksum); e = 0; while(!(rand() % 16)) // błędy transmisji { e = 1; tchksum ^= 1 << (rand() % 4); } if(e) printf(" (X) "); else printf(" (-) "); print4b(tchksum); printf(" "); print4b(rchksum); printf("\n"); printf("-----------------------\n"); if(tchksum == rchksum) printf(" DANE POPRAWNE\n\n"); else printf(" DANE USZKODZONE\n\n"); return 0; } |
Program wyświetla dane nadawane oraz odbierane. Dodatkowo po przesłaniu każdej danej wyświetlane są sumy kontrolne nadajnika i odbiornika. Jeśli w trakcie transmisji pojawi się błąd, to zostanie wyświetlony napis (X). Jeśli nie było błędu, pojawi się napis (-):
NADAJNIK ODBIORNIK dane suma dane suma --------->>>>>--------- 0000 0000 0000 0000 (-) 0000 0000 1110 1110 (-) 1110 1110 0010 0000 (-) 0010 0000 0111 0111 (-) 0111 0111 1101 0100 (-) 1101 0100 0100 1000 (-) 0100 1000 1101 0101 (-) 1101 0101 1010 1111 (-) 1010 1111 0010 0001 (-) 0010 0001 1110 1111 (-) 1110 1111 0101 0100 (-) 0101 0100 1000 1100 (-) 1000 1100 1110 1010 (-) 1110 1010 0110 0000 (-) 0110 0000 0101 0101 (-) 0101 0101 0100 1001 (-) 0100 1001 1001 (-) 1001 1001 ----------------------- DANE POPRAWNE |
NADAJNIK ODBIORNIK dane suma dane suma --------->>>>>--------- 0000 0000 1000 1000 (-) 1000 1000 0011 1011 (-) 0011 1011 1000 0011 (-) 1000 0011 1001 1100 (-) 1001 1100 1000 0100 (-) 1000 0100 0110 1010 (-) 0110 1010 1111 1001 (X) 1110 1000 1110 0111 (-) 1110 0110 0011 1010 (-) 0011 1001 0110 0000 (-) 0110 1111 0101 0101 (X) 0111 0110 1010 1111 (-) 1010 0000 0101 0100 (-) 0101 0101 0110 1010 (-) 0110 1011 1111 1001 (-) 1111 1010 0010 1011 (-) 0010 1100 1011 (-) 1011 1100 ----------------------- DANE USZKODZONE |
Algorytm tworzenia sum kontrolnych jest zwykle bardziej skomplikowany. Informacje na ten temat znajdziesz w sieci.
Jedną z bardziej popularnych metod zabezpieczania danych przed błędami jest metoda cyklicznej kontroli nadmiarowej CRC (ang. cyclic redundancy check). Polega ona na dołączaniu do danych reszty z dzielenia tych danych przez odpowiednio dobrany dzielnik. Dzielniki dobiera się matematycznie wg kryterium największej skuteczności w wykrywaniu błędów.
Zasadę działania tej metody najlepiej jest zrozumieć na podstawie przykładu:
Załóżmy, że chcemy przesłać dane 8-mio bitowe: 00110111. Wybieramy dzielnik 4-bitowy 1011.
Zapisujemy dane, a pod nimi dzielnik:
00110111 1011 |
Do danych dopisujemy 3 bity o stanie 0 (reszta z dzielenia przez 4-bitowy dzielnik jest maksymalnie 3-bitowa):
00110111000
1011 |
Dzielnik przesuwamy w prawo, aż nad jego najstarszym bitem o wartości 1 znajdzie się bit 1 danych:
00110111000
1011 |
Wykonujemy operację EX-OR na poszczególnych bitach danych i dzielnika. Wynik zapisujemy pod spodem:
00110111000 1011 00011011000 |
Dzielnik zapisujemy pod wynikiem i znów przesuwamy go w prawo aż nad jego najstarszym bitem 1 pojawi się bit 1 danych:
00110111000 1011 00011011000 1011 |
Wykonujemy operację EX-OR i wynik zapisujemy pod spodem:
00110111000 1011 00011011000 1011 00001101000 |
Powtarzamy:
00110111000 1011 00011011000 1011 00001101000 1011 00000110000 |
Powtarzamy:
00110111000 1011 00011011000 1011 00001101000 1011 00000110000 1011 00000011100 |
Powtarzamy:
00110111000 1011 00011011000 1011 00001101000 1011 00000110000 1011 00000011100 1011 00000001010 |
Powtarzamy:
00110111000 1011 00011011000 1011 00001101000 1011 00000110000 1011 00000011100 1011 00000001010 1011 00000000001 |
Koniec, ponieważ wszystkie bity danych są wyzerowane. Reszta z dzielenia jest w dodanych trzech bitach CRC i wynosi 001. Dołączamy ją do danych i przesyłamy do odbiornika jako: 00110111001.
Jeśli w czasie transmisji nie było błędów, to odbiornik odbierze bity: 00110111001. Wykonuje na nich te same operacje, które wykonywał wcześniej nadajnik:
00110111001 1011 00011011001 1011 00001101001 1011 00000110001 1011 00000011101 1011 00000001011 1011 00000000000 |
Zwróć uwagę, że teraz dodatkowe bity CRC wyzerowały się. Jest to znak, że dane zostały odebrane poprawnie.
Załóżmy, że w trakcie transmisji doszło do dwóch błędów i odbiornik odebrał dwa bity o stanie przeciwnym do nadanego, np.: 00111101001
00111101001 1011 00010011001 1011 00000101001 1011 00000000101 |
Obliczenia skończyły się wcześniej, ponieważ wszystkie bity danych zostały wyzerowane. Bity CRC nie wyzerowały się, zatem dane odebrano z błędami.
Poniżej prezentujemy prostą symulację przesłania danych z CRC napisaną w języku C (Code Blocks):
/* SYMULATOR TRANSMISJI Z CRC (C)2018 mgr Jerzy Wałaszek */ #include <stdio.h> #include <stdlib.h> #include <time.h> /* Funkcja wyświetla n bitów liczby x */ void printnb(int x, int n) { int mask = 1 << (n - 1); // maska bitowa: while(mask) { if(x & mask) printf("1"); else printf("0"); mask >>= 1; } } /* Funkcja wyświetla zadaną liczbę spacji */ void printns(int n) { while(n--) printf(" "); } int main() { // Zmienne int td,rd,d,p,i,e; // Inicjujemy generator pseudolosowy srand((unsigned int)time(NULL)); printf("SYMULATOR TRANSMISJI DANYCH Z CRC\n"); printf("=================================\n"); // Losujemy dane do wysłania td = rand() & 0x1f; printf("NADAJNIK:"); printf("\nDANE = "); printnb(td,5); printf("\nCRC = "); d = td << 3; // Dołączamy 3 bity 0 printnb(d,8); // Wyliczamy CRC dzieląć przez wielomian 1011 while(d & 0xf8) { // Wyznaczamy pozycję pierwszego bitu 1 w danych p = 7; while(!(d & (1 << p))) p--; // Pozycjonujemy wielomian na wydruku printf("\n"); printns(15 - p); // Tworzymy dzielnik p = 11 << (p - 3); // Wyświetlamy dzielnik printnb(11,4); // Modyfikujemy wynik d ^= p; // Wyświetlamy wynik printf("\n"); printns(8); printnb(d,8); } printf("\nWYNIK = "); td = (td << 3) | d; printnb(td,8); // Transmisja z ewentualnymi błędami printf("\n\nNADAJNIK --------> ODBIORNIK\n"); printf("============================\n"); printnb(td,8); rd = td; e = 0; // Błędy for(i = 0; i < 11; i++) if(!(rand() % 8)) { e = 1; rd ^= (1 << i); // negujemy i-ty bit } if(e) printf(" ---(X)---> "); else printf(" ---------> "); printnb(rd,8); // Sprawdzenie sumy kontrolnej d = rd; while(d & 0xf8) { // Wyznaczamy pozycję pierwszego bitu 1 w danych p = 11; while(!(d & (1 << p))) p--; // Pozycjonujemy wielomian na wydruku printf("\n"); printns(27 - p); // Tworzymy dzielnik p = 11 << (p - 3); // Wyświetlamy dzielnik printnb(11,4); // Modyfikujemy wynik d ^= p; // Wyświetlamy wynik printf("\n"); printns(20); printnb(d,8); } rd >>= 3; printf("\nDANE = "); printnb(rd,5); printf(" CRC = "); printnb(d,3); if(!d) printf(" ACK\n\n"); else printf(" NACK!!!\n"); return 0; } |
Symulacja jest dwuetapowa. Najpierw generowane są dane 5-bitowe. Następnie nadajnik wylicza dla nich CRC. Dane są łączone z obliczonym CRC i przesyłane. W trakcie transmisji mogą pojawić się błędy przekłamujące odebrane bity. W takim przypadku wyświetlany jest symbol (X). Drgi etap polega na wyznaczeniu CRC odebranych danych. Jeśli CRC zeruje się, to dane zostały odebrane poprawnie i odbiornik wysyła potwierdzenie ACK. Jeśli dla odebranych danych CRC nie zeruje się, to odebrane zawierają błąd i nadajnik wysyła potwierdzenie negatywne NACK.
SYMULATOR TRANSMISJI DANYCH Z CRC ================================= NADAJNIK: DANE = 10101 CRC = 10101000 1011 00011000 1011 00001110 1011 00000101 WYNIK = 10101101 NADAJNIK --------> ODBIORNIK ============================ 10101101 ---------> 10101101 1011 00011101 1011 00001011 1011 00000000 DANE = 10101 CRC = 000 ACK |
SYMULATOR TRANSMISJI DANYCH Z CRC ================================= NADAJNIK: DANE = 00110 CRC = 00110000 1011 00011100 1011 00001010 1011 00000001 WYNIK = 00110001 NADAJNIK --------> ODBIORNIK ============================ 00110001 ---(X)---> 00100001 1011 00001101 1011 00000110 DANE = 00100 CRC = 110 NACK!!! |
Kodowanie CRC jest bardzo popularne ze względu na prostotę implementacji. Spotkasz się z nim w sieciach komputerowych oraz przy zapisie/odczycie na dyski twarde. Przy większej ilości bitów danych kod CRC ma długość 16, 32 lub 64 bity. Dzielniki CRC znormalizowano i znajdziesz je w sieci.
Kody korekcyjne mają za zadanie usunąć przekłamania bitów, gdy dojdzie do błędów transmisji. Stosuje się je tam, gdzie nie ma możliwości powtórzenia transmisji danych (np. telewizja cyfrowa) lub powtórzenie nie usuwa błędu (np. porysowany dysk DVD). Kody korekcyjne są zwykle skomplikowane i dokładne omówienie ich wykracza poza ramy tego artykułu. Niemniej możemy podać przykład prostego kodu korekcyjnego, który usuwa przekłamanie 1 bitu w trakcie transmisji. Jest to tzw. kod korekcyjny Hamminga (ang. Hamming's correction code). Kod ten wykorzystuje w specyficzny sposób bity parzystości.
Pokażemy jak skonstruować słowo kodowe. Załóżmy, że chcemy przesłać 4-bitowe słowo danych 1011. Dla 4 bitów danych słowo kodowe będzie zbudowane z 7 bitów. Dodatkowe 3 bity służą do korekcji. Ponumerujmy bity od najmłodszego do najstarszego:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
Bity o numerach będących potęgami liczby 2 są bitami kontrolnymi, pozostałe bity są bitami danych:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
x | x | x |
Wpisujemy w bity danych przesyłane bity kolejno od największego do najmniejszego:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
1 | 0 | 1 | x | 1 | x | x |
Wypiszmy dwójkowo numery bitów, które mają stan 1:
7 | 1 | 1 | 1 |
5 | 1 | 0 | 1 |
3 | 0 | 1 | 1 |
Teraz w pionowych kolumnach dodajmy bit parzystości (liczba bitów 1 w kolumnie ma być parzysta):
7 | 1 | 1 | 1 |
5 | 1 | 0 | 1 |
3 | 0 | 1 | 1 |
0 | 0 | 1 |
Otrzymaliśmy kolejne bity kontrolne, które wpisujemy w słowo kodowe:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
1 | 0 | 1 | 0 | 1 | 0 | 1 |
Dla danych 1011 słowo kodu Hamminga ma postać: 1010101. Słowo to przesyłamy do odbiornika. Załóżmy, że w trakcie transmisji przekłamaniu uległ bit b6 i odbiornik odebrał słowo kodowe:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
1 | 1 | 1 | 0 | 1 | 0 | 1 |
Wypisujemy dwójkowo wszystkie pozycje bitów o stanie 1, uwzględniając również bity kontrolne:
7 | 1 | 1 | 1 |
6 | 1 | 1 | 0 |
5 | 1 | 0 | 1 |
3 | 0 | 1 | 1 |
1 | 0 | 0 | 1 |
Wyznaczamy bity parzystości w kolumnach:
7 | 1 | 1 | 1 |
6 | 1 | 1 | 0 |
5 | 1 | 0 | 1 |
3 | 0 | 1 | 1 |
1 | 0 | 0 | 1 |
1 | 1 | 0 |
Jeśli otrzymamy wszystkie bity 0, to znaczy, że informacja została odebrana bez błędów. W przeciwnym razie otrzymane bity traktujemy jako liczbę dwójkową 1102 = 6, która wskazuje pozycję bitu odebranego błędnie. Ponieważ błąd cyfrowy polega na odebraniu bitu o stanie przeciwnym do nadanego, zmieniamy stan bitu b6 w odebranym słowie:
b7 | b6 | b5 | b4 | b3 | b2 | b1 |
1 | 0 | 1 | 0 | 1 | 0 | 1 |
Usuwamy bity kontrolne i otrzymujemy przesłaną informację 1011.
Kod Hamminga potrafi naprawić jeden bit w odebranych danych. Gdy liczba błędów może być większa, stosowane są bardziej zaawansowane kody korekcyjne, np. kod Salomona-Reeda (płyty CD/DVD). Są to zagadnienia skomplikowane i zainteresowanych odsyłam do informacji w sieci.
W latach 90-tych wszystkie komputery PC posiadały złącze RS-232 (ang. recommended standard 232), które umożliwiało szeregowe przesyłanie danych. Obecnie standard USB zastąpił je całkowicie i w nowych komputerach nie spotkamy tego złącza. Niestety, komunikacja złączem USB jest dosyć skomplikowana, jednakże za niewielkie pieniądze możesz zakupić konwerter USB–RS-232:
Jeśli będziesz stosował moduły Arduino, to mają one już wbudowany taki konwerter.
UART przesyła/odbiera bajty danych bit po bicie w sposób szeregowy.
Układ posiada dwie asynchroniczne linie transmisyjne:
Transmisja rozpoczyna się od wysłania bitu startowego o stanie 0, po czym wysyłane jest 5...9 bitów danych, ewentualny bit parzystości, a na końcu przesyłany jest bit stopu, który może zostać przedłużony na dowolną liczbę bitów stopu:
Parametry transmisji (liczba bitów danych, bity parzystości, szybkość transmisji) nadajnika i odbiornika muszą być takie same, a ustawia się je w sposób określony przez producenta w dokumentacji układu UART. Gdy odbiornik skompletuje bajt danych, ustawia odpowiedni znacznik informujący, że dane są gotowe do odczytu lub generuje tzw. przerwanie, a w odpowiedzi mikrokontroler odczytuje dane i przetwarza je.
Transmisja może być prowadzona w jednym kierunku (simplex), w obu kierunkach jednocześnie (duplex) lub na zmianę raz w jednym a raz w drugim kierunku (duosimplex).
Nadajnik po otrzymaniu bajta danych z magistrali wpisuje go do swojego rejestru przesuwającego, po czym przez odpowiedni czas generuje na wyjściu bit startu o stanie niskim, następnie przesuwa dane w rejestrze z odpowiednią szybkością. Wyjście szeregowe rejestru jest połączone z linią Tx. W ten sposób na linii Tx pojawiają się kolejne bity danych od najmłodszego do najstarszego. Gdy cała zawartość rejestru zostanie przesłana, nadajnik generuje bit stopu o stanie wysokim, po czym oczekuje na kolejny bajt danych do przesłania.
Odbiornik z odpowiednio dużą częstotliwością (przynajmniej 8 razy większą od częstotliwości przesyłania bitów) testuje stan linii Rx. Gdy wykryje stan niski, po okresie bitu startu rozpoczyna cykliczny wpis stanu tej linii do rejestru przesuwającego. Po każdym wpisie dane w rejestrze są przesuwane, w ten sposób tworzony jest bajt. Gdy do rejestru trafią wszystkie bity, odbiornik czeka na bit stopu, po czym sygnalizuje gotowość danych do odczytu. Po odczycie przez mikrokontroler danych odbiornik wraca do trybu oczekiwania na transmisję danych.
Połączenie dwóch układów UART wygląda następująco:
Jeśli transmisja ma być wykonana na większą odległość, to linie Tx i Rx należy dołączyć do odpowiednich nadajników/odbiorników linii, aby uniknąć zakłóceń.
Oprócz układów do transmisji asynchronicznej produkowane są ich odpowiedniki dla transmisji synchronicznej:
Układami UART zajmiemy się dokładniej w sekcji poświęconej programowaniu mikrokontrolerów.
Oryginalna prędkość transmisji I2C jest równa 100kb na sekundę. opracowano również standardy 400kb (fast mode), 1Mb (fast mode plus) i 3,4Mb (high speed mode) na sekundę. Sam protokół I2C jest dosyć skomplikowany, na szczęście dostępne jest dużo bibliotek dla różnych mikrokontrolerów, które go implementują.
Transmisja I2C prowadzona jest dwoma liniami:
Stanem aktywnym jest stan niski, który uzyskuje się przez zwarcie danej linii do masy za pomocą tranzystora z otwartym kolektorem (wersja bipolarna) lub otwartym drenem (wersja polowa). Dzięki takiemu rozwiązaniu dane mogą być przesyłane pomiędzy układami o różnych poziomach zasilania. Do linii można podłączać wiele układów, dlatego nazywane są one magistralą I2C (ang. I2C bus).
Typowe połączenie magistralą I2C wygląda następująco:
Oporniki R służą do podciągania napięcia na liniach SCL i SDA, gdy nie są one zwierane do masy przez jeden z układów. Tymi samymi liniami magistrali mogą przesyłać dane więcej niż dwa układy:
W czasie transmisji danych pomiędzy dwoma układami jeden z nich pełni rolę nadrzędną (ang. master), a drugi jest podporządkowany (ang. slave). Sygnał zegarowy na linii SCL zawsze wytwarza bieżący układ nadrzędny. Układ podporządkowany może zwierać ten sygnał do masy, jeśli nie jest gotowy na przesłanie lub przyjęcie danych. Oporniki podciągające R przywracają wysoki stan na liniach I2C, gdy żaden układ nie zwiera ich do masy.
Przesłanie danych odbywa się ściśle wg protokołu I2C. Jest on bardziej skomplikowany od protokołu UART, ponieważ do magistrali I2C może być przyłączone wiele układów, zatem przed rozpoczęciem przesłania danych należy określić nadawcę i odbiorcę. Na szczęście większość układów współpracujących z magistralą I2C zawiera już odpowiednią implementację protokołu. Dane na magistrali będziemy nazywać wiadomościami (ang. messages). Wiadomość składa się z dwóch rodzajów ramek (ang. frames):
Pojawia się ona w wiadomości zawsze jako pierwsza. Celem tej ramki jest zaadresowanie właściwego układu Slave oraz poinformowanie go o trybie transmisji, tzn. czy ma odbierać, czy przesłać dane w następnych ramkach.
Transmisję rozpoczyna układ Master przez pozostawienie linii SCL (zegar) w stanie wysokim i ustawienie linii SDA (dane) w stan niski:
Jest to sygnał dla wszystkich układów Slave, że za chwilę rozpocznie się transmisja. Jeśli na magistrali I2C obecnych jest kilka układów Master, to może się zdarzyć, iż dwa lub więcej z nich rozpoczną transmisję. W takim przypadku kontrolę nad magistralą przejmuje ten, który jako pierwszy ustawił linię SDA w stan niski. Protokół I2C obejmuje powtórzenia startu transmisji.
Po starcie na linia SCL jest ustawiana w stan niski, a na linii SDA są umieszczane kolejne bity danych adresowych, które są odczytywane przez układy Slave przy narastających zboczach impulsów zegarowych na linii SCL. Najpierw przesyłane są bity adresu (zwykle 7 bitów w kolejności od najstarszego do najmłodszego), po nich idzie bit zapisu/odczytu R/W, który informuje zaadresowane urządzenie Slave, czy transmisja danych będzie do niego (zapis, Write), czy też od niego (odczyt, Read). Na końcu przesyłany jest bit potwierdzenia o stanie wysokim. Po przesłaniu 8 pierwszych bitów (7 bitów adresu + bit R/W) układ Master oddaje sterowanie linią SDA układowi Slave, który w bicie potwierdzenia powinien wymusić na tej linii stan niski, co oznacza gotowość na wykonanie operacji:
Po pozytywnym przesłaniu ramki adresowej układ Master kontynuuje generowanie impulsów zegarowych i są przesyłane ramki danych (ich ilość jest dowolna i zależna od typu komunikujących się układów). Dane na linii SDA są umieszczane przez układ Master przy zapisie lub przez układ Slave przy odczycie (określa to bit R/W w ramce adresowej). Ramki danych przesyłają 8 bitów (od najstarszego do najmłodszego) oraz 9-ty bit potwierdzenia (potwierdza odbiorca):
Gdy transmisja ramek danych zostanie ukończona układ Master ustawia linię SCL w stan wysoki, po czym również ustawia linię SDA w stan wysoki i tak pozostaje do następnej transmisji:
Więcej na temat protokołu I2C znajdziesz w sieci (adresowanie 10-bitowe, wznawianie transmisji, rozciąganie impulsów zegarowych, itp.). Zagadnienie jest zbyt obszerne, aby opisać je w małym podrozdziale. Podane tutaj informacje potraktuj tylko jako wstęp.
Znaczenie sygnałów jest następujące:
SCLK | – | (ang. Serial CLocK) impulsy zegarowe synchronizujące transmisję. |
MOSI | – | (ang. Master Output, Slave Input) wyjście danych z urządzenia Master, wejście danych dla urządzenia Slave. |
MISO | – | (ang. Master Input, Slave Output) wejście danych dla urządzenia Master, wyjście danych dla urządzenia Slave. |
SS | – | (ang. Slave Select) uaktywnienie urządzenia Slave. |
Jeśli kilka urządzeń podporządkowanych ma być podłączone pod wspólną magistralę SPI, to do każdego z nich należy doprowadzić osobny sygnał SS:
Istnieje również możliwość łączenia niektórych urządzeń Slave w pierścień z urządzeniem Master.
Takie rozwiązanie pozwala stosować tylko 4 linie do transmisji SPI. Dane są przesyłane szeregowo od urządzenia Master do pierwszego urządzenia Slave, które następnie retransmituje je do następnego urządzenia Slave, itd. Urządzenie Master musi w tym przypadku zapewnić odpowiednią ilość impulsów zegarowych.
Zasada prowadzenia transmisji jest następująca:
Urządzenie Master (najczęściej twój mikrokontroler) uaktywnia wybrane urządzenie Slave przez ustawienie jego linii SS w stan niski. Następnie generuje odpowiednią ilość impulsów zegarowych na linii SCLK. Dane zapisywane do urządzenia Slave są przesyłane linią MOSI, a urządzenie Slave przesyła dane do urządzenia Master linią MISO. Przesyłane dane są odczytywane przy dodatnim lub ujemnym zboczu sygnału zegarowego w zależności od wybranego trybu pracy.Dane przesyłane są na zasadzie rejestrów przesuwających:
Pod wpływem impulsów zegarowych dane w rejestrze Master są przesuwane i wysyłane linią MOSI. Z kolei dane z linii MISO są wpisywane z drugiej strony rejestru. W urządzeniu Slave dane z linii MOSI są wpisywane do rejestru. A dane w rejestrze Slave są przesuwane i wysyłane linią MISO. W ten sposób po 8 impulsach zegarowych (jeśli rejestry są 8-bitowe) dane z obu rejestrów zostaną wymienione między sobą.
Tutaj występuje kilka ustaleń technicznych, które zależą od konkretnego urządzenia SPI. Niestety, nie ma jednolitego standardu i musisz dostosować się do parametrów udostępnianych przez producenta:
Sposób komunikacji z konkretnym urządzeniem powinien być zgodny z danymi technicznymi publikowanymi przez jego producenta. Zwykle wygląda to tak, iż urządzenie Master najpierw przesyła linią MOSI 8-bitowy rozkaz, a następnie przesyła tą samą linią dane lub odczytuje dane linią MISO. Niektóre urządzenia SPI tylko przesyłają dane, zatem urządzenie Master inicjuje transmisję, po czym odczytuje linią MISO serię bitów z wybranego urządzenia Slave.
W Arduino jest odpowiednia biblioteka do komunikacji SPI. Zajmiemy się tym zagadnieniem na kursie programowania konkretnych mikrokontrolerów.
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.