Elektroda.pl
Elektroda.pl
X
Servizza
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11

p.kaczmarek2 21 Kwi 2017 20:51 6336 7
  • Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11
    Witajcie moi drodzy!
    Dzisiaj przedstawię wam mój prosty mikroserwer WWW na PIC24FJ64GA002 i ENC28J60 oraz jego przykładowe zastosowanie - pomiar temperatury, wilgotności (DHT-11) i poziomu oświetlenia "przez internet". Pomysł bazuje na projekcie "Business Card Server" z sieci, ale dostosowałem go do swoich potrzeb a firmware napisałem w mikroC, w przeciwieństwie do pierwowzoru którego firmware jest w MPLab (kompilator C30).

    Kilka słów o PIC24FJ64GA002
    PIC24FJ64GA002 to 16-bitowy mikrokontroler od Microchipa. Posiada 64KB pamięci Flash, 8KB RAM oraz zasilany jest napięciem 2.0 do 3.6V. Oferuje bogate peryferia, takie jak 2 moduły UART, 2 moduły SPI oraz 2 moduły I2C, których wyjścia można przypisać różnym pinom wyjściowym dzięki systemowi PPS (Peripheral Pin Select). Ponadto, ma wbudowany moduł RTCC i występuje w różnych obudowach: DIP, SSOP, SOIC i QFN.
    Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11

    Projekt płytki
    Jest to jeden z pierwszych projektów, w którym w duzej mierze zastosowałem montaż powierzchniowy. Wiem, że PIC24FJ64GA002 i ENC28J60 są dostępne w obudowach DIP, ale uznałem, że warto nauczyć się pracować z czymś mniejszym, takim jak obudowy SOIC. Płytka jest jednostronna i zaprojektowana tak, by można było ją wytworzyć w domu. Całość powstała w darmowej wersji Eagle. Ścieżki wyglądają tak:
    Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11

    Warstwa opisowa natomiast wygląda tak:
    Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11





    Na płytce znajduje się:
    - PIC24FJ64GA002 z wyjściami wyprowadzonymi i podpisanymi na warstwie opisowej. Korzysta z wbudowanego rezonatora (internal oscillator)
    - ENC28J60 wraz z gniazdem MagJack i rezonatorem 25MHz
    - osobno diody led dla ENC28J60
    - gniazdo do zewnętrznego zasilacza i stabilizator 3.3V
    - wyjście ICSP do programowania zewnętrznym programatorem
    - wyprowadzone wolne piny IO PICa
    - przecisk RESET dla PICa
    - dioda na pinie RB7 PICa

    Wykonanie płytki
    Już po wytrawieniu płytki troszkę zmieniłem plan, bo złączę Ethernetowe które miałem dostępne miało już diody LED wbudowane, i ostatecznie użyłem tych diod w złączu zamiast tych osobno na płytce. Ponadto diodę LED z pinu RB7 PICa pozwoliłem sobie dać jednak montażem through-hole, tak aby wystawała zza płytki. Wszystko inne obyło się bez żadnych komplikacji. Rezystory do Ethernetu 49R9 1%, ferrite bead (na schemacie L1) dałem jakiś z wylutu. Kondensator VCAP/VDDCore dla PICa 10uF tantalowy (ale wg. datasheeta mógłby być też ceramiczny).


    Firmware
    Oprogramowanie do płytki napisałem w mikroC PRO for dsPIC (ono obsługuje również PIC24) w oparciu o gotową bibliotekę dla ENC28J60. Dodatkowo musiałem użyć modułu PPS (Peripheral Pin Select) do odpowiedniego przypisania funkcji SPI do pinów tak, by pasowały one w miarę do nóżek ENC28J60 i uprościły rozmieszczenie ścieżek. Cały kod projektu znajduje się w załączniku. Hex wgrałem na PICa z pomocą mojego klona PICKIT2, ale Brenner9 też by się tu sprawdził. Drugiego scalaka, ENC28J60 z kolei oczywiście nie trzeba wcale programować.

    Przykładowe zastosowanie serwerka - pomiar temperatury, wilgotności i oświetlenia "przez internet"
    Na bazie swojego serwerka zrobiłem bardzo prostą, pseudo-stację meteorologiczna. Na ten moment posiada ona dwa czujniki:
    - czujnik DHT11 (pomiar temperatury i wilgotności), który komunikuje się z PICem z pomocą specjalnego protokołu po jednej szynie danych. Zasilany jest z tego samego napięcia co mikrokontroler, czyli 3.3V, i ma podłączony dodatkowy rezystor pullup do szyny danych. Kod jego obsługi bazuje na przykładzie w sieci i jest umieszczony w głównym pliku .C projektu.
    - fotorezystor (pomiar oświetlenia), który podłączony wraz z dodatkowym rezystorem stanowi dzielnik napięcia a pomiar wykonywany jest poprzez ADC. Do obsługi ADC użyłem gotowej biblioteki od mikroC PRO for dsPIC.
    Całość została złożona na płytce stykowej, którą połączyłem kabelkami z modułem serwera:
    Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11
    Wyniki pomiarów są prezentowane w ten sposób:
    Serwer WWW na PIC24FJ64GA002 i ENC28J60 + czujnik temperatury/wilgotności DHT11
    Serwerek jest dostępny poprzez przeglądarkę www i wyświetla wyniki pomiarów na prostej stronie internetowej. Do całości można się dostać z poziomu sieci domowej, zarówno z komputerów, laptopów jak i innych urządzeń podłączonych do wifi, takich jak tablety i smartfony. Oczywiście, to jest tylko przykładowe zastosowanie, i w podobny sposób można by zrealizować też sterowanie jakimś urządzeniem w domu poprzez przeglądarkę.

    Podsumowanie
    Jest to jedna z moich pierwszych samodzielnie wykonanych płytek w technologi SMD. Wcześniej wykonałem już webserwer na PIC18F67J60, ale w jego przypadku tylko on sam był w obudowie SMD (TQFP64), natomiast pozostałe elementy były przewlekane, tutaj natomiast już wiekszość części jest montowana powierzchniowo. Termotransfer, a dokładniej stara metoda "żelazkowa" znów się sprawdziła. Układ działa, a bezproblemowość wykonania całości i uruchomienia Ethernetu zachęciła mnie do dalszych eksperymentów z ENC28J60, których wyniki zapewne też wkrótce opiszę na DIY.

    Do postu dodaję załączniki:
    PIC24FJ64GA002_ENC28J60_PDFs.zip - pdf schematu (kolorowy), mozaika ścieżek (czarno biała) do wydruku, warstwa opisowa
    PIC24FJ64GA002_ENC28J60_sch_brd.zip - pliki Eagle
    PIC24FJ64GA002_ENC28J60_mikroC_source.zip - projekt mikroC PRO for dsPIC, tu też jest kod obsługi DHT-11
    PIC24FJ64GA002_datasheet.pdf - datasheet rodziny PIC24FJ64GA002
    ENC28J60_datasheet.pdf - datasheet ENC28J60
    RJLD-043TC1_A6_20170123.pdf - datasheet użytego gniazda RJ45
    PIC24FJ64GA002_blink_mikroC_PRO_for_dsPIC_A1_B7.zip - blink przydatny do pierwszych testów mojej płytki


    Fajne! Ranking DIY
    Potrafisz napisać podobny artykuł? Wyślij do mnie a otrzymasz kartę SD 64GB.
  • Servizza
  • #2 21 Kwi 2017 21:15
    ehhhhhhh
    Poziom 5  

    Jaka moze byc maksymalna wielkosc strony WWW na tym serwerku?

  • Servizza
  • #3 22 Kwi 2017 09:02
    marnowak
    Poziom 14  

    Strona jest konstruowana w kodzie C na charach.
    Gdyby zaimplementować obsługę karty SD byłoby to bardziej user friendly.

    Pytanie jak można by obsłużyć taką linijkę w head:
    <link href="/style.css" type="text/css" rel="stylesheet" />
    Lub analogicznie kod javascript z linku.

    Czy przeglądarka zapyta w tym przypadku serwerek o css? Jeśli tak, to jak jej go zwrócić? Potrzeba implementować w kodzie niejako interpreter pakietów?

    Pewnym wyjściem byłby pewnie link do zewnętrznego serwera, na którym umieszczony byłby css.

    Czy biblioteka ma zaimplementowane bardziej zaawansowane funkcje do tego, czy jej działanie kończy się na przesłaniu tylko jednego pliku html z umieszczonym w nim wszystkim?

  • #4 22 Kwi 2017 10:01
    p.kaczmarek2
    Poziom 23  

    ehhhhhhh napisał:
    Jaka moze byc maksymalna wielkosc strony WWW na tym serwerku?

    W tym konkretnym przypadku ogranicza nas pamięć mikrokontrolera PIC24FJ64GA002. Można by zastosować jakąś zewnątrzną pamięć, chociażby tę kartę SD o której wspomniał @marnowak, ale moim zdaniem najprostsze wyjście to trzymanie ewentualnych stylów na innym serwerze, chociażby nawet na darmowym CBA.
    To rozwiązuje większość problemów bez żadnego nakładu finansowego, mamy mnóstwo darmowych hostingów, polskich i nie tylko.
    Wtedy zamiast:
    Kod: html
    Zaloguj się, aby zobaczyć kod

    piszesz
    Kod: html
    Zaloguj się, aby zobaczyć kod

    To rozwiązanie ma dużą zaletę - możesz robić styl, kosmetykę strony WWW bez dostępu do programatora! Pliki na FTP zewnętrznego hostingu można edytować z każdego miejsca podłączonego do sieci.

    marnowak napisał:

    Jeśli tak, to jak jej go zwrócić? Potrzeba implementować w kodzie niejako interpreter pakietów?


    Całość tutaj jest bardzo niskopoziomowa. Na ten moment parsing pakietów HTTP jest bardzo prymitywny, ale można go bez problemu rozbudować.
    W funkcji
    Kod: c
    Zaloguj się, aby zobaczyć kod

    wystarczy użyć SPI_Ethernet_getByte aby poznać treść zapytania HTTP, które przykładowo wygląda mniej więcej tak:
    Code:

    GET /style.css HTTP/1.1
    Host: www.example.com

    Z tego można łatwo wyciągnąć nazwę pliku, o który pyta przeglądarka a potem już np. z pomocą ifów wysłać odpowiednią odpowiedź.
    Można nawet pokusić się o jakieś łatwiejsze rozwiązanie, np. użycie funkcji strstr, coś w ten sposób: if(strstr(request,"style.css")) {
    podobnie można obsłużyć zapytania które np. zmieniają stan na danym pinie (sterowanie przekaźnikiem, itp, itd).

    marnowak napisał:

    Czy przeglądarka zapyta w tym przypadku serwerek o css?

    Tak, wyśle zapytanie HTTP GET do serwera. To akurat dzieje się już w pełni automatycznie po stronie przeglądarki i tym programując serwer nie musimy się martwić.


    marnowak napisał:

    Pytanie jak można by obsłużyć taką linijkę w head:
    <link href="/style.css" type="text/css" rel="stylesheet" />
    Lub analogicznie kod javascript z linku.

    Oprócz tego z zewnętrznym serwerem (style.css na innym hostingu) i z ifami jest trzecie rozwiązanie - style i skrypty w HTML mogą być embedd, tzn. mogą być w tym samym dokumencie co treść HTML.



    marnowak napisał:

    Gdyby zaimplementować obsługę karty SD byłoby to bardziej user friendly.

    Zastosowany PIC ma dwa interfejsy SPI, więc nie ma problemu by taką kartę podpiąć nawet na osobnej magistrali danych, po prostu uznałem, że w przypadku tego projektu tego nie potrzebuję.


    marnowak napisał:

    Czy biblioteka ma zaimplementowane bardziej zaawansowane funkcje do tego, czy jej działanie kończy się na przesłaniu tylko jednego pliku html z umieszczonym w nim wszystkim?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Tak dokładniej to biblioteka obsługuje TCP, a my obsługujemy w kodzie HTTP. Odpowiedź jest generowana w locie z pomocą funkcji putConstString i putString. Może to być dokument w pełni z pamięci PICa, może być częsciowo z pamięci a częściowo np. złożony z integerów zamienionych na tekst, a również może być wczytany z zewnątrz.
    W zasadzie możliwości masz nieograniczone - możesz nawet porzucić całkiem HTTP i implementować inny protokół na bazie TCP.

  • #5 22 Kwi 2017 10:33
    marnowak
    Poziom 14  

    Ale w tej funkcji:

    Cytat:
    unsigned int SPI_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength, TEthPktFlags *flags)
    {
    char rs[16];
    unsigned int len; // my reply length

    // should we close tcp socket after response is sent?
    // library closes tcp socket by default if canCloseTCP flag is not reset here
    // flags->canCloseTCP = 0; // 0 - do not close socket
    // otherwise - close socket

    if(localPort != 80) // I listen only to web request on port 80
    {
    return(0);
    }

    // get 10 first bytes only of the request, the rest does not matter here
    for(len = 0; len < 10; len++)
    {
    getRequest[len] = SPI_Ethernet_getByte();
    }
    getRequest[len] = 0;
    len = 0;

    if(memcmp(getRequest, httpMethod, 5)) // only GET method is supported here
    {
    return(0);
    }

    httpCounter++; // one more request done



    WordToStr(httpCounter,rs);
    len = putConstString(httpHeader); // HTTP header
    len += putConstString(httpMimeTypeHTML); // with HTML MIME type
    len += putConstString(indexPage); // HTML page first part
    len += putString(rs);
    len += putConstString("<br> Temperature: "); // HTML page first part
    len += putString(stemp);
    len += putConstString("C <br> Humidity: "); // HTML page first part
    len += putString(hum);
    len += putConstString("% <br> Light: "); // HTML page first part
    len += putString(lit);
    len += putConstString(indexPage2); // HTML page second part
    /// }

    return(len); // return to the library with the number of bytes to transmit
    }


    nie sprawdzasz, czy pytanie odnosiło się strony, czy czegoś innego (np. strumienia danych).

    Jedyne co sprawdzasz, to czy:
    Cytat:
    if(localPort != 80) // I listen only to web request on port 80
    {
    return(0);
    }

    zapytanie pochodzi z przeglądarki,

    i czy:
    Cytat:
    if(memcmp(getRequest, httpMethod, 5)) // only GET method is supported here
    {
    return(0);
    }

    jest przesłane metodą GET

    Podałeś przykładowy request:
    Cytat:
    // get 10 first bytes only of the request, the rest does not matter here
    for(len = 0; len < 10; len++)
    {
    getRequest[len] = SPI_Ethernet_getByte();
    }

    Czy jest jakaś metoda sprawdzania przesyłanych zapytań przez przeglądarkę bez posiadania urządzenia? Można to może w jakimś Wireshark-u podejrzeć lub innym sofcie?

  • #6 22 Kwi 2017 11:18
    Urgon
    Poziom 36  

    AVE...

    Nie lepiej zrobić gdzieś broker MQTT + strona WWW subskrybująca do wszystkich tematów na brokerze, a ten "serwer" wysyła tylko wiadomości do stosownych tematów na brokerze? Zaletą takiego rozwiązania byłaby możliwość użycia najróżniejszych układów i urządzeń w jednym systemie...

  • #7 22 Kwi 2017 11:28
    marnowak
    Poziom 14  

    Urgon napisał:
    AVE...

    Nie lepiej zrobić gdzieś broker MQTT + strona WWW subskrybująca do wszystkich tematów na brokerze, a ten "serwer" wysyła tylko wiadomości do stosownych tematów na brokerze? Zaletą takiego rozwiązania byłaby możliwość użycia najróżniejszych układów i urządzeń w jednym systemie...


    Wyjaśnij prościej, bo nie chwytam słownictwa.

  • #8 22 Kwi 2017 11:34
    p.kaczmarek2
    Poziom 23  

    marnowak napisał:

    nie sprawdzasz, czy pytanie odnosiło się strony, czy czegoś innego (np. strumienia danych).

    Zgadza się, w zamieszczonym kodzie nie ma sprawdzania o jaki plik pyta przeglądarka, bo jest to najprostszy przykład serwerka. Po prostu nie było takiej potrzeby, ale jakby była to można te sprawdzanie bez problemu dodać.

    Dość prymitywne sprawdzanie o co pyta przeglądarka jest w oryginalnym przykładzie SPI Ethernet od mikroC. Pozwala on na sterowanie diodami przez zapytania GET, całość napisana jest w taki prosty sposób:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Jak "getRequest" zawiera "GET /index.html" to getRequest[5] to jest 'i'. Czyli tutaj sprawdzają tylko jedną literkę i to wystarcza.
    Cały kod przykładu od mikroC wraz z sprawdzaniem powyżej daję w załączniku.
    A, i ten przykład z załącznika jest dla dsPIC30F4013, więc jakbyś chciał go użyć z tym PICem co ja to byś musiał portować projekt albo po prostu przekopiować tylko obsługę zapytań do kodu ode mnie.

    marnowak napisał:

    Czy jest jakaś metoda sprawdzania przesyłanych zapytań przez przeglądarkę bez posiadania urządzenia? Można to może w jakimś Wireshark-u podejrzeć lub innym sofcie?

    Jest dużo sposobów, m.in:
    - Wireshark
    - pluginy do przeglądarek na podejrzenie treści zapytań HTTP
    - narzędzia online, takie jak http://www.rexswain.com/httpview.html
    - możesz napisać samodzielnie prosty program w C na Windowsa lub Linuxa i tam nasłuchiwać na TCP porcie 80 i z przeglądarki wysyłać zapytania. Sam język C jest taki sam na komputerze stacjonarnym jak i na PICu, więc nawet potem mógłbyś przenieść napisany parser żądań na PICa (oczywiście, na są inne biblioteki, ale ja mówię o samej składni języka).
    - możesz użyć narzędzia typu Putty by samodzielnie wysłać GETa bez przeglądarki (http://geekthis.net/post/using-putty-for-http-requests-and-more/)