ARDUINO – programovanie mikrokontrolérov Atmel

0

(web server na SD karte – zobrazenie obrázkov na stránke)

V minulej časti sme si ukázali, ako vytvoriť  webovú stránku, uložiť na SD kartu a pomocou http servera a Arduina túto stránku zobrať na obrazovke prehliadača. Toto všetko sme robili pre určitý dôvod – kvôli obmedzenej kapacite pamäte Arduina. My už vieme, aké limity má Arduino a tiež vieme, že webová stránka je napísaná v HTML jazyku, čo je v podstate čistý text. Cez to všetko sa môže stať, že pri dlhších kódoch narazíme na koniec pamäte. Existujú však webové stránky, ktoré obsahujú určité grafické prvky, ako sú obrázky alebo animácie, ktoré by sme do pamäte Arduina skutočne nedostali. Preto sme sa naučili vytvoriť a spustiť stránku z iného úložiska – z SD karty. Tu je hranica kapacity poriadne ďaleko a vojdú sa nám tu aj obrázky. A ako na to, to si dnes ukážeme a k tomu si pridáme ešte niečo – odkaz na inú stránku, čo je v podstate princíp hypertextu.

Webová stránka s obrázkom a odkazom

Ako prvé si pripravíme webovú stránku v HTML jazyku s názvom index.htm:

   
        Arduino Web server na SD karte
       
   
   
       

Arduino Web server na SD karte s obrázkom a linkami

       
       

Choď na stranu 2 .

   
 

Je to klasická HTML stránka skladajúca sa z hlavičky (HEAD) a tela (BODY). V tele je nadpis H1. Toto už vieme a poznáme. Nasledujúci tag  spôsobí zaslanie žiadosti o obrázok s názvom arduino.jpg. Ďalší tag   Choď na stranu 2 vytvorí odkaz (link), kde  po kliknutí naň sa vytvorí požiadavka o HTML stránku s názvom page2.htm.

Jej HTML kód  je takýto:

   
        Arduino Web server na SD karte
   
   
       

Arduino Web server - strana 2

        
       

Choď na hlavnú stránku page.

   

Zase sa jedná o podobnú, veľmi jednoduchú stránku, ktorá okrem nadpisu H1 obsahuje aj odkaz na obrázok s názvom uno.jpg. A obsahuje aj link na návrat na hlavnú stránku.

Vytvoríme obidva súbory index.htm aj page2.htm a nahráme ich na SD kartu. Je samozrejmé, že na SD karte sa musia nachádzať aj obidva obrázky arduino.jpg a uno.jpg. Je jedno, aké obrázky to sú , jednoducho ich stiahneme z Internetu a premenujeme.

Ako to teda funguje?

Keď sa webový prehliadač pripojí k web serveru, odošle webovému serveru protokolom http požiadavku metódou GET o zaslanie hlavnej webovej stránky s názvom index.htm. Túto príjme a v zmysle príkazov (tagov) HTML jazyka ju zobrazí na obrazovke počítača. Keď počas spracovania webovej stránky zistí, že táto má obsahovať obrázok arduino.jpg (tag img src), pošle druhú požiadavku metódou GET o zaslanie obrázku arduino.jpg. Následne server odošle obrázok prehliadaču. Keď prehliadač pri spracovávaní kódu web stránky zistí, že bolo kliknuté na odkaz na inú stránku (a href), znovu odošle už tretiu požiadavku metódou GET o zaslanie HTML kódu súboru page2.htm.  Ten analogicky vykoná a požiada metódou GET o zaslanie obrázku s názvom uno.jpg. Ak klikneme na link pre návrat na hlavnú stránku, opätovne požiada o zaslanie stránky index.htm. Jednoduché, nie?

Teraz prejdeme k tvorbe skeče pre Arduino, ktorá vyššie spomínaný postup vykoná.

Obsah skeče je na výpise:

