Image
6.3.2017 2 Comments

Seriál: ARDUINO - programovanie mikrokontrolérov Atmel/Zobrazenie dvoch teplôt v grafickej podobe

Zobrazenie dvoch teplôt v grafickej podobe

V predchádzajúcej časti sme si vysvetlili, ako možno na webovej stránke zobrazovať analógovú hodnotu v grafickej podobe, napríklad v tvare kruhového merača. Využili sme na to znalosti s predchádzajúcich lekcií, hlavne s využitím systému AJAX, čo je asynchrónny JavaScrip a XML. V dnešnej časti nadviažeme na minulú časť, avšak ukážeme si zobrazovanie dvoch analógových hodnôt. Zameriame sa hlavne na odlišnosti oproti zobrazovaniu jednej hodnoty. Tieto odlišnosti potom dokážeme využiť pri zobrazovaní viacerých (tri a viac) analógových hodnôt v tvare grafického merača.

Hardvérové zapojenie

V minulej časti sme použili iba jeden potenciometer, z ktorého sme vyčitávali iba jednu analógovú hodnotu. Bežec potenciometra bol pripojený k analógovému pinu A2. Toto zapojenie je možné rozšíriť o pripojenie druhého potenciometra k analógovému pinu A3, tak ako na obrázku č.1. Aj druhý potenciometer je pripojený svojimi krajnými bodmi k napájaciemu napätiu (5 Voltov a GND) a stredný vývod k analógovému pinu A3. V prípade, že stred potenciometra pripojíme k inému analógovému pinu, musíme upraviť aj skeč Arduina! Inak sa hodnoty nebudú zobrazovať správne.

Aby sme však vytvorili aj niečo užitočné, nebudeme k Arduinu pripájať predsa potenciometre (aj keď v určitej aplikácii je to výhodné), ale pripojíme si napríklad senzory teploty. Najlepšie by bolo, keby to boli senzory, ktoré sa správajú podobne ako potenciometre, aby sme nemuseli pracne upravovať program z minulého príkladu. A naozaj – existujú senzory (termistory) MCP9700. MCP9700 je lineárny termistor, teda odpor závislý na teplote. Meria v rozsahu od -40 do +150 stupňov Celzia. Citlivosť je 10mV/stupeň Celzia s offsetom 500 mV. Značenie vývodov je na obrázku č.2. Jeho výhodou je, že nepotrebuje žiadne iné okolité súčiastky, cez to všetko je vhodné pripojiť dva kondenzátory o kapacite 100n na výstup a napájanie ku každému termistoru. Nie je to výslovne nutné, avšak s kondenzátormi bude zariadenie stabilnejšie. Ako sa termistory pripoja k Arduinu ukazuje obrázok č.3.

Softvérová časť sa podobne ako v predchádzajúcom príklade skladá s webovej stránky, uloženej na SD karte a skeče uloženej v Arduinu.

HTML  stránka

Na výpise č.1 je neúplný obsah webovej stránky index.htm, uloženej na SD karte:

<!DOCTYPE html>
<html>
    <head>
        <title>Arduino Dva Teplomery</title>
        <script>
        var data_val = 0;
        var data_val2 = 0;
