data logger+ webserver

Ciao a tutti e grazie in anticipo a chiunque saprà aiutarmi...sono davvero alla frutta!

Ho a disposizione arduino uno+ethernet shield con sd+rtc(non ancora collegata).
Quello che vorrei realizzare è un dispositivo in grado di registrare su un file di log giornaliero (quindi ogni giorno crearne uno diverso) lo stato di un ingresso e che al tempo stesso implementi un web server in grado di rendere "navigabili" i vari file di log creati giorno per giorno tramite browser

Sono riuscito agevolmente a fare le due cose separatamente grazie ai diversi esempi in rete e sul forum...ma non c'è verso di farle funzionare contemporaneamente...

praticamente funziona perfettamente il web server e la rilevazione dello stato dell'ingresso...ma non appena aggiungo la scrittura su file dello stato di ingresso quando rilevo una variazione si inchioda tutto, il server smette di funzionare e la board si riavvia!!!

è come se le due cose andassero in conflitto!!
devo in qualche modo "arrestare" il server quando scrivo su sd e viceversa?come?
qualcuno saprebbe aiutarmi???

codice

BTW sia la SD che la ethernet usano il protocollo SPI. devi fare attenzione, quindi, ad abilitare il pin SS della ethernet o della SD in base a chi vuoi "parlare"

ogni volta che uso sd o ethernet devo abilitare/disabilitare il relativo pin??? la libreria non lo fa di suo???

al massimo mi è capitato di trovare esempi in cui dice di settare il 10 come output alto anche dopo l'inizializzazione "Ethernet.begin" per disabilitare l'SPI.

#include <SdFat.h>
#include <SdFatUtil.h>
#include <Ethernet.h>
#include <SPI.h>


const int chipSelect = 4;// pin di inzializzazione sd NON MODIFICARE MAI
const int InputPin = 2;    // ingresso da rilevare
const int RefreshTime = 300;  //periodo di scansione ingresso [ms]


int StatoAttuale = 0;
int StatoPrecedente = 0;

//SD

Sd2Card card;
SdFat sd;
SdFile myFile;

SdVolume volume;
SdFile root;

//ETHERNET

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 0, 80 };
EthernetServer server(80);


// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

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);
}



void ListFiles(EthernetClient client, uint8_t flags) {
  // This code is just copied from SdFile.cpp in the SDFat library
  // and tweaked to print to the client output in html!
  dir_t p;
  
  root.rewind();
  client.println("<ul>");
  while (root.readDir(&p) > 0) {
    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) break;

    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

    // print any indent spaces
    client.print("<li><a href=\"");
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print((char)p.name[i]);
    }
    client.print("\">");
    
    // print file name with possible blank fill
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print((char)p.name[i]);
    }
    
    client.print("</a>");
    
    if (DIR_IS_SUBDIR(&p)) {
      client.print('/');
    }

    // print modify date/time if requested
    if (flags & LS_DATE) {
       root.printFatDate(p.lastWriteDate);
       client.print(' ');
       root.printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    client.println("</li>");
  }
  client.println("</ul>");
}


void write_log(char* NomeFile, String Messaggio, String Data){
  
  //apertura del file
  if (!myFile.open(NomeFile, O_RDWR | O_CREAT | O_AT_END)) {
    sd.errorHalt("apertura file di log fallita");
  }
  
  Serial.print("Scrivendo sul file di log..");
  //scrittura sul file
  myFile.println(Messaggio+";"+Data);
  Serial.println(Messaggio+";"+Data);
  
  //chiusura del file
  myFile.close();
  
}

