NTP ed SD Card: comportamento anomalo

Ciao a tutti.
Sto imparando ad usare Arduino tramite qualche libro e tanti tutorial che trovo su internet, di tanto in tanto leggo il forum e ho chiesto supporto in passato, ma tanto tempo fa.

Nello sperimentare sto provando a realizzare una sorta di datalogger per temperatura e pressione ambiente, nulla di nuovo, ci sono parecchi tutorial. Le caratteristiche di quello che ho in mente però differiscono da ciò che ho trovato in rete, in particolare:

  • vorrei salvare i dati su una SD card;
  • i valori di temperatura e pressione li vorrei associarli ad una data e ora, sincronizzata di tanto in tanto con un server NTP;
  • uso rete cablata e IP fisso.
    Finora non ho avuto problemi, o meglio li ho avuti ma sono riuscito a risolverli da solo, nel configurare la sincronizzazione dell'ora con un server NTP (il controllo viene fatto ogni ora, ma posso anche farlo solo 2 o 3 volte al giorno), nell'impostare l'IP fisso, configurare un mini server web, leggere e scrivere sulla SD.
    Il problema sopraggiunge se cerco di usare tutte queste funzioni insieme.
    Sono arrivato ad un punto in cui, scelgo l'intervallo di aggiornamento al server NTP, ora impostato una volta all'ora, per fare delle prove, prima di salvare i dati di T e P sulla SD sto cercando di salvare il numero di volte che effettivamente Arduino manda e riceve dal server NTP un segnale e sincronizza l'ora. Vorrei salvare questo dato sulla scheda SD (lo faccio per prendere un po' dimistichezza con tutto questo insieme di funzioni).
    Nel fare questo Arduino si comporta in modo strano. Nell'upload del programma mi viene visualizzato un messaggio che mi avvisa di usare troppa memoria e che il comportamento potrebbe essere instabile, questo è un segnale ovviamente.
    Ad ogni modo, il comporamento è il seguente:
    *viene ripetuto ad intervalli regolari il setup (non il loop);
    *sulla seriale stampo alcuni valori per verificare che sia tutto ok, in particolare quando carica il setup stampo l'IP, subnet ... visto che il setup (come scritto al punto precedente) viene ripetuto più volte, vedo dei valori di rete (IP, subnet, gateway ...) completamente diversi;
    *ovviamente ho problemi nella lettura e scrittura della SD.
    Riporto di seguito un po' di codice:

#include <TimeLib.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <SD.h>
#define PINSD 4         //definisce il pin a cui è collegata l'SD
File Fcont;         //file usato per salvare il numero di cicli di aggiornamento
int mem=0;              //indirizzo di memoria della EEPROM nel quale
                        //vado a scrivere il numero di aggiornamento ora
int nC=0;               //contatore numero di aggiornamenti
unsigned long t0=0;     // tempo trascorso dall'accensione della scheda
unsigned long t1=1;     // tempo di riferimento
//unsigned long periodo=3600000; //intervallo di aggiornamento ora (1 volta ogni ora)
unsigned long periodo=30000;     // valore di 30 secondi, usato solo nelle prove
int D=10000;              // delay del loop in millisecondi
long n;                       //numero di frazionamenti del delay necessari per ottenere D
int ore;                      //numero di ore per l'aggiornamento
byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x51, 0xE8 }; 
unsigned int localPort = 8888;
char timeServer[] = "ntp2.inrim.it"; // time.nist.gov NTP server ntp2.inrim.it 
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; // A UDP instance to let us send and receive packets over UDP
const int timeZone = 2;     // Central European Time
IPAddress ip(172,16,0,130);
IPAddress gateway(172,16,0,254);
IPAddress dnServer(172,16,0,15);
IPAddress subnet(255,255,255,0);
EthernetServer server(80);

void setup() {
   Serial.begin(9600);
   Serial.println("========== INIZIO SETUP ==========");
       
   n=periodo/D;
   Serial.print("Numero di periodi: ");
   Serial.println(n);
   ore=6;
   Serial.println("Esempio ora internet");
   Ethernet.begin(mac, ip, dnServer, gateway, subnet );
   server.begin();
   delay(1000);
   
   Serial.print("IP statico: ");
   Serial.println(Ethernet.localIP());
   Serial.print("Gateway: ");
   Serial.println(Ethernet.gatewayIP());
   Serial.print("DNS: ");
   Serial.println(Ethernet.dnsServerIP());
   Serial.print("Subnet: ");
   Serial.println(Ethernet.subnetMask());
   Udp.begin(localPort);
   Serial.println("Attesa sincronizzazione");
   setSyncProvider(getNtpTime);
   nC=nC+1;
   
    
   Serial.print("Ora aggiornata");
   digitalClockDisplay();
   Serial.print("Nome file: ");
   Serial.println(__FILE__);
   if (!SD.begin(PINSD)){
    Serial.println("ERRORE SD CARD O CARD NON PRESENTE");
    while(1);
   }
   Serial.println("SD INIZIALIZZATA CORRETTAMENTE");
   Fcont=SD.open("conta.txt", FILE_WRITE); //crea il file conta, dove salvare il contatore
   if (Fcont) {
    Fcont.println("Contatore: ");
    Fcont.println(nC);           //Salvo sul file della SD il numero di aggiornamenti ora
    Fcont.close();
   } else {
    Serial.println("SD card: errore apertura file conta.txt");
    }
   Serial.println("========== FINE SETUP ==========");
   delay(1000);
}

