Tenere il tempo

Ho fatto girare per mezz'ora uno sketch che logga su SD alcuni dati... e dal log risulta che ha girato per 15 minuti! Come, cioe', se il tempo misurato non fosse corretto! Si basa sulla funzione millis(), quindi suppongo che la ArduinoUno, di per sè, non sia precisissima, invatti vedo che alcuni gli affiancano un RTC.
E' possibile realizzare un cronometro affidabile senza dover spendere 25 euro? (15di RTC e 10 di spedizione...) C'e' modo di aggiungere semplicemente un quarzo ad ArduinoUno perchè tenga il tempo in modo più preciso?

Sulla Arduino UNO R1, la prima versione, c'erano ancora i fori per il vecchio quarzo ed i C del precedente modello 2009.
Si tratterebbe solo di dissaldare il risonatore e saldare i componenti nuovi.
Sulla R2 tali fori sono scomparsi.

Oppure ti compri un RTC, un quarzo da 32 kHz, uno o 2 C a seconda del chip, e usi quello.

La precisione di un risonatore come lo usa il Arduino UNO é piú scarso di un Quarzo ma sempre abbondante sotto 1% di errore.
Ho piú un sospetto che l' errore del 50% sia dato da un errore di programmazione.
Ciao Uwe

Ho piú un sospetto che l' errore del 50% sia dato da un errore di programmazione.

Quoto!
Facci vedere un po' di codice...
PS: per un RTC in contenitore DIL bastano 3€
Ciao

Ma una volta comprato il chippetto da 3 euo (non lo troverò mai, qui i GBC al massimo hanno led e resistenze =( ), che componenti gli devo attaccare intorno?!?

Cmq questo è il codice, ottenuto pastrocchiando un po' con uno sketch di esempio trovato nell'IDE:

// A simple data logger for the Arduino analog pins
// Set time with string: [hh:mm:ss dd mm yyyy]
#define LOG_INTERVAL  10 // mills between entries
#define SENSOR_COUNT     3 // number of analog pins to log
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define WAIT_TO_START    1 // Wait for serial input in setup()
#define SYNC_INTERVAL 1000 // mills between calls to sync()
uint32_t syncTime = 0;     // time of last sync()
#define TIME_SET_StrLen 15  // the maximum length of a time set string [hhmmssddmmyyyy]

#include <SdFat.h>
#include <SdFatUtil.h>
#include <Time.h>  
#include <ctype.h>
#include <SPI.h> 
#include <Ethernet.h>
// #include <WString.h> // No more needed since IDE 0019; standard operators can now be used with strings.

// PINS USED BY ETHERNET SHIELD:
// 4, 10, 11, 12, 13

String inString = String(35);
int StatusLed = 13;
int StatusLedValue=HIGH;

uint16_t data0;
uint16_t data1;
uint16_t data2;

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
boolean WaitToStart=false;
float duration;
TimeElements te; // holds the time elements for setting the time
boolean LoopActive=true;
boolean ParamError=true;
// 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);
  }
}

void setup(void) {
  Serial.begin(9600);
  Serial.println();  
  WaitToStart=false;
  digitalWrite(9,LOW);
  pinMode(9,INPUT); // Se il pin 9 è a massa, parte subito.
  if (digitalRead(9)==HIGH) {
    WaitToStart=false;
  }
  
if (WaitToStart) {
  Serial.println("Type [hh:mm:ss dd mm yy] or a random character to start");
  while (!Serial.available());
}

  processSetTime();  // Imposta orologio interno
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards. use SPI_FULL_SPEED for better performance.
  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, 4)) error("card.init failed!");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();
  
  if (!root.openRoot(&volume)) error("openRoot failed");
  // create a new file
  char name[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    name[6] = i/10 + '0';
    name[7] = i%10 + '0';
    if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
  }
  if (!file.isOpen()) error ("file.create");
  Serial.print("Logging to: ");
  Serial.println(name);

  // write header
  file.writeError = 0;
  file.print("millis");
#if ECHO_TO_SERIAL 
  Serial.print("millis");
#endif //ECHO_TO_SERIAL

#if SENSOR_COUNT > 6
#error SENSOR_COUNT too large
#endif //SENSOR_COUNT

  for (uint8_t i = 0+14; i < SENSOR_COUNT+14; i++) {
    file.print("\t sens");file.print(i, DEC);  
    pinMode(i,INPUT);
    digitalWrite(i,LOW);  
    
    
#if ECHO_TO_SERIAL
    Serial.print(",sensor");Serial.print(i, DEC);
#endif //ECHO_TO_SERIAL
  }
  file.println();  
#if ECHO_TO_SERIAL
  Serial.println();
#endif  //ECHO_TO_SERIAL

  if (file.writeError || !file.sync()) {
    error("write header failed");
  }
}

