Tutorial: Arduino, Ethernet e pagine multiple su SD Card

Probabilmente sei tra gli appassionati che hanno già letto il mio articolo su Arduino Ethernet e SD Card, e probabilmente come altri che mi hanno scritto ti sei chiesto se è possibile realizzare un piccolo WebServer in grado di gestire più pagine e non solo la home …

Ethernet Shield Arduino

… eccoti accontentato 🙂

Ti mostro oggi uno sketch con cui puoi gestire più pagine e fare anche qualche cosa in più  😆

Come nel precdente articolo anche in questo caso le pagine che lo sketch carica sono sulla SD Card da 2Gb inserita nello slot della Ethernet Shield:

SD Card Ethernet Shield

in questo modo è più facile fare le modifiche alle pagine inserendo la scheda di memoria nel tuo computer o mac per costruire le tue pagine web e poi spostarla nella shield per farle eseguire al server.

Curiosità: mi sono accorto solo nel realizzare questo tutorial che la Ethernet Shield ha un adesivo sul retro con 6 numeri esadecimali separati da un trattino, questa notazione è tipica dei Mac Address, ho inserito questo numero sul sito: http://www.coffer.com/mac_find/?string=90-A2-DA-00-5A-82 dove il numero 90-A2-DA-00-5A-82 è quello che ho letto sull’etichetta ed ho scoperto che il vendor è: GHEO SA una azienda svizzera:

schermata del sito mac finder

ed ecco il Mac Address della mia shield:

Mac Address Arduino Ethernet

a cosa serve questa info? Io ho pensato di modificare il mio sketch inserendo come mac address quello della scheda, in generale anche inserire un Mac Address inventato non da problema, potresti incontrare dei problemi se la tua Arduino Ethernet Shield fosse connessa direttamente ad Internet senza passare per un router o altro dispositivo, in tal caso i Mac Address nel Web devono essere univoci per questo sono composti da 6 numeri, i primi 3 indicano il vendor (produttore) ed i secondi 3 indicano un numero progressivo che il produttore assegna a ciascuna scheda.

Lo sketch del miniWebServer è il seguente:

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

#define maxLength 25

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x5A, 0x82 };
byte ip[] = { 192,168,2,130 };
File htmlFile;
EthernetServer server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
  if (!SD.begin(4)) { return; }
}

void loop()
{
  char* file_to_load = "home.htm";
  String inString = String(maxLength);

  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (inString.length() < maxLength) {
          inString += c;
        }
        if (c == '\n' && currentLineIsBlank) {
          if (inString.indexOf(".htm") > -1) {
            String new_file_load;
            int rootIndex = inString.indexOf("/");
            new_file_load = inString.substring((rootIndex+1), (rootIndex+13));

            int endIndex = new_file_load.indexOf(" ");
            if (endIndex > -1) {
              new_file_load = new_file_load.substring(0, endIndex);
            }
            if (new_file_load != "")  {
              new_file_load.toCharArray(file_to_load,12);
            }
          }

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println(); 

          read_file( "header.htm",client );
          read_file( file_to_load,client );
          read_file( "footer.htm",client );

          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

void read_file( char* page_html, EthernetClient client )
{
  htmlFile = SD.open( page_html );
  if (htmlFile) {
    while (htmlFile.available()) {
        client.write(htmlFile.read());
    }
    // close the file:
    htmlFile.close();
  }
}

rispetto al precedente sketch che hai visto ci sono alcune differenze che ti mostro nel dettaglio:

linea 05: definisci una costante maxLength di 25 sarà la costante su cui si basa l’oggeto String per l’istanza inString che vedrai nelle righe succesive;

linea 07: nota il mac address che ho inserito è quello della mia scheda, puoi sostituirlo con il tuo;

le linee successive relative a Ip, File, sono identiche;

linea 10: l’oggetto Server nella versione dell’IDE 1.0 è cambiato in EthernetServer per cui ho adeguato il codice;

la funzione setup() è invariata;

linea 21: all’interno della funzione loop() definisci una variabile di tipo char* in cui inserisci il nome della prima pagina in caso non sia specificata alcuna pagina da chiamare, ricorda che i file devono essere sempre del tipo 8.3 ( 8 caratteri per il nome, un punto e 3 caratteri per l’estensione)

linea 22: definisci l’istanza dell’oggetto String, chiama questa instanza inString e ci memorizzerai l’url chiamato, è importante che sia di tipo String così che tu possa usare tutti i metodi di manipolazione delle stringhe offerti da Arduino;

linea 24: come la Server anche la classe Client è stata sostituita con la EthernetClient nell’IDE 1.0;

le righe successive sono identiche a quelle già viste;

linee 30-32: questa condizione è nuova ed assegna alla variabile inString il risultato letto dal metodo read() della classe EthernetClient; in pratica assegna i valori di Header letti dalla chiamata del Browser;

linee 34-46: qui si compiono i giochi per far funzionare il tuo miniWebServer con Arduino, ecco cosa fa lo sketch linea per linea:

linea 34: usa il metodo indexOf() della classe String cercando il testo “.htm” sai che ogni file deve avere una estensione di tipo .xxx dove le tre x sono i tre caratteri dell’estensione, l’estensione tipica delle pagine HTML in notazione di tre caratteri è htm per cui tutte le tue pagine saranno .htm; il metodo indexOf(“.htm”) restituisce la posizione del valore cercato nella stringa e -1 se non lo trova per cui in questa riga se trova .htm entra nella condizione if. A cosa serve? la prima volta ti collegherai al tuo server solo con l’IP senza specificare nulla, a questo punto la condizione di if viene evitata e la pagina di default ( vedi linea 21 ) diventa la pagina chiamata, dalla seconda chiamata in poi la nuova pagina avrà estensione htm e ti farà entrare nella condizione if;

linea 35: definisci una nuova istanza della classe String;

linea 36: con il metodo indexOf cerca la prima occorrenza del carattere “/” siccome l’url è composto da http://192.168.2.130/[pagina].htm l’header conterrà una stringa simile alla seguente: 25GET /home.htm HTTP/1.1 dove la parte http://192.168.2.130 non è riportata e l’Url parte da /home.htm, trovato il carattere “/” sai dove inizia il nome della pagina da chiamare;

linea 37: assegna all’istanza new_file_load definita alla linea 35, il valore risultante dall’operazione di substring, il metodo substring( inizio, fine) estrae da una stringa una sua parte dal numero di carattere definito come inizio fino al numero di carattere definito come fine;

linea 39: nella stringa appena estratta new_file_load potrebbero esserci caratteri vuoti che determinano la fine della linea, questo perchè le pagine possono avere nomi di 12 caratteri ( 8.3 => 8+1+3 = 12 ) ma possono anche averne meno, in tal caso dopo aver tagliato i 12 caratteri massimi attesi verifica se ci sono spazi;

linea 40: controlla il risultato della indexOf precedente;

linea 41: estrae la parte della stringa dal carattere numero 0, inizio, fino al carattere spazio trovato;

linea 43: un ultimo controllo ti assicura che dopo tutti i tagli eseguiti esista ancora un nome pagina da chiamare;

linea 44: assegna la stringa estratta alla variabile  file_to_load definita alla linea 21; per farlo utilizza il metodo toCharArray( istanza, numero di caratteri) questa operazione è necessaria  in quanto new_file_load è di tipo String mentre file_to_load è di tipo char* e le funzioni che chiameremo dopo vogliono che il valore passato sia di tipo char*, per saperne di più sulla conversione String2char leggi i miei articoli: Tutorial Arduino e le stringhe e Tutorial Arduino e le stringhe II

linee 48-50: sono invariate, impostano gli header di risposta per il Browser;

linee 52-54: sono identiche ma il loro scopo è ben preciso, tutte chiamano una pagina ma la prima e l’ultima chiamano una pagina definita e fissa che deve chiamarsi header.htm e footer.htm in queste due pagine potrai mettere intestazione e pié pagina fissa per tutte le pagine Html, ho fatto questo introducendo il concetto di pagina inclusa, se programmi in linguaggi come php, asp o altro conosci già questo trucco utilizzato per semplificare la vita del programmatore. In pratica le parti comuni di un sito, come ad esempio l’intestazione ed il pié pagina si scrivono una sola volta e le si includono in tutte le altre pagine, in questo modo se devi fare una modifica all’intestazione non dovrai modificare tutti i file del sito ma solo l’intestazione. In questo esempio ho voluto che fosse lo sketch a fare per te questa operazione per cui chiama in sequenza: l’intestazione ( header.htm ), la pagina che hai chiesto ( vedi linee 34-46 ) ed infine la chiusura pagina ( footer.htm );

linee 55-69: sono invariate;

linea 71: definisci la funzione richiamata alle linee 52-54, tale funzione deve accettare in ingresso 2 parametri: il primo è la pagina da chiamare, il secondo è l’istanza dell’oggetto Client con cui rispondere al browser;

linea 73: varia rispetto al precedente sketch solo per il nome del file chiamato che viene ripreso dal primo parametro passato alla funzione;

linea 76: c’è un piccolo cambiamento dovuto alla variazione della classe EthernetClient che non supporta più l’opzione BYTE nel metodo print per cui ho cambiato con il metodo write che non soffre il problema della codifica caratteri.

Tutte le righe non descritte non sono variate.

Ed ecco i file che io ho utilizzato nel mio Sketch, puoi scaricarli qui, poi decomprimi il file zip e metti tutti i file nella memory card senza cartelle o path, metti la memory card nella ethernet shield e premi il pulsante reset prima di collegarti con un browser.

Io mi ci sono collegato con il mio iPhone 3G ed ho catturato alcune schermate:

ethernet-shield-home

home.htm

whoami.htm

mauroa.htm

contact.htm

Buon divertimento.

Prima di inserire un commento, per favore, leggi il regolamento

Permanent link to this article: https://www.mauroalfieri.it/elettronica/tutorial-arduino-ethernet-e-pagine-multiple-su-sd-card.html

156 pings

Skip to comment form

  1. […] Tutorial: Arduino, Ethernet e pagine multiple su SD Card […]

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.