boolean CheckCambiamento(int NumeroPin){
  
  int i=0;
  
  StatoAttuale = digitalRead(NumeroPin);

  if (StatoAttuale != StatoPrecedente) {
   
    if (StatoAttuale == HIGH) {
      Serial.println("Rilevato cambiamento di stato:->ALTO");
    } 
    else {
      Serial.println("Rilevato cambiamento di stato:->BASSO"); 
    }
    
    StatoPrecedente=StatoAttuale;    
    return true;
  }
  
  StatoPrecedente=StatoAttuale;
  return false;
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void webserver()
{
  char clientline[BUFSIZ];
  int index = 0;
  
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    
    // reset the input buffer
    index = 0;
    
    while (client.connected()) {
      
       
      if (client.available()) {
        char c = client.read();
        
        // If it isn't a new line, add the character to the buffer
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ) 
            index = BUFSIZ -1;
          
          // continue to read more data!
          continue;
        }
        
        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;
        
        // Print it out for debugging
        Serial.println("Clientline:");
        Serial.println(clientline);
        Serial.println("--------------------------");
        
        // Look for substring such as a request to get the root file
        if (strstr(clientline, "GET / ") != 0) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          
          // print all the files, use a helper to keep it clean
          client.println("<h2>Files:</h2>");
          ListFiles(client, LS_SIZE);
        } else if (strstr(clientline, "GET /") != 0) {
          // this time no space after the /, so a sub-file!
          char *filename;
          
          filename = clientline + 5; // look after the "GET /" (5 chars)
          // a little trick, look for the " HTTP/1.1" string and 
          // turn the first character of the substring into a 0 to clear it out.
          (strstr(clientline, " HTTP"))[0] = 0;
          
          // print the file we want
          Serial.println("Nome del file che cerco di aprire:");
          Serial.println(filename);
          

         if (!myFile.open(&root, filename, O_READ)) {
            Serial.println("ho fallito");
            client.println("HTTP/1.1 404 Not Found");
            client.println("Content-Type: text/html");
            client.println();
            client.println("<h2>File non trovato 3</h2>");
            break;
          }
          
          Serial.println("Opened!");
                    
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/plain");
          client.println();
          
          int16_t c;
          while ((c = myFile.read()) > 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              client.print((char)c);
          }
          myFile.close();
          
        } else {
          // everything else is a 404
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File non trovato 4!</h2>");
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }

}




void setup() {


  delay(300);
  pinMode(InputPin, INPUT);
  Serial.begin(9600);
  Serial.println("Procedure di inizializzazione...");
  
  PgmPrint("RAM libera: ");
  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, chipSelect)) error("inizializzazione della sd fallita!");
  
  if (!volume.init(&card)) error("inizializzazione del volume fallita!");
  
  if (!root.openRoot(&volume)) error("apertura root sd fallita");

  // list file in root with date and size
  root.ls(LS_DATE | LS_SIZE);
  
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
  
  //apro un file di prova solo per testare che funziona l'sd
  if (!myFile.open("Test4.txt", O_RDWR | O_CREAT | O_AT_END)) {
        //Serial.println(i);
        sd.errorHalt("Apertura del file in scrittura fallito");//concatenare nome file
    
      }
  myFile.close();
  
  // Debugging complete, we start the server!
   Ethernet.begin(mac, ip);
   server.begin();
   
   digitalWrite(10, HIGH);    
}

void loop() {
   
  delay(RefreshTime);
  Serial.println("Controllando lo stato dell'ingresso...");
  if (CheckCambiamento(InputPin)) {
       if(StatoAttuale==HIGH){
         write_log("23062013.txt","RILEVATA VARIAZIONE->ACCESO"," data di prova");  
         Serial.println("ALTO_Scrittura su file eseguita");          
       }
       else {
         write_log("23062013.txt","RILEVATA VARIAZIONE->SPENTO"," data di prova");  
         Serial.println("BASSO_Scrittura su file eseguita");
       }
  } 
  else {
    Serial.println("Nessuna variazione rilevata");
    webserver();
  }

 
 //Serial.println("Server Eseguito");
  
}

no, credo che sia tu a dover scegliere quando usare uno o l'altro.. non ci ho mai giocato, ma è un problema ricorrente.

ci ho provato ma evidentemente mi sfugge come...nessuno ha mai provato a fare nulla di simile?

Usa il menu Search in alto (non il campo scrivibile con bottone search).
Cerca datalog. E seleziona solo le voci della sezione "italiano"

