Mikrokontrolery AVR. Język C - podstawy programowania: serwer HTTP

Mikrokontrolery AVR. Język C - podstawy programowania: serwer HTTP
Pobierz PDF Download icon
Z końcem 2010 roku na polskim rynku pokazała się wydana przez firmę Atnel książka autorstwa Mirosława Kardasia pt: \"Mikrokontrolery AVR - Język C - Podstawy Programowania\". Postanowiliśmy przybliżyć czytelnikom tę interesującą pozycję poprzez opublikowanie jej fragmentu poświęconego tworzeniu serwera http na mikrokontrolerach AVR. Przykłady prezentowane w książce mogą być z łatwością wykonane z użyciem zestawów deweloperskich firmy Atnel.
?)); plen=fill_tcp_data_p(buf,plen,PSTR(?Witaj !\n?)); plen=fill_tcp_data_p(buf,plen,PSTR(?twój serwer www działa znakomicie\n\n?)); plen=fill_tcp_data_p(buf,plen,PSTR(??)); plen=fill_tcp_data_p(buf,plen,PSTR(?
www.atnel.pl?)); plen=fill_tcp_data_p(buf,plen,PSTR(?\n?)); return(plen); } // główna funkcja programu int main(void){ uint16_t dat_p; // CLKPR=(1<200 OK?)); goto SENDTCP; } // just one web page in the ?root directory? of the web server if (strncmp(?/ ?,(char *)&(buf[dat_p+4]),2)==0){ dat_p=print_webpage(buf); goto SENDTCP; }else{ dat_p=fill_tcp_data_p(buf,0,PSTR(?HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\ n

401 Unauthorized

