Programowanie mikroprocesorów ( mikrokontrolerów )

Uruchomienie DS1820

Spis funkcji
1. Inicjalizacja (sprawdzenie obecności DS1820)
2. zzzzzzzzzzz



1. Inicjalizacja (sprawdzenie obecności DS1820)

W dziale tym zostanie opisany program do obsługi termometra cyfrowego DS1820. W programie użyte zostaną standardowo przezemnie stosowane pdprogramy i funkcje stworzone we wcześniejszych samouczkach szerzej opisane w dziale "Programowanie -> Przydatne Funkcje". Termometr cyfrowy DS1820 podłączony będzie do portu B na szóstym pinie według poniższego schematu ideowego.

Aby zmusić układ DS1820 do pracy należy go na początku zainicjalizować. Poniżej przedstawiona została procedura inicjalizacji termometru DS1820.

Inicjalizacja DS1820
  1.  
  2. // Reset one wire ds1820
  3. unsigned char One_wire_reset(void)
  4. {
  5.         sbi(PORTB,6); // ?
  6.         sbi(DDRB,6);
  7.         cbi(PORTB,6);
  8.         _delay_us(500);
  9.         cbi(DDRB,6);
  10.         sbi(PORTB,6);
  11.         _delay_us(60);         
  12.         if (bit_is_clear(PINB,6))
  13.         {
  14.                 _delay_us(500);
  15.                 if (bit_is_set(PINB,6)) {obecnosc=1;} else {obecnosc=3;}
  16.         }
  17.         else {obecnosc=2;}
  18. return (obecnosc);
  19. }
  20.  
  21.  

Użyte funkcje: cbi, sbi, bit_is_clear, bit_is_set.

 Aby zainicjalizować termometr i przygotować go do dalszej pracy należy wykonać kolejno sekwencje inicjalizującą. Termometr podpięty jest do portu B pin6. Sytuacją wyjściową jest stan jeden na lini tak więc na początek ustawiamy jedynkę na wyjście podpięte do lini danych termometru DS1820 (5 linijka programu). W kolejnym kroku ustawiamy port B jako wyjściowy (6) następnie rozpoczyna się procedura inicjalizacji tzn ustawiamy 0 na wyjścoi danych (7) i czekamy czas który według dokumentacji może mieścić się w zakresie od 480us do 960us. Ja przyjąłem czas  500us (8). Po upływie ściśle określonego czasu przechodzimy do odczytania impulsu obecności. Po upływie czasu przełączamy port w tryb wejścia (9) i ustawiamy jedynkę na porcie (10). należy odczekać czas od 15 do 60 us aby linia danych zdążyła się naładować ( a w zasadzie kondensator magazynujący energię do zasilania układu znajdujący się wewnątrz DS1820). Po upływie tego czasu przy ustawieniach portu na wejściowy i stanie jeden na wyjściu mikrokontrolera odczytujemy stan wejścia (12). Jeśli DS1820 odpowie nam że jest obecny jedynkę na lini danych ściągnie nam do poziomu zera i odczytując wartość portu otrzymamy wartość 0 wystawioną przez DS1820. Jeśli układ DS1820 nie odpowie nam i mamy ciągłą jedynkę na lini danych warunek w lini 12 zostaje złamany i program przechodzi do lini 17 i ustawia wartość zmiennej obecnosć na 2 co oznacza że układ DS1820 jest nieobecny i nie odpowiedział nam. Jeśli jednak układ DS1820 odpowie nam i ustawi stan lini danych na 0 oznacza to że jest obecny na lini danych wówczas warunek w lini 12  jest spełniony i program przechodzi o upewnienia się że faktycznie 0 na lini jest odpowiedzią układu DS1820. Układ DS1820 utrzymuje stan lini w stanie zero przez czas od 60 do 240 us po którym  pwinien wrócić ze stanem lini danych na jedynkę. Stan lini danych czy DS1820 wrócił na jedynkę możemy sprawdzić po minimum 480us od momentu gdy ustawiliśmy ją na jeden mikrokontrolerem. Dla pełniejszego zrozumienia opisu wykres inicjalizacji przedstawiono na rysunku poniżej.

programowanie mikroprocesorów mikrokontrolerów