Ad esempio trovi questi:
http://forum.arduino.cc/index.php?topic=92275.15
http://forum.arduino.cc/index.php?topic=107093.0

Tieni conto che le librerie ethernet e sd sono grossine e se hai fatto un web server di sicuro scrivi molte frasi per comporre le pagine html.
Arduino Uno ha solo 2K di ram. Potrebbe essere che esaurisci la memoria e lui si resetta.
Prova ad usare la libreria "freeram" e vedere quanta memoria occupi.
Per diminuire l'occupazione in ram delle frasi, leggi questo a proposito dell'uso di F(): Aiuto...pagina html in 3G perdo dei pezzi - Software - Arduino Forum
Leggi anche questo tutorial, puo essere una idea: http://www.mauroalfieri.it/elettronica/tutorial-arduino-ethernet-sdcard.html

ciao e grazie per l'aiuto...
con freeram ho già provato a vedere qualcosa e ci dovrei stare dentro a ram.
tuttavia non credo di aver capito...già di suo il web server (quello da tutorial che visualizza il contenuto di un file di testo per intenderci) accede alla sd in lettura quando necessario per fornire al client il contenuto dei files e come immaginavo la libreria gestisce lo "swap" di sd ed ethernet ...che differenza c'è se di tanto in tanto su questi file ci scrivo?
avevo già trovato diversi esempi e in tutti sembra non esserci nessunissimo problema...bah...è evidente che faccio qualche cappellata grossa io!
ci sbatterò su la testa ancora un po'...
grazie ancora!

Prova a ridurre le frasi, ad esempio i msg d'errore momentaneamente, metti solo un valore che tu sai interpretare.
E' un tentativo.

se leggi la SD, attiva il suo pin CS e disattiva quello della eth, e iceversa. Altrimeti la ETH ascolta i messaggi della SD e viceversa e non si paisce più niente

lesto:
se leggi la SD, attiva il suo pin CS e disattiva quello della eth, e iceversa. Altrimeti la ETH ascolta i messaggi della SD e viceversa e non si paisce più niente

ma no lesto, lo fanno già le librerie lo switch tra i 2 enable (4 e 10) più che altro controllerei i colse, perché sono quelli che chiudono i pin e quindi le comunicazioni verso l'spi, io uso attualmente ethernet e SD contemporaneamente e funziona egregiamente, sono sicuro di quello che dico

Colse?sarebbero?

Close. :wink:
Il contrario di Open.

Ah ok close...si in effetti ci potevo arrivare ahahah :grin:
Ti riferisci alla chiusura dei file sulla sd alla fine delle operazioni di lettura/scrittura?o c'è qualcosa di analogo da fare anche per la ethernet?

Premetto che no uso la sdfat ne la sdutil, mi sembra molto complicato quello sketch per fare quello che chiedi, ma lo hai messo insieme tu o lo hai preso da qualche parte?

ho combinato questo tutorial Arduino Tutorials - Ethernet+SD
con la mia esigenza di scrivere su file di testo lo stato di un ingresso.

Piuttosto...se hai un'idea più semplice ed efficace spara!...mi farebbe davvero comodo anche perchè a quanto pare nessuno sa di preciso dove possa stare il problema...

Prova a usare questo http://arduino.cc/en/Tutorial/Datalogger e sostituisci il pezzo che legge le analogiche con il pin digitale che vuoi controllare
Chiaramente devi poi aggiungere #include <Ethernet.h> per la parte server

PS: quel tutorial ha 2 bachi:

  1. manca #include <SPI.h>
  2. non vengono settati nel setup() i pin 4 e 10 come OUT e impostati in HIGH

menomale che
created 24 Nov 2010
modified 9 Apr 2012
by Tom Igoe :smiley:

ciao

Grazie per l'aiuto...in ogni caso scrivere sulla sd o eseguire la parte server in due sketch separati non è mai stato un problema come dicevo all'inizio....il guaio era combinarli!
In ogni caso ho risolto per tentativi...appena capisco bene dove stava l'inghippo pubblico!