<!-- Tu je kód merača -->

      
        function GetArduinoInputs()
        {
            nocache = "&nocache=" + Math.random() * 1000000;
            var request = new XMLHttpRequest();
            request.onreadystatechange = function()
            {
                if (this.readyState == 4) {
                    if (this.status == 200) {
                        if (this.responseXML != null) {
                            data_val  = this.responseXML.getElementsByTagName('analog')[0].childNodes[0].nodeValue;
                            data_val2 = this.responseXML.getElementsByTagName('analog')[1].childNodes[0].nodeValue;
                            data_val  = ((data_val * 5.0 / 1024.0) - 0.5) / 0.01;
                            data_val2 = ((data_val2 * 5.0 / 1024.0) - 0.5) / 0.01;
                        }
                    }
                }
            }
            request.open("GET", "ajax_inputs" + nocache, true);
            request.send(null);
            setTimeout('GetArduinoInputs()', 200);

          
        }
    </script>
    </head>
    <body onload="GetArduinoInputs()">
        <h1>Arduino Teplomer</h1>
        <canvas id="an_gauge_1" data-title="Vonkajšia" data-units="Teplota &deg;C" width="500" height="500" data-major-ticks="-40 -30 -20 -10 0 10 20 30 40 50 60" data-type="canv-gauge" data-min-value="-40" data-max-value="60" data-highlights="-40 0 #4D89F2, 0 10 #25B8D9, 10 30 #0BB950, 30 40 #cc5, 40 60 #f33" data-onready="setInterval( function() { Gauge.Collection.get('an_gauge_1').setValue(data_val);}, 200);"></canvas>
        <canvas id="an_gauge_2" data-title="Vnútorná" data-units="Teplota &deg;C" width="500" height="500" data-major-ticks="-10 0 10 20 30 40" data-type="canv-gauge" data-min-value="-10" data-max-value="40" data-highlights="-10 0 #4D89F2, 0 10 #25B8D9, 10 30 #0BB950, 30 40 #cc5, 40 40 #f33" data-onready="setInterval( function() { Gauge.Collection.get('an_gauge_2').setValue(data_val2);}, 200);"></canvas>
    </body>
</html>

Poznámka:

Na uvedenom výpise je neúplný obsah HTML stránky. Slúži na vysvetlenie činnosti kódu a tak neobsahuje definíciu merača. Úplný HTML kód si môžete stiahnuť zo servera redakcie.

Keďže vychádzame z príkladu v minulej časti, nebudeme kód rozoberať do podrobností, ale vysvetlíme si iba odlišnosti.

Všimnime si, že v AJAX skripte pribudla ďalšia premenná data_val2, ktorú definujeme príkazom var data_val2 = 0; Tá bude obsahovať hodnoty z analógového vstupu A3 na Arduine. Tak ako prvú, tak aj druhú analógovú hodnotu zo vstupu A3 bude webová stránka získavať z XML súboru, ktorý jej odošle Arduino. Tú najprv prevedieme na text, a to príkazom

document.getElementById("input4").innerHTML =
        this.responseXML.getElementsByTagName('analog')[1].childNodes[0].nodeValue;
 
a potom ako premennú, ktorú potrebuje merač na vykreslenie ručičky merača:
data_val2 = this.responseXML.getElementsByTagName('analog')[1].childNodes[0].nodeValue;
 
Ako sme si už povedali, termistor MCP9700 udáva teplotu na svojom výstupe ako analógovú hodnotu v miliVoltoch. Aby sme ju dokázali zobrazovať ako číslo v stupňoch Celzia, musíme získané analógové  hodnoty prepočítať pomocou vzorca:
data_val  = ((data_val * 5.0 / 1024.0) - 0.5) / 0.01;
data_val2 = ((data_val2 * 5.0 / 1024.0) - 0.5) / 0.01;
 
A keďže chceme zobrazovať aj druhý merač, musíme ho v sekcii <body>  nadefinovať ďalším tagom <canvas>.  Pridelíme mu meno an_gauge_2. Teraz musíme zviazať meno merača s premennou JavaScriptu data_val2. Podobne ako v predchádzajúcom príklade to dosiahneme funkciou
... Gauge.Collection.get('an_gauge_2').setValue(data_val2); ...

V  tagu <canvas> môžeme nadefinovať prvky merača, ako je jeho rozsah, popis či jednotka zobrazovania a farebnú škálu. Všimnime si, že merač pre vonkajšiu hodnotu má iný rozsah ako merač pre vnútornú hodnotu. Skúste sa trochu pohrať s parametrami tagu <canvas> podľa vašich požiadaviek a sledujte zmeny na obrazovke webového prehliadača.

Skeč Arduina

