Arduino Due: reperire data via Ethernet

Salve, vi scrivo per chiedervi come reperire la data corrente (giorno-mese-anno) via Ethernet attraverso un Ethernet Shield. Per quanto riguarda l’orario non sembra esserci problema ma non riesco proprio a fargli calcolare la data. Di seguito una bozza del codice che ho trovato e modificato, nel caso dovesse essere utile. Come Shield Ethernet uso questo: http://www.seeedstudio.com/wiki/Ethernet_Shield_V1.0

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

// configura il mac address
byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char isodate[25];
const  long timeZoneOffset = -7200L;
time_t cur_time = 0;
unsigned int localPort = 8888;      // porta in listening per i pacchetti UDP
//IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server
//IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
 IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server

const int NTP_PACKET_SIZE= 48; // prende i primi 48 bytes del pacchetto

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer per fermare i pacchetti in entrata e uscita 

// Istanza UDP per mandare e ricevere pacchetti sul protocollo UDP
EthernetUDP Udp;

void setup() 
{
  Serial.begin(9600);
   while (!Serial) {
    ; 
  }


  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    for(;;)
      ;
  }
  Udp.begin(localPort);
}

void loop()
{
  sendNTPpacket(timeServer); // manda il pacchetto NTP al time server
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // Se ha ricevuto un pacchetto leggilo
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // leggi il pacchetto presente nel buffer
    // il timestamp parte al byte 40 del pacchetto ricevuto ed è lungo 4 bytes o 2 word. Quindi estrai le due word:
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    // unisci i 4 bytes in un long integer
    // NTP time (Secondi trascorsi dal 1 Gennaio 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  
    Serial.print("Secondi trascorsi dal 1 Gennaio 1900 = " );
    Serial.println(secsSince1900);               

    // converti l'NTP time
    Serial.print("Unix time = ");
    // L'Unix time parte dal 1 Gennaio 1970. In secondi sono: 2208988800:
    const unsigned long seventyYears = 2208988800UL;     
    // sottrai settanta anni:
    unsigned long epoch = secsSince1900 - seventyYears;  
    //Serial.println(epoch); 
    //Serial.println(CurrentYear);    

//prova giorno settimana
    long day = epoch / 86400L;
    Serial.println(day);
    
    int day_of_the_week = day % 7;
    switch (day_of_the_week) {
    case 0:
    Serial.println("Gio");
    break;
    case 1:
    Serial.println("Ven");
    break;
    case 2:
    Serial.println("Sab");
    break;
    case 3:
    Serial.println("Dom");
    break;
    case 4:
    Serial.println("Lun");
    break;
    case 5:
    Serial.println("Mar");
    break;
    case 6:
    Serial.println("Mer");
    break;
    }
    
    //Serial.println(cur_time);
    //Serial.println(now());
    //Serial.println(day_of_the_week);
    //cur_time = now();
   // makeISOdate();
    //Serial.println(isodate);
    //digitalClockDisplay();
    time_t t = now(); // store the current time in time variable t 
  hour(t);          // returns the hour for the given time t
  minute(t);        // returns the minute for the given time t
  second(t);        // returns the second for the given time t 
  //day(t);           // the day for the given time t 
  weekday(t);       // day of the week for the given time t  
  month(t);         // the month for the given time t 
  year(t);          // the year for the given time t 
   // Serial.println(month());
    
    
    // Stampa ora, minuti e secondi
    Serial.print("Sono le ore ");       // UTC time: Meridiano di Greenwich
    Serial.print(((epoch  % 86400L) / 3600)+2); // stampa l'ora (86400 secondi al giorno)
    Serial.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // Nei primi 10 minuti di ciascuna ora abbiamo uno zero davanti
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // stampa i minuti (3600 secondi al minuto)
    Serial.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // Nei primi 10 secondi di ciascun minuto abbiamo uno zero davanti
      Serial.print('0');
    }
    Serial.println(epoch %60); // stampa i secondi
  }
  // attendi 10 secondi prima di chiedere ancora l'orario
  delay(10000); 
}
 
 
/* 
void digitalClockDisplay(){
  // Ask only once for date and time:
  time_t t = cur_time;
  // digital clock display of the time
  Serial.print(hour(t));
 // printDigits(minute(t));
  //printDigits(second(t));
  Serial.print(" ");
  Serial.print(day(t));
  Serial.print(" ");
  Serial.print(month(t));
  Serial.print(" ");
  Serial.print(year(t)); 
  Serial.println(); 
} */

 
void makeISOdate(){
  sprintf(isodate, "%4d-%02d-%02dT%02d:%02d:%02d%+05d\n",
      year(), month(), day(), hour(), minute(), second(), timeZoneOffset/36 );
}  


// manda una richiesta NTP al server
unsigned long sendNTPpacket(IPAddress& address)
{
  // mette tutti i bytes nel buffer a 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // inizializza i valori nell'NTP request
  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
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
        
  Udp.beginPacket(address, 123); // le richieste NTP vengono fatte sulla porta 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

Puoi estrapolare la funzione dalla libreria swRTC di Leonardo --> swRTC - Megatopic - Arduino Forum
La funzione è setClockWithTimestamp e permette di ottenere dal Timestamp data e ora.

EDIT:
La funzione se non ero è anche disponibile nella libreria time. Controllala.

Provo anche io a darti una mano :slight_smile:
se hai una connessione ad internet puoi provare in questo modo:

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

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "http://www.timeapi.org/utc/now";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192,168,0,177);