Ja w programie przyjąłem 500us (14) po czasie tym sprawdzam czy DS1820 powrócił ze stanem lini na 1 (15). Jeśli powrócił zmienna obecnośćprzyjmuje wartość 1 i DS1820 uważany jest jako obecnyi może być dalej wykorzystywany do pomiarów. Jeśli jednak linia w dalszym ciągu będzie utrzymana w stanie 0 zmienna obecność ustawiana jest na wartosć 3 i DS1820 uważany jest jako nieobecny. Najczęstrzą przyczyną nieprawidłowego wykrywania układu DS1820 jest nieprecyzyjne przestrzeganie czasów zawartych w instrukcji, złe taktowanie procesora np. myślimy że taktowany jest 1 Mhz wpisujemy w procedury delay prawidłowe czasy a okazuje się że parametry konfiguracyjne mikroprocesora powodują że jest on taktowany prędością 8Mhz i wszystkie czasy jakie wpisaliśmy trwają 8 razy krócej czego gołym okiem nie da rady zauważyć. Najlepiej przetestować układ oscyloskopem lub gdy go nie mamy migać diodą co 10 sekund stosując komendę _delay_ms(10000) i mierząc czas migania stoperem.

2. Wysłanie bitu a następnie całego bajtu do układu DS1820

Aby wysłać bajt danych do układu DS1820 należy wysłać do niego 8 bitów w sposób przedstawiony poniżej

Wysłanie bitu do ds1820 one wire
  1. // wysłanie bitu do ds1820 one wire
  2. void wire_write_bit(unsigned char bit)
  3. {
  4. _delay_us(2);
  5.         sbi(PORTB,6);
  6.         sbi(DDRB,6);
  7.         cbi(PORTB,6);
  8.         _delay_us(5);  //_delay_us(10);
  9.         if(bit==1)
  10.         {
  11.                 sbi(PORTB,6);
  12.         }
  13.         _delay_us(60);  //_delay_us(60);
  14.         sbi(PORTB,6);
  15. }
  16.  

Ogólnie wysyłanie danych do układu DS1820 polega na wysłaniu 8 pojedynczych bitów składających się w jeden bajt danych. Ogólnie transmisja danych w układzie DS1820 realizowana jest na zasadzie slotów czasowych które odpowiadają odczytowi lub wysłaniu jednego bitu do lub z układu DS1820. każdy slot ma ściśle określony czas dzięki czemu transmisja danych może przebiegać z wykorzystaneim tylko jednej linii bez dodatkowych szyn synchronizacji. Ograniczenia czasowe dla slotów czasowych przedstawia poniszy rysunek.

programowanie mikroprocesorów mikrokontrolerów

Maksymalny czas trawania slotu wymiany danych moze trwać 120us. Ja w programie starałem się zminimalizować czas trwania slotu. I tak na poczatku funkcji wysyłającej bit do DS1820 wstawione zostało opóźnienie czasowe 2us (4) ze względu na wymagany czas odbudowania stanu lini po wysłaniu poprzedniej wartosci bitu na rysunku to opóźnienie czasowe zostało nazwane tREC i ma być większe od 1us. Kolejnym krokiem jest postawienie lini danych w stan wysoki i ustawienie pinu jako wyjściowy (przygotowanie się do wysłania bitu do DS1820) (5)(6). W lini (7) programu zerujemy linie danych aby poinformować DS1820 o tym że za chwile będzie wysyłana dana ( czas trwanai tego stanu musi być większy od 1us maksymalnie trwać do 15us) ja odczekuje 5us. Po tym czasie układ DS1820 oczekuje na przyjęcie wartości daneg bitu z szyny danych. Funkcja wysyłania bitu do DS1820 posiada następującą konstrukcje void wire_write_bit(unsigned char bit) tzn że zastosowanie jej wymaga podania wartości parametru bit np wire_write_bit(1); dla wysania 1 i wire_write_bit(0); dla wysłania 0. W lini (9) programu następuje identyfikacja danej wejściowej. Jeśli dana wejściowa (tzn zmienna bit - parametr wejściowy funkcji ) jest równa dokłądnie 1 wówczas funkcja ustawia wartść lini danych na 1 (11) a następnie czeka 60us (13) aby DS1820 odczytał prawidłowo stan lini danych. Do DS1820 zostaje wysłana wartość bitu = 1. Jeśli w lini (9) programu wartość zmiennej bit nie równa się jeden wówczas wartość bitu nie zostaje zmieniona i pozostaje zerem przez 60us (13) (jest to dosyć nieeleganckie oprogramowanie funkcji gdyż bit 0 zostanie podtrzymany dla jakiejkolwiek wartości zmiennej różnej od jeden. Zmienna bit powinna zostać zadeklarowana jako bitowa i przyjmować tylko dwie wartości 1 i 0 jednak tak było mi wygodniej więc zostawiłem w tej formie) i do DS1820 przesłana zostaje wartość bitu równa zero. linia 14 ustawia wartoć lini danych do stanu wyjsciowego na 1 do gotowości wysłania kolejnej zmiennej.