void loop(void) {  
    int ParamPos, ParamLen;
    String Param="";
  
  // clear print error
  file.writeError = 0;
if (StatusLedValue==HIGH) {
  StatusLedValue=LOW;
} else {
  StatusLedValue=HIGH;
}
digitalWrite(StatusLed, StatusLedValue);
  
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
  
  // log time
  uint32_t m = millis();
  //file.print(m);  
/*  file.print(year());
  file.print("/");
  file.print(month());
  file.print("/");
  file.print(day());
  file.print(" ");
*/
  file.print(hour());
  file.print(":");
  file.print(minute());
  file.print(":");
  file.print(second());
  file.print(".");
  file.print(m);
#if ECHO_TO_SERIAL
  //Serial.print(m);
  /*Serial.print(year());
  Serial.print("/");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print(" ");
  */
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  Serial.print(":");
  Serial.print(second());  
  Serial.print(".");
  Serial.print(m);
#endif //ECHO_TO_SERIAL
      
  // add sensor data 
//  for (uint8_t ia = 0+14; ia < SENSOR_COUNT+14; ia++) {
    data0 = analogRead(A0);
    data1 = analogRead(A1);
    data2 = analogRead(A2);
    file.print('\t');    
    file.print(data0);
    file.print('\t');    
    file.print(data1);
    file.print('\t');    
    file.print(data2);
#if ECHO_TO_SERIAL
    Serial.print(';');   
    Serial.print(data0);
    Serial.print(";");
    Serial.print(data1);
    Serial.print(";");
    Serial.print(data2);
#endif 

//ECHO_TO_SERIAL
 // }
/*  file.print(";"); 
   file.print(analogRead(pin)); 
#if ECHO_TO_SERIAL
   Serial.write(";us;");
   Serial.print(analogRead(pin));
#endif //ECHO_TO_SERIAL
*/   
  file.println();  
#if ECHO_TO_SERIAL
  Serial.println();
#endif //ECHO_TO_SERIAL

  if (file.writeError) error("write data failed");
  
  //don't sync too often - requires 2048 bytes of I/O to SD card
  if ((millis() - syncTime) <  SYNC_INTERVAL) return;
  syncTime = millis();
  if (!file.sync()) error("sync failed");
}


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


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


void processSetTime(){
  //[hh:mm:ss dd mm yyyy]
  char setString[TIME_SET_StrLen];
  int index = 0;
  char c = Serial.read();
  if( c != '[')
     return;  // first character must be opening square brackets
  do
  {
     c = Serial.read();
     if( isdigit(c))  // non numeric characters are discarded
	 setString[index++] = c -'0'; // convert from ascii    
  }
  while (c != ']'); // wait for trailing square brackets

  breakTime(now(), te);   // put the time now into the TimeElements structure  
  
  int count = index;
  int element = 0;
  for( index = 0; index < count; index += 2)  // step through each pair of digits
  {
	int val = setString[index] * 10 + setString[index+1] ; // get the numeric value of the next pair of numbers
	switch( element++){
	  case  0 :  te.Hour = val; break;
	  case  1 :  te.Minute = val; break;
	  case  2 :  te.Second = val; break;
	  case  3 :  te.Day = val; break;
	  case  4 :  te.Month= val; break;
	  case  5 :  te.Year = val + 30; break; // year 0 is 1970	  
	}    
  }
  setTime( makeTime(te));
}

Devo solo salvare 3 valori letti 10 volti al secondo, per una durata massima di un paio d'ore.

Se non richiedi una precisione stratosferica puoi evitare di comprare chip esterni.
Potresti anche pensare di usare la mia libreria swRTC (cerca nel forum): per tenere tempi va bene, se usi l'Arduino l'approssimazione che ottieni è buona e per poche ore non sbaglia di molto.

Cmq resta in essere il consiglio di Uwe, e cioè ricontrolla il software (ora io non ho tempo per farlo) perché perdere mezz'ora su un compito di 2 ore non è normale.

Ciao, puoi sempre acquistare uno di questi moduli http://www.ebay.it/itm/DS1307-RTC-for-PIC-AVR-Arduino-Real-Time-Clock-module-/250810027549?pt=LH_DefaultDomain_0&hash=item3a65714e1d , hanno già tutto ed il prezzo non è cattivo , in Cina ci trovi anche qualcosa di più economico , altrimenti nel forum qualcuno aveva fatto anche il PCB.

Ciao.

Come non detto, avevo interpretato male i miei dati: mentre Arduino loggava, anche il cellulare loggava (la posizione GPS)... ma ha iniziato diversi minuti prima e finito diversi minuti dopo, e non avevo fatto ben combaciare i due grafici ottenuti! :roll_eyes:

cosa dovrebbe fare questo?

delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));

Se vuoi controllare se l' attesa é passata é meglio scrivere

if(OLDmillis - milllis() >  LOG_INTERVAL)
{
fai un nuovo campionamento ecctera....
}

Guardati l' esempio BlinkWithoutDelay che trovi nei esempi del IDE sotto Digital.

Ciao Uwe