In questo articolo parliamo di come l’Arduino configura l’Ethernet Shield leggendo i parametri da un file in SD.
Con il codice seguente verrà mostrato come poter configurare l’Ethernet Shield leggendo i parametri in un file di testo salvato nell’SD.
Le caratteristiche principali dello shield sono:
- Tensione di alimentazione 5V (erogati da Arduino)
- Ethernet Controller: W5100 con 16K di buffer interno
- Velocità della connessione: 10/100Mb
- Connessione con l’Arduino su porta SPI
L’Ethernet Shield che è stato preso in considerazione integra uno slot per l’inserimento della SD com’è ben visibile nell’immagine.
Lo sketch allegato di seguito è compatibile con l’IDE 0022.
/* * Ethernet shield attached to pins 10, 11, 12, 13 * SD pin 4 * * pin 2 digit output * pin 3 digit pwm */ #include <SD.h> #include <SPI.h> #include <Ethernet.h> byte *mac = NULL; byte *ip = NULL; int port; byte *gateway = NULL; byte *subnet = NULL; Server server = NULL; #define ASCII_HEX_START_CHAR 65 //Index of ascii char 'A' /************ SDCARD STUFF ************/ #define SERVER_CONFIG_FILE_NAME "CONFIG.TXT" //Server config file name #define SRV_MAC_TOKEN "srv_mac" //Mac token in the config file #define SRV_IP_TOKEN "srv_ip" //Ip token in the config file #define SRV_PORT_TOKEN "srv_port" //Port token in the config file #define SRV_GATEWAY_TOKEN "gateway" //Gateway token in the config file #define SRV_SUBNET_TOKEN "subnet" //Subnet token in the config file #define DFN_TIPOPORTDIGIT "portD" //Define delle porte digitali tipo input o output #define SRV_NUMBER_TOKEN 5 //Tokens number Sd2Card card; //Sd card objcet SdVolume volume; //Sd card volume object SdFile root, //Root dir of sd card serverCfgFile; //Server config file in sd card //Store error strings in flash to save RAM #define error(s) error_P(PSTR(s)) String readString; void error_P(const char* str) { PgmPrint("Error: "); SerialPrintln_P(str); if (card.errorCode()) { PgmPrint("SD error: "); Serial.print(card.errorCode(), HEX); Serial.print(','); Serial.println(card.errorData(), HEX); } while(1); } boolean initValue(String info, String value){ if(info.equals(SRV_MAC_TOKEN)){ //value si riferisce al mac free(mac); //libera la memoria in caso di inizializzazioni precedenti mac = strMac2byteVect(value); if (mac == NULL) return false; return true; } if(info.equals(SRV_IP_TOKEN)){ //value si riferisce ad un ip free(ip); //libera la memoria in caso di inizializzazioni precedenti ip = strIp2byteVect(value); if (ip == NULL) return false; return true; } if(info.equals(SRV_PORT_TOKEN)){ port = value.toInt(); if (port <= 1) return false; return true; } if(info.equals(SRV_GATEWAY_TOKEN)){ free(gateway); gateway = strIp2byteVect(value); if (gateway == NULL) return false; return true; } if(info.equals(SRV_SUBNET_TOKEN)){ free(subnet); subnet = strIp2byteVect(value); if (subnet == NULL) return false; return true; } return false; } void setup() { Serial.begin(9600); PgmPrint("Free RAM: "); Serial.println(FreeRam()); pinMode(10, OUTPUT); // set the SS pin as an output (necessary!) digitalWrite(10, HIGH); // but turn off the W5100 chip! if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed"); // initialize a FAT volume if (!volume.init(&card)) error("vol.init failed"); PgmPrint("Volume is FAT"); Serial.println(volume.fatType(),DEC); if (!root.openRoot(&volume)) error("openRoot failed"); // list file in root with date and size PgmPrintln("Files found in root:"); root.ls(LS_DATE | LS_SIZE); Serial.print("Server parameters initializations..."); if (!serverCfgFile.open(root, SERVER_CONFIG_FILE_NAME, O_RDONLY)) error("open file failed"); char *tmpChr; String valueStr, infoStr; boolean isValue; for (boolean endof = false; !endof;){ //Ciclo sui token (righe) isValue = false; for(endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1); !endof && *tmpChr != 'n'; endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1)){ //Ciclo sui caratteri if (*tmpChr == '#'){ //La riga contiene un commento for(endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1); !endof && *tmpChr != 'n'; endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1)); break; } if (*tmpChr == 't' || *tmpChr == ' ') //E' stato letto il nome del tag isValue = true; if(isValue){ //Se è stato letto il tag viene letto il valore if (*tmpChr != 't' && *tmpChr != ' ') valueStr += *tmpChr; } else infoStr += *tmpChr; free(tmpChr); } initValue(infoStr, valueStr); //Inizializza il valore delle variabili globali valueStr= ""; infoStr = ""; } if (((int)gateway[0])==0 && ((int)subnet[0])==0) Ethernet.begin(mac, ip); else Ethernet.begin(mac, ip, gateway, subnet); server = Server(port); server.begin(); PgmPrint("Free RAM: "); Serial.println(FreeRam()); } void loop() { while(1); } String getMACString(byte b[]){ String macStr, tmpStr; int length = 6; for (int i = 0; i < length; ++i){ tmpStr = String((long)b[i],HEX); if (tmpStr.length() == 1) macStr += "0"; if (i < length-1) tmpStr += ":"; macStr += tmpStr; } return macStr; } /* * Convert the vector "b" of 4 bytes (an IP address) * into a well formatted String. */ String getIPString(byte b[]){ String ipStr = ""; int length = 4; for (int i = 0; i < length; ++i) if (i < length-1) ipStr += String((long)b[i]) + "."; else ipStr += String((long)b[i]); return ipStr; } /* * Ritorna la conversione decimale del codice * esadecimale contenuto in str. * Nel caso in cui str non e' un codice esadecimale ritorna -1. * * TODO: verifica se e' possibile rappresentare * il codice esadecimale str con un int. */ int hexString2dec(String str){ int strLen = str.length(), //numero di caratteri esadecimali tmpNumber; //intero temporaneo per l'i-esimo carattere double result = 0; //risultato complessivo della conversione char tmpChar; //carattere temporaneo per l'i-esimo elemento di str str = str.toUpperCase(); //converte i caratteri in maiuscoli per il codice ascii for (int i = 0; i < strLen; ++i){ //ciclo sui caratteri di str tmpChar = str.charAt(i); //conversione dell'i-esimo carattere o numero di str in intero if (isDigit(tmpChar)) //numero tmpNumber = atoi(&tmpChar); else if (isHexadecimalDigit(tmpChar)) //carattere tmpNumber = tmpChar - ASCII_HEX_START_CHAR + 10; else return -1; //se il carattere non e' riconosciuto come esadecimale ritorna -1 result += pow(16, strLen - i - 1) * tmpNumber; //aggiornamento risultato } //per la conversione in int del risultato senza perdita di precisione if ((result*10-((int)result*10)) >= 5) return result+1; else return result; } /* * Ritorna un vettore di 6 byte ottenuto dalla stringa str * rappresentante un mac address. * Ritorna null nel caso in cui str non rappresenta un mac address. */ byte *strMac2byteVect(String str){ byte *macVect = (byte *) malloc(6); str = str.replace(':', ""); //elimina i separatori for (int i = 0; i < 12; i += 2){ //Ciclo sulle coppie di caratteri macVect[i/2] = hexString2dec(str.substring(i, i+2)); //Inizializza l'i-esimo byte del mac if (macVect[i/2] == -1){ free(macVect); return NULL; } } return macVect; } /* * Ritorna un vettore di 4 byte ottenuto dalla stringa str * rappresentante un indirizzo ip. * Ritorna null nel caso in cui str non rappresenta un indirizzo ip. */ byte *strIp2byteVect(String str){ String tmpStr; int bytesCount, //contatore per il num di byte i; //contatore per il ciclo sulla stringa byte *ipVect = (byte *) malloc(4); i = 0; for (bytesCount = 0; bytesCount < 4; bytesCount++){ //Ciclo sui byte for ( ; (str.charAt(i) != '.') && (str.charAt(i) != '