Skeč aplikácie v Arduine je takisto veľmi podobná tej z minulej časti a preto ju nebudeme podrobnejšie vysvetľovať.  Jej obsah je výpise č.2:

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// 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 inicializovana");
    // 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) {
                   
                    client.println("HTTP/1.1 200 OK");// zašle klasickú hlavičku
                    // táto časť hlavičky nižšie v závislosti na tom, či
                    // web stránka alebo XML stránka je požadovaná
                    // Ajax požiadavka - zaslanie XML súboru
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // zaslanie zvyšku hlavičky
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        // odoslanie XML súboru obsahujúceho vstupné stavy
                        XML_response(client);
                    }
                    else {  // odoslavie klasickej hlavičky
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        webFile = SD.open("index.htm");        // otvor súbor index.htm
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // zašli stránku klientovi
                            }
                            webFile.close();
                        }
                    }
                    // vypíš prijatú HTTP požiadavku na sériový port
                    Serial.print(HTTP_req);
                    // 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 if (client.available())
        delay(1);      // dajme čas klientovi prijať dáta
        client.stop(); // ukonči spojenie s klientom
    } // koniec if (client)
}
 
// zaslanie XML súboru obsahujúceho analógové hodnoty
void XML_response(EthernetClient cl)
{
    int analog_val;
   
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
      // čítaj analóg pin A2
    analog_val = analogRead(2);
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
     // čítaj analóg pin A3
    analog_val = analogRead(3);
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
    cl.print("</inputs>");
}
 
// 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;
}

Vidíme, že aby sme mohli odosielať v XML tvare aj hodnotu vstupu A3, pridali sme do sekcie XML_response() tieto riadky:

analog_val = analogRead(3);
cl.print("<analog>");
cl.print(analog_val);
cl.print("</analog>");

Skeč spolu s HTML stránkou si stiahneme so serveru redakcie. HTML stránku nahráme pod názvom index.htm na SD kartu, skeč vložíme do IDE prostredia Arduina, preložíme a nahráme do Arduina. Zasunieme ethernet shield, na prehliadači nastavíme správnu IP adresu a na obrazovke uvidíme grafický merač podobný tomu na obrázku č.4.

Súbory na stiahnutie:

Index.htm

teplomer.ino

výpis č. 1 - index.txt

výpis č. 2 - skeč.txt


Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

ITPro

Linux súkromne i pracovne v2.0 (40. časť) Príkazy git

18.06.2019 14:20

Táto časť seriálu bude stručným sumárom základných príkazov CLI, pomocou ktorých naštartujeme prácu v systéme git. Pomocou tejto jednoduchej referencie sa naučíme inicializovať prácu so systémom git a ...

ITPro

Praktická kryptológia (25. časť) Hašovacie konštrukcie

18.06.2019 14:05

V prípade, že sa rozhodneme hlbšie si naštudovať základy hašovacích algoritmov MD a SHA, určite sa stretneme s pojmami ako Merklova-Damgårdova, resp. Wide-Pipe konštrukcia. Pomocou nich sa za použitia ...

ITPro

VMware NSX L2 VPN alebo Ako si ponechať IP adresu

19.06.2019 14:01

V digitálnej dobe 21. storočia čoraz viac spoločností outsourcuje svoje IT riešenia a systémy k rôznym poskytovateľom na IT trhu ako súčasť znižovania nákladov. Aj keď v poslednom čase pozorujeme znač ...

q

2 Comments

  1. obrázky reakcia na: Seriál: ARDUINO - programovanie mikrokontrolérov Atmel
    8.3.2017 12:03
    A čo obrázky, na tie ste zabudli? Doplnte ich!
    Reagovať
  2. (TU TREBA DOPLNIŤ LINK na STIAHNUTIE!!!) reakcia na: Seriál: ARDUINO - programovanie mikrokontrolérov Atmel
    7.2.2017 15:02
    (TU TREBA DOPLNIŤ LINK na STIAHNUTIE!!!)
    Reagovať

Vyhľadávanie

SWAN_062019

Najnovšie videá