Wysłanie bajtu jest funkcją sparametryzowaną w postaci void wire_write_bajt(unsigned char wbajt). Zmienna wbajt jest 8 bitową zmienną wejściową funkcji wysyłaną do DS1820.

Wysłanie bitu do ds1820 one wire
  1. // wysłanie bajtu do ds1820 one wire
  2. void wire_write_bajt(unsigned char wbajt)
  3. {
  4.         unsigned char pom;
  5.         for (unsigned char i=0;i<8;i++)
  6.         {
  7.                 pom=wbajt>>i;
  8.                 pom&=0x01;
  9.                 wire_write_bit(pom);
  10.                 _delay_us(5);
  11.         }
  12. }

w lini (4) programu deklarowana jest zmienna pomocnicza potrzebna do działań bitowych. W linii (5) pogramu dwfiniowana jest ośmiokrokowa pętla w celu wysłania każdego z ośmiu bitów pokolei. Do zmiennej pomocniczej pom przypisana zostaje wartość bajtu który chcemy wysłać przesunięty o ilość pozycji w prawo w zależności od tego w którym kroku się znajdujemy (7). Operacja ta pozwala umieścić nam na miejscu najmłodszego bitu zmiennej pom kolejno każdy z bitów zmiennej wbajt tak aby kolejna funkcja mogła wyfiltrować jego wartość. W lini (8) programu ze zmiennej pom zostaje wyfiltrowana wartość jej najmłodszego bitu dzięki czemu w kolejnych krokach w zmiennej pom w (8) linijce programu pojawiają się kolejno poszczególne bity zmiennej wbajt. następnie zmienna pom zostaje wysłana na linie danych (9) do DS1820 wyżej opisaną funkcją wire_write_bit w sposób opisany powyżej. Następnie odczekujemy 5us (10) pomiedzy wysłaniem jednego bitu a kolejnego. Dzięki dwóm powyższym funkcjom jesteśmy w stanie wysyłać dane do DS1820. Poniżej przedstawiony zostanei odczyt danych z DS1820.

2. Odczyt danych z DS1820

Aby odczytać dane z szyny One Wire deklarujemy sobie dwie zmienne buforowe: bit (3) i bajt (4). Funkcja odczytu danych przyjmuje formę "unsigned char wire_read_bajt (void)". Powyższy zapis świadczy o jednej danej wyjściowej funkcji i braku danych wejściowej. 

Odczyt danych z DS1820
  1.  
  2. // odebranie bajtu od ds1820 one wire
  3. unsigned char bit;
  4. unsigned char bajt;
  5.  
  6. unsigned char wire_read_bajt (void)            
  7. {
  8.         bit=0;
  9.         bajt=0;
  10.         for(unsigned char b=0;b<8;b++)
  11.         {
  12.         sbi(PORTB,6); // ?
  13.         sbi(DDRB,6);
  14.         _delay_us(2);
  15.         cbi(PORTB,6);
  16.         _delay_us(5);  
  17.         cbi(DDRB,6);
  18.         sbi(PORTB,6);
  19.         _delay_us(5);
  20.         if(bit_is_set(PINB,6)) bit=1;
  21.         else bit=0;
  22.         if(bit==1) bajt|=0x01<<b;
  23.         _delay_us(55);  //_delay_us(31);
  24.        
  25.         }
  26. return (bajt);
  27. }

