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.