Caricare parametri da SD

Ciao a tutti.

Ho creato (copiando codice qua e là e adattandolo alle mie esigenze) un semplice sketch che ad una certa ora inizia un ciclo di funzionamento di 8 relè e ad una ora successiva lo disattiva (mi serve per comandare delle elettrovalvole per irrigazione). L'ora, per adesso, è presa tramite server NTP (ma in futuro passerò ad un RTC per evitare di dover usare lo shield ethernet).

Il codice, postato qui di seguito, funziona.

Ora vorrei semplificarne un pochino il funzionamento facendogli caricare i parametri di funzionamento (le parti indicate come // Config DURATA e // Config PARTENZA e FINE all'interno del codice) da una scheda SD, scrivendole in un file txt di configurazione apposito, in modo poi da poter installare il device nel suo posto definitivo e dovendo semplicemente inserire la SD e resettare per cambiare il programma di irrigazione.

Per le prove userei il lettore sd presente sullo shield ethernet.

Qualche idea o suggerimento su come fare? (link, guide, librerie)
Commenti o idee per il codice?

Grazie in anticipo per tutto l'aiuto.

// Prova comando elettrovalvole con ora presa da NTP

#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <TimeAlarms.h>

//CONFIG RELAY BOARD
#define RELAY_ON 0
#define RELAY_OFF 1
#define Relay_1  3 // Stazione 1
#define Relay_2  4 // Stazione 2
#define Relay_3  5 // Stazione 3
#define Relay_4  6 // Stazione 4
#define Relay_5  8 // Stazione 5
#define Relay_6  2 // Stazione 6
#define Relay_7  7 // Stazione 7
#define Relay_M  9 // VALVOLA MASTER


// Configurazione di rete e NTP
byte mac[] = { 0x90, 0xA2, 0xDA, 0x06, 0x00, 0x5A }; //Mac Adress Arduino
unsigned int localPort = 8888;      // Porta UDP
IPAddress timeServer(199,167,198,163); // pool.ntp.org NTP server
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 
EthernetUDP Udp;
int timeZoneHour = +2; // Timezone (+1 inverno - +2 Estate)
long timeZoneOffset = (timeZoneHour * -1) * 60 * 60 ;
int NTP_Update_Interval = 86400; // Intervallo update NTP in secondi (86400 = una volta al giorno)

// Config DURATA
int var;
int attive; // Numero Stazioni attive (per il calcolo della pausa)
int durata1 = 10; //in secondi
int durata2 = 0; //in secondi
int durata3 = 0; //in secondi
int durata4 = 0; //in secondi
int durata5 = 10; //in secondi
int durata6 = 10; //in secondi
int durata7 = 0; //in secondi
long intervallo = 60; //in secondi

// Config PARTENZA e FINE
int orapartenza = 8;
int minutopartenza = 00;
int orafine = 18;
int minutofine = 00; //Dare tempo di fare un ulteriore giro se necessario

// Void Setup - Esecuzione solo all'avvio
void setup() 
{
  digitalWrite(Relay_1, RELAY_OFF);
  digitalWrite(Relay_2, RELAY_OFF);
  digitalWrite(Relay_3, RELAY_OFF);
  digitalWrite(Relay_4, RELAY_OFF);
  digitalWrite(Relay_5, RELAY_OFF);
  digitalWrite(Relay_6, RELAY_OFF);
  digitalWrite(Relay_7, RELAY_OFF);
  digitalWrite(Relay_M, RELAY_OFF);
  Serial.begin(9600);
  Serial.println("Starting");
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;);
  }
  Udp.begin(localPort);
  Serial.print("Got IP:");
  Serial.println(Ethernet.localIP());
  setSyncProvider(getNTPTime);
  Serial.println("Looking for a time");
  while(timeStatus()== timeNotSet);
  Serial.println("Got a Time");
  setSyncInterval(NTP_Update_Interval);
  // SVEGLIE  
  Alarm.alarmRepeat(orapartenza,minutopartenza,0, MorningAlarm);  // Partenza
  Alarm.alarmRepeat(orafine,minutofine,0,EveningAlarm);  // Fine
  //LED
  pinMode(Relay_1, OUTPUT);   
  pinMode(Relay_2, OUTPUT);  
  pinMode(Relay_3, OUTPUT);
  pinMode(Relay_4, OUTPUT);
  pinMode(Relay_5, OUTPUT);   
  pinMode(Relay_6, OUTPUT);  
  pinMode(Relay_7, OUTPUT);
  pinMode(Relay_M, OUTPUT);   
}


//void loop - Programma sempre in esecuzione
void loop(){
if (var == 1)
{
   Azione();
}
else
{
  stampaorario();
  Alarm.delay(1000);
}
}

// Printdigits - Mette lo 0 davanti alle cifre
void printDigits(int digits){
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

//Accende i LED
void Azione(){
  // MASTER
  if ( durata1 > 0 || durata2 > 0 || durata3 > 0 || durata4 > 0 || durata5 > 0 || durata6 > 0 || durata7 > 0 )
  {  
  Serial.print("Partenza Stazione MASTER: ");
  stampaorario();
  digitalWrite(Relay_M, RELAY_ON);
  Alarm.delay(1000);
  attive++;
  }
  // Stazione 1
  if ( durata1 > 0 ){   
  Serial.print("Partenza Stazione 1: ");
  stampaorario();
  digitalWrite(Relay_1, RELAY_ON); 
  Alarm.delay(durata1*1000);
  digitalWrite(Relay_1, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  //Stazione 2
  if ( durata2 > 0 ){ 
  Serial.print("Partenza Stazione 2: ");
  stampaorario();
  digitalWrite(Relay_2, RELAY_ON);
  Alarm.delay(durata2*1000);
  digitalWrite(Relay_2, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  //Stazione 3
  if ( durata3 > 0 ){ 
  Serial.print("Partenza Stazione 3: ");
  stampaorario();
  digitalWrite(Relay_3, RELAY_ON);
  Alarm.delay(durata3*1000);
  digitalWrite(Relay_3, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  // Stazione 4
  if ( durata4 > 0 ){ 
  Serial.print("Partenza Stazione 4: ");
  stampaorario();
  digitalWrite(Relay_4, RELAY_ON); 
  Alarm.delay(durata4*1000);
  digitalWrite(Relay_4, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  // Stazione 5
  if ( durata5 > 0 ){ 
  Serial.print("Partenza Stazione 5: ");
  stampaorario();
  digitalWrite(Relay_5, RELAY_ON); 
  Alarm.delay(durata5*1000);
  digitalWrite(Relay_5, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  // Stazione 6
  if ( durata6 > 0 ){ 
  Serial.print("Partenza Stazione 6: ");
  stampaorario();
  digitalWrite(Relay_6, RELAY_ON); 
  Alarm.delay(durata6*1000);
  digitalWrite(Relay_6, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  // Stazione 7
  if ( durata7 > 0 ){ 
  Serial.print("Partenza Stazione 7: ");
  stampaorario();
  digitalWrite(Relay_7, RELAY_ON); 
  Alarm.delay(durata7*1000);
  digitalWrite(Relay_7, RELAY_OFF);
  Alarm.delay(1000);
  attive++;
  }
  // Fine MASTER e Pausa
  if ( durata1 > 0 || durata2 > 0 || durata3 > 0 || durata4 > 0 || durata5 > 0 || durata6 > 0 || durata7 > 0 ) {
  digitalWrite(Relay_M, RELAY_OFF);
  Serial.print("Inizio Pausa: ");
  stampaorario();
  Serial.print("Durata Pausa: ");
  Serial.print(intervallo-durata1-durata2-durata3-durata4-durata5-durata6-durata7-attive);
  Serial.print(" Secondi ");
  Serial.println();  
  Alarm.delay(intervallo*1000-durata1*1000-durata2*1000-durata3*1000-durata4*1000-durata5*1000-durata6*1000-durata7*1000-1000*attive);
  attive=0;
  }
}

// Stampaorario - Stampa l'ora come voglio io
void stampaorario() {
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
  Serial.print(" ");
  printDigits(day());
  Serial.print("/");
  printDigits(month());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println();
} 

// functions to be called when an alarm triggers:
void MorningAlarm(){
  var = 1;    
}

void EveningAlarm(){
  var = 0;           
}

//Codice NTP
unsigned long getNTPTime()
{
  Serial.println("In getNTPTime");
  sendNTPpacket(timeServer);
  Alarm.delay(1000); 
  if ( Udp.parsePacket() ) {  
    Serial.println("Got Time Packet");
    Udp.read(packetBuffer,NTP_PACKET_SIZE);
 
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    unsigned long secsSince1900 = highWord << 16 | lowWord;  

    const unsigned long seventyYears = 2208988800UL + timeZoneOffset;      
    unsigned long epoch = secsSince1900 - seventyYears;  
  
    return epoch;    
  }
  Serial.println("No Time Packet Found");
  return 0;
}
// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

Se ti serve uno shield con SD e RTC ti consiglio questo --> Adafruit Data logging shield for Arduino [v1.0] : ID 243 : $24.80 : Adafruit Industries, Unique & fun DIY electronics and kits
E' da saldare.

Se Ti bastano 1kByte di dati puoi usare la EEPROM del Atmega. Cosí non devi usare la shield. La EEprom la leggi/scrivi con la libreria EEPROM.h

Ciao Uwe

Config PARTENZA e FINE all'interno del codice) da una scheda SD, scrivendole in un file txt di configurazione apposito, in modo poi da poter installare il device nel suo posto definitivo e dovendo semplicemente inserire la SD e resettare per cambiare il programma di irrigazione.

@uwefed
Come pensi possa usare la eeprom, ogni volta dovrebbe collegarci un pc e riprogrammarlo. La sua domanda è chiara, caricare da SD

ciao

Però scrivere sulla Eeprom interna comporta il dover usare un programmatore e relativo PC da portarsi dietro mentre fradetti, da quel che ho capito, pensa all'uso di una SD proprio per la praticità del sistema: basta portarsi dietro una schedina con le impostazioni e modificare così l'intervento della scheda "giardiniere".

@fradetti:
allegati all'IDE ci sono diversi esempi sull'uso della libreria SD per accedere ai file di una schedina di memoria

Se lo fai con la ethernet shield, non devi nemmeno accedere alla SD, salvi i dati direttamente nello sketch senza riavviare, le modifiche sarebbero immediatamente effettive.

per quanti giorni devi programmare le fasi... per uno, per 30, per 365 ?

è chiaro che hai la necessità di implementare il file-system con FAT per inizializzare la sd-card, aprire il file e leggere i dati.

lo vuoi fare sequenzialmente ? o prelevare tutti i dati dal file e memorizzarli sulla memoria eeprom?

@pablos:
se non ho capito male col tempo vuole non usare più la ethernet, per cui resterebbe solo la SD da usare

pablos:
@uwefed
Come pensi possa usare la eeprom, ogni volta dovrebbe collegarci un pc e riprogrammarlo. La sua domanda è chiara, caricare da SD

@pablos
Ho segnato una soluzione piú semplice. Per la programmazione puó aggiungere un LCD e 4 pulsanti.

Ciao Uwe