#include
#include
#include
// velkost bufferu pre požiadavky
#define REQ_BUF_SZ   20
 
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 100, 203); // IP addresa
EthernetServer server(80);  // server na port 80
File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // bufferovaná požiadavka
char req_index = 0;              // index na HTTP_req buffer
 
void setup()
{
    // vypnutie Ethernet čipu
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
   
    Serial.begin(9600);       // zapnutie sériového portu pre ladenie
   
    // inicializácia SD karty
    Serial.println("Inicializacia SD karty...");
    if (!SD.begin(4)) {
        Serial.println("Chyba - SD karta nie je inicializovana");
        return;   
    }
    Serial.println("OK - SD karta initializovana");
    // hľadáme súbor index.htm
    if (!SD.exists("index.htm")) {
        Serial.println("Chyba - nemozem najst subor index.htm");
        return;  // návrat, ak nemôže nájsť súbor index.htm
    }
    Serial.println("OK - subor index.htm najdeny.");
   
    Ethernet.begin(mac, ip); 
    server.begin();          
}
 
void loop()
{
    EthernetClient client = server.available(); 
 
    if (client) { 
        boolean prazdnyRiadok = true;
        while (client.connected()) {
            if (client.available()) {   // ak klient zaslal požiadavku
                char c = client.read(); // prečítaj 1 bajt od klienta
                // do bufferu vloží HTTP požiadavku
               
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // ulož znak HTTP požiadavky
                    req_index++;
                }
                // vypíš HTTP požiadavku na serial monitor
                Serial.print(c);
                // posledný riadok klientskej požiadavky je prázdny riadok a končí znakom \n
                if (c == '\n' && prazdnyRiadok) {
                   
                    if (StrContains(HTTP_req, "GET / ")
                                 || StrContains(HTTP_req, "GET /index.htm")) {
                        client.println("HTTP/1.1 200 OK");      // zašleme klasickú hlavičku
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("index.htm");        // otvor súbor index.htm
                    }
                    else if (StrContains(HTTP_req, "GET /page2.htm")) {
                        client.println("HTTP/1.1 200 OK");      // zašleme klasickú hlavičku
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("page2.htm");        // otvor súbor page2.htm
                    }
                    else if (StrContains(HTTP_req, "GET /arduino.jpg")) {
                        webFile = SD.open("arduino.jpg");     // otvor súbor arduino.jpg
                        if (webFile) {
                            client.println("HTTP/1.1 200 OK");  // zašleme potvrdenie
                            client.println();
                        }
                    }
 
 
                    else if (StrContains(HTTP_req, "GET /uno.jpg")) {
                        webFile = SD.open("uno.jpg");         // otvor súbor uno.jpg
                        if (webFile) {
                            client.println("HTTP/1.1 200 OK");  // zašleme potvrdenie
                            client.println();
                        }
                    }
 
                   
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // zašli stránku klientovi
                        }
                        webFile.close();
                    }
                    // vymaž index bufferu a obsah bufferu nastav na nulu
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // každý riadok textu prijatý od klienta končí znakmi \r\n
                if (c == '\n') {
                    // posledný znak na riadku prijatého textu
                    prazdnyRiadok = true;
                }
                else if (c != '\r') {
                   
                    prazdnyRiadok = false;
                }
            } // koniec if (client.available())
        } // koniec while (client.connected())
        delay(1);      // dajme čas klientovi prijať dáta
        client.stop(); // ukonči spojenie s klientom
    } // koniec if (client)
}
 
// nastavuje každý element reťazca na nulu (vymaže pole)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}
 
// hľadá znaky sfind v reťazci str
// vráti hodnotu 1 ak znaky našiel
// vráti hodnotu 0 ak znaky nenašiel
 
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;
 
    len = strlen(str);
   
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }
 
    return 0;
}

Výpis je komentovaný, aby sme sa nemuseli vracať k nám už známym postupom a krokom, podrobnejšie si vysvetlíme len nové funkcie.