Funkcja będzie kolejno odczytywać dane z układu DS1820. Na początku wszystkie zmienne buforowe zostają wyzerowane (8)(9). Aby odczytać 1 bajt danych czyli 8 bitów tworzymy pętlę o ośmiu krokach odczytującą kolejno bity (10). Ustawiamy bit danych w stan wyjsciowy 1 (12) i jako port wyjściowy (13) aby wymuśić stan wyjściowy na lini danych stan 1. Odczekujemy 2 us dla ustalenia się stanu lini (14). Aby rozpocząć slot odczytu danych należy linie danych ściągnąć do zera (15) na czas około maksymalnie 15us (16). Rozpoczynamy odczyt wartości tzn. ustawiamy pin danych na wejściowy (17) i podciągamy pin danych wewnętrznym rezystorem podciagającym do jedynki (18). Odczekuejmy 5us (19). Najpewniejszym momentem jak widać na rysunku (daleko) powyżej jest odczyt wartości po 15us. W lini (20) następuje odczyt stanu lini danych do zmiennej bit. Funkcja sprawdza wartość lini danych po czasie 12us od rozpoczęcia slotu odczytu (suma czasów (14) 2us (16) 5us (19) 5us = 12us ). Po podciągnięciu lini do 1 rezystorem podciągającym DS1820 ściągnie linie do 0 dla nadawania wartosci bitu 0 lub pozostawi linie w stanie jeden dla wysyłania do nas wartości bitu 1. Funckcja w lini (22) programu sprawdza czy na lini danych do zmiennej bit została odczytana jedynka. Ponieważ dane buforowe zostały wyzerowane na samym początku wszystkie ich bity równają się zero. W przypadku gdy bit zostaje odczytany jako 1 w zależności od kroku w jakim jest pęta for na takim miejscu zostanie wpisana 1 do zmiennej buforowej bajt jeśli zostanei odczytane zero zmienna bajto nie jest modyfikowana. Dzięki czemu po przejściu pęti przez wzystkie osiem kroków uzyskujemy wartość odczytanego bajtu z DS1820. W celu zachowania wymaganej długości slotu wymiany danych wstawione jest opóźnienie czasowe 55us w lini (23) programu. Po odczytaniu wszystkich bitów w lini (26) funkcja wystawia wartość do zmeinnej globalnej jako bajt.

Mając już wszystkie podstawowe narzędzia do oprogramowania termometru możemy zabrać się za oprogramowanie pomiaru temperatury na DS1820.

3. Pomiar temperatury DS1820

W programie do pomiaru temperatury termometrem DS1820 użyte zostały moje własne procedury i funkcje do obsługi wyświetlacza LCD. W przypadku korzystania z gotowych biblotek do obsługi wyświetlacza LCD przogram należy nieznacznie przerobić. Wszystkie użyte procedury mojego autorstwa znajdują się na tej stronie bądź w konkretnym dziale od danego urządzenia bądź w dziale "Programowanie -> Przydatne Funkcje"

Pomiar temperatury DS1820
  1.  
  2. // Ds1820 pomiar temperatury
  3. unsigned char jest;
  4. int temp;
  5. unsigned char tempH;
  6. unsigned char tempL;
  7. unsigned char tempH1;
  8. void DS1820(void)
  9. {
  10.         unsigned int ulamek=0;
  11.         jest=One_wire_reset();
  12.         if(jest==1)
  13.         {
  14.                 wire_write_bajt(0xcc);          //      11001100
  15.                 wire_write_bajt(0x44);          //      10001000
  16.                 _delay_ms(800);                                 // powinno byc 800ms
  17.                 One_wire_reset();
  18.                 tempL=0x00;
  19.                 tempH=0x00;
  20.                 wire_write_bajt(0xcc);          //      11001100       
  21.                 wire_write_bajt(0xbe);          //      10111110
  22.                 tempL=wire_read_bajt();
  23.                 tempH=wire_read_bajt();
  24. }

W pierwszym kroku deklarujemy zmienne globalne (3-7) oraz jeśli chcemy wyświetlać temperature z dokładnością po przecinku musimy zadeklarować zmienną odpowiedzialną za wartość ułamkową temperatury (10). Zadeklarowanej wcześniej zmiennej "jest" przypisujemy wartość wynikową funkcji One_wire_reset() sprawdzającą obecność DS1820 na linni danych (11). Funkcja ta inicjalizuje DS1820 do pracy. Sprawdzamy wartość zmiennej jest (12), jeśli zwrócona wartość wynosi 1 tzn. że ds1820 odpowiedział i prawidłowo zainicjalizował się i jest gotowy do pracy. I możemy przejść do wysyłania komend do DS1820. Aby dokonać pomiaru temperatury dla jednego termometru podłaczonego bezpośrednio do mikroprocesora omijamy funkcję sprawdzania romu wysyłając do DS1820 wartość CC w systemie szesnastkowym czyli 0xCCh (14) i przechodzimy do wydawania komend termometrowi. Następnie wysyłamy komendę 0x44h uruchamiającą konwersje temperatury przez DS1820 (15). Według dokumentacji dla maksymalnej rozdzielczości pomiaru czas konwersji trwa maksimum 750ms dla przetwarzania 12 bitowego odczekujemy np. 800ms (16). Wykonujemy reset magistrali (17). Zerujemy zmienne które będą przechowywać odczyt temperatury z DS1820 (18)(19). Po dokonanym pomiarze inicjujemy odczyt pomierzonej temperatury. W pierwszym kroku pomijamy rom wysyłająć 0xCCh (20) następnie wysyłamy komendę odczytu temperatury 0xBEh (21). Ponieważ odczyt temperatury jest 12 bitowy wartość pomierzonej temperatury przechowywana będzie w dwóch zmiennych ośmiobitowych tempL (Low - część młodsza danych) i tempH (High - cześć starsza danych). Zczytujemy wartość temperatury z DS1820 funkcją do odczytu danych najpierw młodsza część bajtu (22) następnie starsza (23).

Przeliczanie temperatury DS1820
  1. // przeliczenia
  2.                 temp=tempL;
  3.                 temp&=0x0f; //ulamek
  4.                 tempL>>=4;
  5.                 tempH<<=4;
  6.                 tempH=tempL|tempH;
  7.                 T1=tempH;
  8.                 LCD_xy(0,0);
  9.                 if(tempH>127)
  10.                 {
  11.                         tempH=255-tempH;
  12.                         temp=15-temp;
  13.                         LCD_wyslij('-',1);
  14.                 }
  15.                 ulamek=temp*625;
  16.                 temp=ulamek/1000;
  17.                 if(temp==10)temp=0;
  18.                 if(tempH<10) LCD_tekst("0");
  19.                 tempH1=tempH;
  20. //              temp1=tempH;
  21.                 LCD_tekst(utoa(tempH,"     ",10));
  22.                 LCD_wyslij('.',1);
  23.                 dot=temp;
  24.                 LCD_wyslij(temp+48,1);
  25.                 LCD_wyslij(0x60,1); //znaczek stopni
  26.                 LCD_tekst("C");         //znaczek celsjusza
  27.                 One_wire_reset();
  28.                 tempL=0x00;
  29.                 tempH=0x00;
  30.         }
  31.         else
  32.         {
  33.                 LCD_xy(0,0);
  34.                 LCD_tekst("Brak DS18B20");
  35.         }

 

Poniżej przedstawiono program obsługi DS1820 w całości zw wszystkimi elementam iopisanymi powyżej:

Uruchomienie termometru cyfrowego DS1820
  1. unsigned char obecnosc;
  2.  
  3. // Reset one wire ds1820
  4. unsigned char One_wire_reset(void)
  5. {
  6.  
  7.         sbi(PORTB,6); // ?
  8.         sbi(DDRB,6);
  9.         cbi(PORTB,6);
  10.         _delay_us(500);
  11.         cbi(DDRB,6);
  12.         sbi(PORTB,6);
  13.         _delay_us(60);         
  14.         if (bit_is_clear(PINB,6))
  15.         {
  16.                 _delay_us(500);
  17.                 if (bit_is_set(PINB,6)) {obecnosc=1;} else      {obecnosc=3;}
  18.         }
  19.         else {obecnosc=2;}
  20.  
  21. return (obecnosc);
  22. }
  23.  
  24. // wysłanie bitu do ds1820 one wire
  25. void wire_write_bit(unsigned char bit)
  26. {
  27. _delay_us(2);
  28.         sbi(PORTB,6);
  29.         sbi(DDRB,6);
  30.         cbi(PORTB,6);
  31.         _delay_us(5);  //_delay_us(10);
  32.         if(bit==1)
  33.         {
  34.                 sbi(PORTB,6);
  35.         }
  36.         _delay_us(60);  //_delay_us(60);
  37.         sbi(PORTB,6);
  38. }
  39.  
  40. // wysłanie bajtu do ds1820 one wire
  41. void wire_write_bajt(unsigned char wbajt)
  42. {
  43.         unsigned char pom;
  44.         for (unsigned char i=0;i<8;i++)
  45.         {
  46.                 pom=wbajt>>i;
  47.                 pom&=0x01;
  48.                 wire_write_bit(pom);
  49.                 _delay_us(5);
  50.         }
  51.                 //_delay_us(5);
  52.  
  53. }
  54.  
  55. // odebranie bajtu od ds1820 one wire
  56. unsigned char jest;
  57. int temp;
  58. unsigned char tempH;
  59. unsigned char bit;
  60. unsigned char bajt;
  61. unsigned char tempL;
  62. unsigned char tempH1;
  63.  
  64. unsigned char wire_read_bajt (void)            
  65. {
  66.         bit=0;
  67.         bajt=0;
  68.         for(unsigned char b=0;b<8;b++)
  69.         {
  70.         _delay_us(2);
  71.         sbi(PORTB,6); // ?
  72.         sbi(DDRB,6);
  73.         cbi(PORTB,6);
  74.         _delay_us(5);  
  75.         cbi(DDRB,6);
  76.         sbi(PORTB,6);
  77.         _delay_us(5);
  78.         if(bit_is_set(PINB,6)) bit=1;
  79.         else bit=0;
  80.         if(bit==1) bajt|=0x01<<b;
  81.         _delay_us(55);  //_delay_us(31);
  82.        
  83.         }
  84. return (bajt);
  85. }
  86.  
  87. // Ds1820a pomiar temperatury
  88. void DS1820a(void)
  89. {
  90.         unsigned int ulamek=0;
  91.         jest=One_wire_reset();
  92.         if(jest==1)
  93.         {
  94.                 wire_write_bajt(0xcc);          //      11001100
  95.                 wire_write_bajt(0x44);          //      10001000
  96.                 _delay_ms(8);                           // powinno byc 800ms
  97.                 One_wire_reset();
  98.                 wire_write_bajt(0xcc);          //      11001100       
  99.                 wire_write_bajt(0xbe);          //      10111110
  100.                 tempL=0x00;
  101.                 tempH=0x00;
  102.                 tempL=wire_read_bajt();
  103.                 tempH=wire_read_bajt();
  104.        
  105.         // przeliczenia
  106.                 temp=tempL;
  107.                 temp&=0x0f; //ulamek
  108.                 tempL>>=4;
  109.                 tempH<<=4;
  110.                 tempH=tempL|tempH;
  111.                 T1=tempH;
  112.                 LCD_xy(0,0);
  113. //              LCD_xy(0,30);
  114. //              LCD_xy(1,20);
  115. //              LCD_xy(1,30);
  116.                 if(tempH>127)
  117.                 {
  118.                         tempH=255-tempH;
  119.                         temp=15-temp;
  120.                         LCD_wyslij('-',1);
  121.                 }
  122.                 ulamek=temp*625;
  123.                 temp=ulamek/1000;
  124.                 if(temp==10)temp=0;
  125.                 if(tempH<10) LCD_tekst("0");
  126.                 tempH1=tempH;
  127. //              temp1=tempH;
  128.                 LCD_tekst(utoa(tempH,"     ",10));
  129.                 LCD_wyslij('.',1);
  130.                 dot=temp;
  131.                 LCD_wyslij(temp+48,1);
  132. //              LCD_wyslij(0x60,1); //znaczek stopni
  133. //              LCD_tekst("C");         //znaczek celsjusza
  134.                 One_wire_reset();
  135. //              czekajms(1);
  136.                 tempL=0x00;
  137.                 tempH=0x00;
  138.         }
  139.         else
  140.         {
  141.                 LCD_xy(0,0);
  142. //              LCD_xy(0,30);
  143. //              LCD_xy(1,20);
  144. //              LCD_xy(1,30);
  145.                 LCD_tekst("Brak DS18B20");
  146.         }
  147.  
  148. }
  149.  
  150.  
  151.  
  152.  




 
Wszelkie prawa zastrzeżone! Kopiowanie, powielanie i wykorzystywanie zdjęć, treści oraz jej fragmentów bez zgody autora zabronione.
© mikroprocesory.info.pl@gmail.com 2013.