time_t prevDisplay = 0; // when the digital clock was displayed

void loop() {
  t1=millis();
  Serial.println("========== INIZIO LOOP ==========");
  Serial.print("t1: ");
  Serial.println(t1);
  Serial.print("t0: ");
  Serial.println(t0);
  Serial.print("t1-t0: ");
  Serial.println(t1-t0);
  Serial.print("Periodo agg.: ");
  Serial.println(periodo);
  if ((t1-t0)>= periodo){
    Serial.println("Devo aggiornare");
    sendNTPpacket(timeServer); // send an NTP packet to a time server
    nC=nC+1;
    
/*    if (Fcont) {
    Fcont.println("Contatore: ");
    Fcont.println(nC);           //Salvo sul file della SD il numero di aggiornamenti ora
    Fcont.close();
   } else {
    Serial.print(F("SD card: errore apertura file conta.txt"));
    }
 */   
    
    t0=t1;
    Serial.print("Conteggio aggiornamento: ");
    if (timeStatus() != timeNotSet) {
       if (now() != prevDisplay) { //update the display only if time has changed
       prevDisplay = now();
       Serial.print("Ora aggiornata: ");
       digitalClockDisplay();  
     }
   }
  } else{
    Serial.print("Non devo  aggiornare, conteggio aggiornamento: ");
    //Serial.println(EEPROM.get(mem,nC));
    Serial.print("Mancano ancora: ");
    Serial.print(periodo/(t1-t0));
    Serial.print(" cicli, pari a: ");
    Serial.print((periodo-(t1))/1000);
    Serial.println(" secondi.");
    Serial.print("Ora: ");
    digitalClockDisplay(); 
  }
  
      //sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000); 
  Serial.println("Programma: ora_internet");
/*  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      digitalClockDisplay();  
    }
  } */
    Serial.print("Delay: ");
    Serial.println(D);
    delay(D);
    Serial.println("========== FINE LOOP ==========");
}

//===============================================================================
void digitalClockDisplay(){
  // digital clock display of the time
  //Serial.print(hour());
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility for digital clock display: prints preceding colon and leading 0
  //Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*-------- NTP code ----------*/

//const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
//byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets


time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

//void sendNTPpacket(IPAddress & address)
//void sendNTPpacket(const char * address)
void sendNTPpacket(char * 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();
}

Per questi test uso Arduino UNO Rev. 3 ed Ethernet shield
Grazie in anticipo.

Al 95% è un problema di memoria ... Arduino UNO non ha memoria sufficiente per tutto quello che vuoi fare, devi passare alle nuove schede basate almeno su ATSAMD21 o, meglio ancora usare delle schede con ESP32.

Guglielmo

Ciao Guglielmo.
Grazie 1000 per la risposta.
Non conosco schede basate su queste 2 tecnologie, ho già le mie belle difficoltà con Arduino!

Provando a disabilitare la libreria SD l'uso della memoria è passata dal 91% al 41%, quindi penso che il problema sia proprio quello, infatti, per quanto io sia incapace, credo che il programmino che avevo scritto non fosse sbagliato, sicuramente migliorabile ma dovrebbe funzionare.

Secondo te Arduino 2 potrebbe farcela?
Grazie in anticipo.

Lascia stare Arduino DUE ... scheda vecchia ed obsoleta.

Come ti ho detto, o ti orienti sulla serie MKR di Arduino o sugli ESP32 (solo WiFi) ... ma se ti serve necessariamente un collegamento Ethernet, allora, con la serie MKR, hai sia la MCU con la SD che lo shield Ethernet :wink:

Guglielmo

Scusa intendevo Arduino mega, non la due.

Sempre una MCU AVR a 16 MHz è ...
... ti stavo consigliando qualche cosa di più performate e recente :roll_eyes:

Guglielmo

Esempio:

Guglielmo

Ho in casa una Mkr wifi e una env shield che ha anche la lettura della SD, dici che ci posso provare?

Quindi invece che via cavo vai via WiFi ? ... se per te va bene, hai tutto.

Ricorda solo che la serie MKR lavora a 3.3V.

Guglielmo

Si, il mio "vincolo" è solo l'IP statico.
Grazie per avermi ricordato del 3.3V non ci pensavo minimamente.
Ci sentiremo presto allora, migro su quella scheda e faccio un po' di prove, grazie 1000 intanto.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.