Na začiatku sa vykoná aktivácia SD karty a stav aktivácie sa zobrazí v Serial Monitore. Potom Arduino (web server) čaká na požiadavku od klienta. Keď klient zašle požiadavku, táto sa uloží do premennej typu pole s názvom HTTP_req. Postup ukladania do poľa je vyznačený červenou farbou.

Nasleduje sekcia vyhodnocovania požiadaviek. Pamätáte sa ešte na projekt, kde sme klikaním na webovú stránku rozsvecovali LED diódy alebo ovládali relé pripojené k Arduinu? Princíp činnosti programu spočíval v tom, že sme na strane Arduina odchytávali text, ktorý pomocou metódy GET odosielal webový prehliadač. Ak bol text napr. led1=1, tak sa rozsvietila prvá LED dióda, ak bol text napr.rele2=0, tak sa vyplo druhé relé a podobne. Aj v tomto prípade budeme vyhodnocovať požiadavky. Tie sme si vyššie spomínaným spôsobom uložili do poľa HTTP_req. Pomocou nami vytvorenej novej funkcie StrContains() hľadáme v poli konkrétny text (použitie funkcie je vyznačené na výpise modrou farbou):

  • Ak sa v poli HTTP_req nájde text GET / alebo GET /index.htm, server odošle prehliadaču klasickú http hlavičku a do premennej webFile na načíta súbor index.htm
  • Ak sa v poli HTTP_req nájde text GET /page2.htm, server odošle prehliadaču klasickú http hlavičku a do premennej webFile na načíta súbor page2.htm
  • Ak sa v poli HTTP_req nájde text GET /arduino.jpg, server načíta do premennej webFile súbor arduino.jpg. Ak sa podarilo obrázok z SD karty načítať a uložiť do premennej webFile, server odošle prehliadaču potvrdenie OK
  • Ak sa v poli HTTP_req nájde text GET /uno.jpg, server načíta do premennej webFile súbor uno.jpg. Ak sa podarilo obrázok z SD karty načítať a uložiť do premennej webFile, server odošle prehliadaču potvrdenie OK.

Nakoniec sa obsah premennej webFile (čiže stránka alebo obrázok) odošle prehliadaču (klientovi).

Ďalšou nami definovanou funkciou StrClear() vymažeme pole HTTP_req pre príjem nových požiadaviek od klienta.

Nakoniec ukončíme spojenie s klientom.

Na konci výpisu skeče pre Arduino sa nachádzajú definície nových funkcií StrClear()StrContains() (zobrazené fialovou farbou). Za domácu úlohu si prezrite ich kód a skúste pochopiť, ako fungujú. Kto si s tým nedokáže poradiť, nech mi napíše na arduino@cevaro.sk a ja mu tie funkcie popíšem podrobnejšie.

Obsah skeče napíšeme (alebo použijeme Ctrl-C a Ctrl-V), preložíme a nahráme do Arduina. Arduino s ethernet shieldom pripojíme káblom k notebooku alebo počítaču. Spustíme webový prehliadač a zadáme IP adresu servera. Zároveň spustíme Serial Monitor, kde môžeme sledovať ladiace informácie o aktivácii SD karty a zároveň hlavičky požiadaviek odosielaných od prehliadača do servera. Príklad prvotnej komunikácie je na obrázku č.1. Na obrazovke prehliadača uvidíme hlavnú webovú stránku (obrázok č.2). Keď klikneme na link „Choď na stranu 2“, Prehliadač odošle novú požiadavku, ktorú zase môžeme sledovať na Serial Monitore (obr.č.3) a na obrazovke prehliadača sa zobrazí druhá stránka (obr.č.4).

Nabudúce si ukážeme, ako zobraziť na webovej stránke nielen obrázky, ale aj hodnoty snímané rôznymi snímačmi ako je teplota či tlak. A tieto hodnoty zobrazíme pomocou efektného grafického merača s ručičkou.

Zobrazit Galériu

Miroslav Oravec

Všetky autorove články

Pridať komentár