?)); goto SENDTCP; } SENDTCP: www_server_reply(buf,dat_p); // wysłanie strony http // tcp koniec obsługi portu 80 } return (0); } Na listingu  3. Przedstawiono cały kod programu serwera HTTP uruchomiony na mikrokontrolerze ATmega32. Na początku typowe jest dołączanie plików nagłówko- wych zarówno tych systemowych, jak i po- trzebnych bibliotek. Warto zauważyć, że oznaczyłem jako komentarz linię dołączającą plik timeout.h, który wcześniej usunęliśmy. MAC, IP i port Następnie mamy do czynienia z bardzo istotną rzeczą, jaką jest przydzielenie odpo- wiedniego adresu MAC dla naszego urzą- dzenia, oraz adresu IP. Trzeba pamiętać, że oba muszą być unikalne, tzn. że nie mogą przybierać takiej samej wartości jak w  in- nym urządzeniu pracującym w twojej sieci lokalnej. Musisz, zatem sprawdzić w syste- mie, (np. Windows), jaki adres IP ma twój komputer. Można tego dokonać za pomocą polecenia ?ipconfig /all? wydanego z  linii poleceń w  konsoli typu DOS. Zakładam oczywiście, że czytelnik ma dostęp do lokal- nej sieci LAN, w której pracuje jakiś router, a ten wyznacza dostępną klasę adresów IP 85ELEKTRONIKA PRAKTYCZNA 3/2011 Mikrokontrolery AVR Co sugeruje, iż można bez cienia wątpli- wości wprowadzić własny adres np.: static uint8_t mymac[6] = {?A?,?L?,?A?,0x10,0x00,0x24}; Niestety w  ten sposób przypadkowo utworzony adres MAC może powodować przedziwne zachowania się przykładowych programów w  sieci lokalnej lub rozległej. Przedziwne z powodu braku znajomości pra- widłowych sposobów tworzenia MAC adre- sów. Często właśnie przypadkowa zmiana MAC adresu w przykładowych programach z  tej strony powoduje, że nie działają one zgodnie z oczekiwaniem i przez to wielu lu- dzi się zniechęca do dalszych prób ze stosem TCP. Początkujący nie zwraca uwagi na to, że dokonał zmiany adresu MAC, tylko na to, że kod jest identyczny jak w przykładach, a po- mimo to informacje raz się pojawiają, a in- nym czasem nie docierają do albo z kompu- tera. Zasada tworzenia adresów MAC została zilustrowana na rysunku 2. Za niepowodzenia początkujących w ustalaniu adresu MAC odpowiadają dwa pierwsze najmłodsze bity z 1. oktetu. Być może autorzy tuxgraphics.org wybrali trzy pierwsze litery świadomie, szczególnie pierwszą literę ?T?. Kod litery T wynosi 0x54. (binarnie: 0b0101 0100), zatem dwa najmłodsze bity 1. oktetu ustawione są na 0 i taki adres MAC praktycznie w każdych Dokładnie tak samo wprowadzamy 6 cyfr, które są bezpośrednio kodami ASCII podanych w  apostrofach liter. Uwagę może wzbudzić pierwszy bajt o wartości 0. Niestety autorzy z tuxgraphics.org popełnili błąd tłu- macząc w kodzie sposób, jak można uzyskać własny adres MAC. W ich przypadku jest to: static uint8_t mymac[6] = {?T?,?U?,?X?,0x10,0x00,0x24}; W  rzeczywistości trzy pierwsze litery TUX zostały zaprezentowane w postaci szes- nastkowej w ich przykładach: static uint8_t mymac[6] = {0x54,0x55,0x58 ,0x10,0x00,0x24}; Jednocześnie tłumaczą, jak uzyskać wła- sny MAC adres, cytuję: ?// how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX? w sieci. Np. jeśli komputer będzie miał ad- res 192.168.0.100, niemal na pewno można urządzeniu przypisać adres IP z  zakresu od: 192.168.0.1 do 192.168.0.254 pomijając adres IP, który jest przypisany komputero- wi PC oraz adres tzw. bramy domyślnej. Adres tej bramy także zostanie wyświetlo- ny w konsoli, przy czym zwykle w tej kla- sie domyślnie wynosi on: 192.168.0.1 ale w  teorii może być on różny, w  zależności od routera. Warto sprawdzić, w jakiej części klasy router przydziela adresy automatycz- nie, a którą jej część pozostawia dla adresów przydzielanych statycznie (przez użytkow- nika). Tu wszystko zależy od konfiguracji routera. Na komputerze autora router za po- mocą DHCP przydziela automatycznie adre- sy w zakresie 192.168.0.2 do 192.168.0.99, dlatego wybrałem dowolny adres z zakresu: 192.168.0.100 do 192.168.0.254, konkret- nie: 192.168.0.110. Nieco inaczej i prościej jest z  dobraniem własnego adresu MAC dla naszego urządzenia. W zasadzie można wpisać 6 dowolnych przypadkowych liczb do tablicy mymac[6]. Można także zasto- sować nieco bardziej przyjazny zapis, np. w takiej postaci: // definicja własnego MAC adresu urządzenia static uint8_t mymac[6] = {0,?M?,?I?,?R?,?E?,?K?}; Rys. 2. Zasada tworzenia adresów MAC. R E K L A M A 86 ELEKTRONIKA PRAKTYCZNA 3/2011 NOTATNIK KONSTRUKTORA warunkach nie będzie powodował proble- mów z przykładami prezentowanymi przez autorów. Nie będę dalej szczegółowo opisy- wał, co oznacza ?unicast?, ?multicast? czy ?locally administrated?, ponieważ temat nieco odbiega od naszego głównego wąt- ku. Podpowiadam tylko, że warto, aby do takich podstawowych prób, testów obydwa bity miały wartość równą 0. Uniemożliwia to korzystanie ze wszystkich liter, gdyż w części z nich, ich kody ASCII będą miały ustawione obydwa te bity lub któryś z nich na wartość 1. Dlatego podany wyżej przy- kład z trzema pierwszymi literami ALA nie będzie działał w każdym przypadku zgod- nie z  oczekiwaniami. Reasumując, z  po- wodów opisanych wyżej, najbezpieczniej będzie, jeśli zawsze pierwszy oktet MAC adresu będzie miał wartość 0, wtedy unik- niemy przykrych niespodzianek i długiego poszukiwania błędów we własnym progra- mie. Przy prawidłowo dobranych numerach MAC adresu wystąpi raczej bardzo nikłe prawdopodobieństwo, że jakieś urządzenie w sieci LAN będzie miało już wybrany przez nas adres. W  dalszej kolejności ustawiamy port, na którym będzie nasłuchiwał nasz ser- wer WWW. Typowo odbywa się to na porcie 80. Dzięki temu, we własnej przeglądarce internetowej wystarczy wpisać w  miejsce nazwy strony adres IP (w moim przypadku 192.168.0.110) oraz nacisnąć klawisz EN- TER. Jeśli jednak zmienimy port np. na war- tość 8090, to wywołanie w przeglądarce bę- dzie już wymagało wyspecyfikowania tegoż portu: 192.168.0.110:8090. Definicja bufora Kolejna kwestia dotyczy definicji bufora do obsługi komunikacji TCP. Obsługuje on zarówno dane przychodzące, jak i  wycho- dzące. Jego wielkość zwiększyłem do 850 bajtów. Można ją jeszcze zwiększać, ale trze- ba pamiętać o  obserwacji zajętości pamięci RAM po kompilacji. Nie może zostać jej zbyt mało, gdyż dojdzie do problemów z działa- niem stosu. W dalszej kolejności mamy de- finicję dwóch funkcji narzędziowych. Pierw- sza z nich służy tylko do przygotowania od- powiedzi z serwera w formacie HTTP o tym, że zapytanie do serwera było poprawne, druga natomiast, print_webpage(), odpowie- dzialna jest bezpośrednio za wygląd strony WWW, jaką podaje nasz serwer. Funkcja ta napełnia tylko bufor ramki TCP, natomiast samo wysyłanie odbywa się za pomocą in- nych funkcji w  dalszej części programu. Na jej wyjściu otrzymujemy długość strony w bajtach. Główna część programu Następnie rozpoczyna się główna funk- cja programu, main(). Na początku dekla- rowane są potrzebne zmienne, oraz do- konywana inicjalizacja sprzętowej części karty sieciowej, ustawianie adresów MAC oraz IP itd. Później rozpoczyna się pętla nieskończona, w  której wciąż na początku dokonywany jest odczyt danych z  układu ENC28J60, jeśli takie w ogóle pojawiły się na jego wejściu. Posługujemy się tutaj zmienną dat_p. Jej wartość po odczycie odpowiada ilości odczytanych bajtów. Jeśli jest równa 0 to oznacza, że nie było żadnego żądania i pętla jest kontynuowana bez wykonywania pozostałych poleceń, które są umieszczone w  dalszej części programu. Trzeba pamię- tać o tej konstrukcji, bo jeśli np. umieścimy jakiś własny dodatkowy kod także poniżej sprawdzania ilości odczytanych bajtów, to nie zostanie on nigdy wykonany, dopóki nie nadejdzie żądanie do serwera. Aby wybrnąć z tej sytuacji, np. gdy chcemy umieścić dla celów testowych naszą wyżej omawianą funkcję SuperDebounce(), która w zależno- ści od stanu klawisza zapalałaby bądź gasi- ła diodę LED, trzeba umieścić ją w tej pętli albo przed odczytem czy sprawdzaniem zmiennej dat_p, albo nieco inaczej napisać kod całej pętli biorąc pod uwagę to, że ko- lejne polecenia powinny być wykonywane tylko i wyłącznie, gdy mamy jasną sytuację, że nadeszły jakieś dane. Dalsza część programu W  dalszej części programu, jeśli na- dejdzie już jakieś zapytanie z zewnątrz do naszej karty sieciowej, to po odczytaniu w buforze zostanie umieszczona ramka TCP wraz z danymi, które nas interesują. Dlatego w pierwszym warunku obsługujemy troszkę po macoszemu zapytania typu GET, nato- miast w  kolejnym sprawdzamy w  uprosz- czony sposób, czy nastąpiło odwołanie do domyślnej strony w głównym folderze ?/ ?. Występująca tutaj spacja oznacza, że pod- czas wywołania naszego adresu w  prze- glądarce nie określono żadnej konkretnej nazwy pliku do odczytu. W  przeciwnym wypadku moglibyśmy na tym właśnie po- ziomie rozpoznawać dostępne dla zapytań pliki, np.: if (strncmp(?/index.html?,(char *)&(buf[dat_p+4]), 11)==0) To spowodowałoby, że nasz serwer wyświetli stronę WWW tylko dla zapytań wpisanych w  przeglądarce w  ten sposób: ?192.168.0.110/index.html?. Można przy- gotować kilka różnych stron HTML w  pa- mięci FLASH mikrokontrolera albo też na karcie pamięci SD i wysyłać je w zależno- ści od nadchodzących żądań z  zewnątrz. Ten prosty przykład nie pokazuje wpraw- dzie wprost możliwości sterowania mikro- kontrolerem poprzez wyświetlanie strony www, ale istnieje wiele innych przykładów na stronie tuxgraphics.org, dzięki którym można bez problemu sterować zdalnie do- wolnymi procesami. Niestety jest jednak pewien problem, którego nie można pominąć. Otóż biblioteki stosu tcp, o  których wspomniałem wyżej, są wciąż rozwijane, ale także dosyć mocno modyfikowane, co powoduje, że praktycz- nie w  każdym pobranym przykładowym projekcie z  tuxgraphics.org spotkamy się z mniej lub więcej zmodyfikowanymi funk- cjami w  plikach ?ip_arp_udp_tcp.*?. Są one czasem wprost dostosowane do kon- kretnego projektu, przez co niestety nie można powiedzieć, że to biblioteki w pełni uniwersalne. Nie wchodząc zatem nieco głębiej w  tajniki działania stosu TCP czy- telnik może mieć problemy, aby płynnie modyfikować opisane tam projekty, jeśli chodzi o  wprowadzanie większych zmian w  ich funkcjonowaniu. Proponuję jednak przećwiczyć i  przetestować chociaż kilka projektów dostosowując je tak, jak pokaza- łem w  tym rozdziale, do własnego mikro- kontrolera. Łatwo wtedy dostrzec pewne powtarzające się zależności, z  których ja- sno wyłoni się sposób podstawowej obsługi stosu TCP. W  dużym skrócie, jego obsługa sprowadza się tak, jak w tym przykładowym omawianym tu programie prostego serwera HTTP, do ciągłego sprawdzania, czy układ enc28j60 otrzymał jakieś dane. W  dalszej kolejności zwykle sprawdzamy, czy zapy- tanie, które dotarło, nie jest zapytaniem czysto informacyjnym związanym ustala- niem adresów, obsługi ARP, czy też obsługi zewnętrznych poleceń typu ping. W innych projektach znaleźć można sprawdzanie, czy ramka, którą odczytał układ ENC28J60, jest przeznaczona właśnie dla nas, i dopie- ro po tym następują procedury parsowania (sprawdzania) danych przesłanych w ram- ce, które mogą być przydatne do sterowania procesami. Obsługa stosu już w kodzie pro- gramu, mając do dyspozycji chociaż podsta- wowe funkcje, nie jest wcale taka trudna. Dodam że chociaż na schematach przykła- dowych urządzeń z tuxgraphics.org prawie wszędzie podłączony jest sygnał INT z kar- ty sieciowej do wejścia INTx mikrokontro- lera, to jednak w  kodzie jest ono nie uży- wane. A szkoda. Można sobie wprowadzić taką obsługę, wystarczy zainicjalizować to przerwanie, w  naszym zestawie będzie to wejście INT2 i napisać najprostszą obsługę przerwania w  postaci ustawiania zwykłej flagi, która będzie następnie sprawdzana i zerowana w pętli głównej. Oznaczać ona będzie zdarzenie odbioru danych z  karty sieciowej. Można dzięki temu nieco upro- ścić oprogramowanie w  pętli głównej pro- gramu, zamiast wciąż badać, czy bufor jest pusty. Wprawdzie w  tak prostym przykła- dzie nie robi to wielkiej różnicy, jednak daje pewne możliwości dla przyszłej wygodniej- szej rozbudowy całego programu. Mirosław Kardaś Atnel
Artykuł ukazał się w
Marzec 2011
DO POBRANIA
Pobierz PDF Download icon
Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik grudzień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio listopad - grudzień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje listopad - grudzień 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna grudzień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich styczeń 2025

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów