Arduino schéma - arduino.sk

Arduino + Ethernet - Webserver - formuláre - EEPROM

Kompletné projekty s návodom a zdrojovým kódom
Príspevky: 84
Registrovaný: Uto 23. Dec 2014 2:15:50

Arduino + Ethernet - Webserver - formuláre - EEPROM

Poslaťod martinius96 » Ned 05. Apr 2020 23:58:43

Arduino s Ethernetom je vhodné pre rôzne sieťové aplikácie založené web technológiách - HTTP (nepodporuje HTTPS), alebo rôznych priemyselných službách založených na: Modbus, MQTT, UDP, TCP protokoloch. Ethernet shield Wiznet W5100 je možné použiť na všetky R3 Arduino dosky, je teda plne kompatibilný pre Arduino Uno, Mega 1280 / 2560.
Obrázok
Ethernet shield, respektíve modul je možné prevádzkovať v dvoch základných režimoch:
    WebClient - Klient v sieti, ktorý je schopný pripojiť sa na vzdialený server - odosielať a prijímať dáta od servera
    Webserver - server, ktorý je schopný prijímať dáta od klientov (spracovať ich), odpovedať na dopyty klientov
Dnes si ukážeme, ako použiť jednoduchý webserver na platforme Arduino + Ethernet (W5100 / W5500). Webserver umožňuje spustenie viacerých HTML podstránok, ktoré je možné klientom otvoriť a získať HTML výstup. Takýto výstup je vhodný pre statické aplikácie pre výpis textu, bez dynamiky na strane servera.
Obrázok
Vzorový príklad pre webserver (jednoduchý, statický) je možné nájsť na adrese: https://www.arduino.cc/en/Tutorial/WebServer
Problémom však býva pokročilá implementácia, napríklad s formulárom, prostredníctvom ktorého je možné zadať hodnoty a uložiť ich na webserveri permanentne. Problémové je predovšetkým spracovanie dát, nakoľko Arduino nedokáže spustiť backend jazyk typu PHP. Ukladanie dát na webserveri pre ich permanentné uloženie je využitie EEPROM pamäte.

EEPROM pamäť v prípade Arduina UNO má veľkosť 512B. EEPROM je limitovaná na 10 až 100 tisíc prepisov, pričom je energeticky nezávislá. Dáta sa na webserveri uchovajú a v prípade výpadku elektrickej energie. Riešenie pre všetky tieto faktory je možné nájsť v mojej implementácii. Dáta z formulára sú spracované druhým HTML súborom, ktorý umožňuje prevziať argumenty formulára vrátane name pre jednotlivé polia formulára.


Argumenty sú interne spracované Arduinom (nemá súvis s HTML stránkou), dáta z argumentov sú uložené do EEPROM pamäte a používateľ je následne z HTML stránky spracovania (s výpisom prebratých argumentov) presmerovaný na HTML stránku predchádzajúcu s formulárom - presmerovanie v HTML vytvorené prestredníctvom meta refresh tagu s relatívnym umiestnením hlavnej stránky.

Tento príklad bol pôvodne vyvinutý pre 12 posuvných registrov 74HC595, ktoré ovládali 3 displeje - program obsahuje iba časť zápisu a čítania z EEPROM pamäte. Každý z posuvných registrov 74HC595 ovládal osmicu led diód - reprezentujúce číslo 0-8. Každý displej obsahoval výpis 4 čísel, celkovo teda 4x 74HC595 posuvných registrov na displej. Každý posuvný register ovláda jednu cifru zadaného čísla, ktoré je vždy 4 miestne.

Aby sa zachovala 4-miestnosť čísla, využíva sa formulár s textovým vstupom pre zadanie čísel (pre typ formulára s číselným vstupom nie je možné aplikovať obmedzenie počtu znakov v poli a taktiež by sa číslo 0002 skonvertovalo na 2). Do HTML stránok je možné pridať aj jednoduchú grafiku v CSS, ale taktiež prostredníctvom link tagov v hlavičke HTML dokumentov priradiť aj externé CSS typu Bootstrap a iné a skrášliť tak vizuál stránky. Moja implementácia nevyužíva žiadne CSS súbory, štýly, classy.

Ethernet shield má mnoho nastavení, ktoré je možné použiť z hľadiska konektivity. IP adresu verzie 4 je možné definovať staticky, priradiť aj ďalšie dôležité sieťové umiestnenia ako:
    brána (gateway)
    subnet
    dns server
    dns server 2
Pôvodný formulár s dátami z EEPROM pamäte:
Obrázok
Po odoslaní nových dát prostredníctvom formuláru (zápis do EEPROm a následne presmerovanie späť):
Obrázok
Presmerovanie na pôvodnú HTML stránku s formulárom (nové hodnoty v EEPROM pamäti):
Obrázok
Viac zaujímavých projektov so zdrojovým kódom je možné nájsť na adrese: https://arduino.php5.sk/, rôzne programové implementácie (nielen) pre Arduino sú dostupné na Github-e: https://github.com/martinius96

Program pre webserver s funkcionalitou opísanou vyššie:
Kód: Vybrať všetko
/*|----------------------------------------------------------|*/
/*|HTTP webserver - FORM - HTML - PROCESSING - EEPROM        |*/
/*|AUTHOR: Martin Chlebovec                                  |*/
/*|EMAIL: martinius96@gmail.com                              |*/
/*|WEBSITE: https://arduino.php5.sk                          |*/
/*|----------------------------------------------------------|*/
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>

void writeString(char add, String data);
String read_String(char add);

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 4, 1 }; // STATICKA IP V LAN SIETI
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(80); //server port
const char terminator1[2] = " ";
const char terminator2[2] = "/";
const char terminator3[2] = "?";
const char terminator4[2] = "&";
const char terminator5[2] = "=";
void setup() {
  // Ethernet.begin(mac); //NASTAVENIE IP ADRESY DYNAMICKY CEZ DHCP
  Ethernet.begin(mac, ip, subnet); //NASTAVENIE IP ADRESY STATICKY
  server.begin();
  Serial.begin(115200);
  Serial.println("Ready");
  Serial.println("Ethernet shield na IP:");
  Serial.println(Ethernet.localIP());
}

void loop() {
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        String line = client.readStringUntil('\n');
        //     Serial.println("Request od klienta");
        //      Serial.println(line);
        char str[line.length() + 1];
        line.toCharArray(str, line.length());
        // Serial.println("Request ako pole znakov");
        // Serial.println(str);
        char *method;
        char *request;
        method = strtok(str, terminator1);
        //  Serial.println("Metóda:");
        //Serial.println(method);
        request = strtok(NULL, terminator1);
        //  Serial.println("Request:");
        //  Serial.println(request);
        if (String(request) == "/") {
          //HLAVNA ROOT HTTP STRANKA
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<!DOCTYPE html>");
          client.println("<html>");
          client.println("<head>");
          client.println("<meta charset='utf-8'>");
          //client.println("<meta http-equiv='refresh' content='5'>");
          client.println("<title>HTTP webserver - Arduino + Ethernet</title>");
          client.println("</head>");
          client.println("<body>");
          client.println("<h3>Zadajte dáta pre webserver (budú uložené do EEPROM):</h3>");
          client.println("<form action='/action.html' method='get'>");
          client.println("<input type='text' id='fname' name='fname' maxlength='4' value=" + read_String(10) + "><br>");
          client.println("<input type='text' id='fname2' name='fname2' maxlength='4' value=" + read_String(100) + "><br>");
          client.println("<input type='text' id='fname3' name='fname3' maxlength='4' value=" + read_String(200) + "><br>");
          client.println("<input type='submit' value='Odoslat'>");
          client.println("</form>");
          client.println("</body>");
          client.println("</html>");
          delay(1);
          client.stop();
          client.flush();
        } else if (String(request) == "/get_data/") {
          //PODSTRANKA PRE VYCITANIE DAT (INYM MIKROKONTROLEROM)
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<!DOCTYPE html>");
          client.println("<html>");
          client.println("<head>");
          client.println("<meta charset='utf-8'>");
          //client.println("<meta http-equiv='refresh' content='5'>");
          client.println("<title>HTTP webserver - Arduino + Ethernet</title>");
          client.println("</head>");
          client.println("<body>");
          client.println("<li>" + read_String(10) + "</li>");
          client.println("<li>" + read_String(100) + "</li>");
          client.println("<li>" + read_String(200) + "</li>");
          client.println("</body>");
          client.println("</html>");
          delay(1);
          client.stop();
          client.flush();
        } else if (String(request) == "/favicon.ico") { //fix chybajuceho faviconu
          client.stop();
        } else {
          String myString = String(request);
          if (myString.startsWith("/action.html")) {
            char* parameter;
            char* value;
            char* hodnota1;
            char* hodnota2;
            char* hodnota3;
            parameter = strtok(request, terminator3);
            Serial.println(parameter);
            value = strtok(NULL, terminator3);
            hodnota1 = strtok(value, terminator4);
            hodnota2 = strtok(NULL, terminator4);
            hodnota3 = strtok(NULL, terminator4);
            char* H_1;
            char* H_2;
            char* H_3;
            strtok(hodnota1, terminator5);
            H_1 = strtok(NULL, terminator5);
            strtok(hodnota2, terminator5);
            H_2 = strtok(NULL, terminator5);
            strtok(hodnota3, terminator5);
            H_3 = strtok(NULL, terminator5);
            hodnota2 = strtok(NULL, terminator4);
            writeString(10, String(H_1));
            writeString(100, String(H_2));
            writeString(200, String(H_3));
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();
            client.println("<!DOCTYPE html>");
            client.println("<html>");
            client.println("<head>");
            client.println("<meta charset='utf-8'>");
            client.println("<meta http-equiv='Refresh' content='5; url=/' />");
            client.println("<title>HTTP webserver - Arduino + Ethernet</title>");
            client.println("</head>");
            client.println("<body>");
            client.println("<h3>Server prijal data:</h3>");
            client.println("<li><b>Hodnota 1: </b>" + String(H_1) + "</li>");
            client.println("<li><b>Hodnota 2: </b>" + String(H_2) + "</li>");
            client.println("<li><b>Hodnota 3: </b>" + String(H_3) + "</li>");
            client.println("<b>Presmerovanie... Prosim cakajte</b>");
            client.println("</body>");
            client.println("</html>");
            delay(1);
            client.stop();
            client.flush();
          }
        }
      }
    }
  }
}

void writeString(char add, String data)
{
  int _size = data.length();
  int i;
  for (i = 0; i < _size; i++)
  {
    EEPROM.write(add + i, data[i]);
  }
  EEPROM.write(add + _size, '\0'); //Add termination null character for String Data
}


String read_String(char add)
{
  int i;
  char data[100]; //Max 100 Bytes
  int len = 0;
  unsigned char k;
  k = EEPROM.read(add);
  while (k != '\0' && len < 500) //Read until null character
  {
    k = EEPROM.read(add + len);
    data[len] = k;
    len++;
  }
  data[len] = '\0';
  return String(data);
}

Späť na Hotové projekty