// Initialize the Ethernet client library
// with the IP address and port of the server 
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /utc/now HTTP/1.1");
    client.println("Host: www.timeapi.org");
    client.println("Connection: close");
    client.println();
  } 
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

Utilizzando un webservice, una volta ricevuta la stringa puoi effettuare il parser del time come meglio credi! ciaooo

Grazie innanzitutto per la risposta. Ho provato ad eseguire uno sketch di test fornito nella stessa cartella della libreria:

/* This file is part of swRTC library.
   Please check the README file and the notes
   inside the swRTC.h file to get more info
   
   This example will print the time every second
   to the computer through the serial port using the 
   format HH:MM or HH:MM:SS
   
   Written by Leonardo Miliani <leonardo AT leonardomiliani DOT com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
    version 3.0 of the License, or (at your option) any later version.
*/

#include <swRTC.h>
swRTC rtc; //create a new istance of the lib
const byte WITHOUT_SECONDS = 0;
const byte WITH_SECONDS = 1;

void setup() {
	rtc.stopRTC(); //stop the RTC
	rtc.setTime(12,0,0); //set the time here
	rtc.setDate(4,6,2012); //set the date here
	rtc.startRTC(); //start the RTC
	Serial.begin(19200); //choose the serial speed here
	delay(2000); //delay to let the user opens the serial monitor
}

void loop() {
    printTime(WITHOUT_SECONDS);
    printTime(WITH_SECONDS);
    Serial.println("");
    delay(1000);
}


void printTime(byte withSeconds) {
    sendNumber(rtc.getHours());
    Serial.print(":");
    sendNumber(rtc.getMinutes());
    if (withSeconds) {
        Serial.print(":");
        sendNumber(rtc.getSeconds());
    }
    Serial.println("");
}


void sendNumber(byte number) {
    byte temp;
    if (number>9) {
        temp=int(number/10);
        Serial.print(char(temp+48));
        number-=(temp*10);
    } else {
        Serial.print("0");
    }
    Serial.print(char(number+48));
}

e ottengo il seguente errore:
In file included from swRTCprintTime.ino:17:
C:\Documents and Settings\01stg_eta\Documenti\Arduino\libraries\swRTC/swRTC.h:39: fatal error: avr/interrupt.h: No such file or directory
compilation terminated.

Eppure il file interrupt.h è nella cartella: C:\Documents and Settings\01stg_eta\Desktop\Arduino Due\arduino-1.5.2\hardware\tools\avr\avr\include\avr

Cosa c’è di errato?

Vuol dire che quel codice non è compatibile con la DUE.
Devi eliminare tutto il superfluo e utilizzare unicamente la funzione che ti calcola data e ora partendo dal timestamp.

Perchè parlate della DUE?
C:\Documents and Settings\01stg_eta\Documenti\Arduino\libraries\swRTC/swRTC.h:39: fatal error: avr/interrupt.h: No such file or directory
compilation terminated.

sta cercando nella cartella /avr non /sam
Hai la versione aggiornata della swrtc?

Perchè il titolo del topic è "Arduino DUE:....." :roll_eyes:

Azz ... sai che non l'avevo proprio visto :smiley: .. ciai ragione mia!!!

da nuovo forum user secondo me è per il problema dell'incopatibilità... :zipper_mouth_face:
Hydrarian ad ogni modo hai provato il codice che ho postato? con quello non "dovresti" avare problemi.. ]:slight_smile:

Ciao Antroid, grazie per la dritta, non ci avevo pensato! Comunque ho appena eseguito il codice aggiungendo anche un

    char c = client.read();
    Serial.print(c);

per la stampa sul Serial Monitor. A parte che durante la compilazione mi da:

C:\DOCUME~1\01STG_~1\IMPOST~1\Temp\build1799273433428212384.tmp/core.a(main.cpp.o): In function main': C:\Documents and Settings\01stg_eta\Desktop\Arduino Due\arduino-1.5.2\hardware\arduino\sam\cores\arduino/main.cpp:50: warning: undefined reference to loop'

Poi quando vado a stampare su serial monitor ottengo:

connecting...
connected
ÿ

Quell'ÿ dovrebbe essere la stringa ottenuta dal server... Come renderla leggibile?

EDIT: Ho sistemato i due warning (erano dovuti all'assenza di loop())

La swRTC è stata scritta e funziona solo per gli Avr8.
Se ti servono le funzioni del timestamp puoi estrapolarle ma NON puoi includere l’intera libreria perché durante l’inizializzazione fa il setup di alcuni registri del micro che ovviamente sulla DUE non esistono.

Per la Due ho scritto una libreria apposita che si chiama adavancedFunctions che permette di accedere a delle periferiche non supportate dal core di Arduino, ad esempio l’RTC integrato. Esso è molto preciso, avendo un quarzo da 32 kHz apposito. Puoi benissimo prelevare questa libreria che ti ho detto ed aggiungerci le funzioni di timestamp. Anzi, prima o poi lo faccio anch’io che servono sempre :wink: