Nahezu gleiche zeitungenauigkeit auf zwei verschiedenen Arduinos

Hallo liebe Community,
ich hoffe ihr könnt mir bei meinem Problem helfen. Ich besitze ein Arduino Uno (rev. 3) und ein Mega (rev. 2) und bin gerade dabei eine art Uhr zu bauen. Ich bin mir auch der Optionen über DCF77 oder RTC-Module bewusst, will aber auch bewusst darauf verzichten, eine Genauigkeit um die 100ppm ist mir vollkommen ausreichend, theoretisch sollten aber bei meinem Aufbau 60ppm und weniger möglich sein, dazu später mehr.

Zu erst habe ich die Zeitgenauigkeit mit der fertig zusammengesteckten Uhr getestet und war enttäuscht, ich habe mit einem Funkwecker über einen tag hinweg die zeitabweichung gemessen und kam auf eine relativ lineare abweichung von ca. einer sekunde pro 10 minuten, was so 140 sekunden pro tag darstellt, und somit bei über 1000ppm ungenauigkeit liegt. In einem zweiten Test habe ich die Uhr noch mit der Time.h lib betrieben und kam auf die gleiche abweichung. gestern habe ich dann noch, um den quarz des UNO als fehlerquelle auszuschließen, eine langzeitmessung auf dem mega gestartet (mit zeitabgleich über ein processing-programm mit der systemuhr) und komme (nur grob berechnet auf den letzten tag) auf nahezu genau den gleichen abweichungswert. ich habe zwar noch keine daten zu dem quarz des UNO und mega gefunden, aber 1000ppm sollten sehr unüblich für quarze sein, im endbetrieb soll ein ATmega328 mit einem 30ppm quarz (+-30ppm thermische abweichung) betrieben werden, was ja mir theoretisch ausreicht. jedoch glaube ich, da beide arduinos mit der gleichen abweichung laufen, dass es ein problem in meiner software oder in der implementierung von irgendetwas gibt. habt ihr auch schon solche erfahrungen gemacht und könnt mir vielleicht tips geben?

P.S. ich denke nicht das es besondere fehler durch meine software gibt, da die referenzmessung auf dem mega im prinzip nur auf einer leicht modifizierten version des beispielprogramms für zeitabgleich über die serielle verbindung aus der Time.h lib basiert.

Und wie sieht dein Testprogramm aus? Hoffentlich nicht irgendein Stückwerk mit delay-Anweisungen... :wink: Wenn du den Code reinstellst, könnten andere auch mal ihren Arduino gegenprüfen.

delay-anweisungen werden in dem eigentlichen uhrenprogramm nicht bis selten verwendet, ich habe in einer version eine für ne millisekunde drin um das multiplexen einiger LEDs zu stabilisieren, habe es in einer anderen version anders gelöst, merke aber kein unterschied. der testcode ist folgender

/* 
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */ 
 
#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(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 processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.println(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  }
}

time_t requestSync()
{
  Serial.write(TIME_REQUEST);  
  return 0; // the time will be sent later in response to serial mesg
}

und der processing sketch:

/**
 * SyncArduinoClock. 
 *
 * portIndex must be set to the port connected to the Arduino
 * 
 * The current time is sent in response to request message from Arduino 
 * or by clicking the display window 
 *
 * The time message is 11 ASCII text characters; a header (the letter 'T')
 * followed by the ten digit system time (unix time)
 */
 

import processing.serial.*;

public static final short portIndex = 0;  // select the com port, 0 is the first port
public static final char TIME_HEADER = 'T'; //header byte for arduino serial time message 
public static final char TIME_REQUEST = 7;  // ASCII bell character 
public static final char LF = 10;     // ASCII linefeed
public static final char CR = 13;     // ASCII linefeed
Serial myPort;     // Create object from Serial class
String[] zeilen=new String[345600];
String zeit="";
int zeile=0;

void setup() {  

  size(200, 200);
  println(Serial.list());
  println(" Connecting to -> " + Serial.list()[portIndex]);
  myPort = new Serial(this,Serial.list()[portIndex], 9600);
}

void draw()
{
  if ( myPort.available() > 0) {  // If data is available,
    char val = char(myPort.read());         // read it and store it in val
    if(val == TIME_REQUEST){
       long t = getTimeNow();
      // sendTimeMessage(TIME_HEADER, t);   
    }
    else
    { 
       if(val == LF)
           ; //igonore
       else if(val == CR) {        
      //zeilen = loadStrings("zeit.txt");
      
      zeilen[zeile]=zeit;
      zeile++;
      if(zeile%100 ==0 )
      saveStrings("zeit.txt", zeilen);
      
      println(zeile+" - "+zeit);

        /* println();
          print(hour());
         print(":");
         print(minute());
         print(":");
         print(second());
         print(" - ");*/
         zeit=hour()+":"+minute()+":"+second()+" ";
        

       }
       else {  
        
        // print(val); // echo everying but time request
         zeit=zeit+val;

         //print(" - ");
         //print(getTimeNow());
       }
    }
  }  
}

void mousePressed() {  
  sendTimeMessage( TIME_HEADER, getTimeNow());   
}


void sendTimeMessage(char header, long time) {  
  String timeStr = String.valueOf(time);  
  myPort.write(header);  // send header and time to arduino
  myPort.write(timeStr);   
}

long getTimeNow(){
  // java time is in ms, we want secs    
  GregorianCalendar cal = new GregorianCalendar();
  cal.setTime(new Date());
  int	tzo = cal.get(Calendar.ZONE_OFFSET);
  int	dst = cal.get(Calendar.DST_OFFSET);
  long now = (cal.getTimeInMillis() / 1000) ; 
  now = now + (tzo/1000) + (dst/1000); 
  return now;
}

ist etwas unsauber geschrieben, sollte aber schnell gehen, daher habe ich nur die bestehenden programme abgeändert, es sollte alles starten wenn man in das fenster klickt, das synchronisiert einmal die uhr und danach wird jede sekunde die arduino-zeit und die systemzeit geloggt und in regelmäßigen abständen in eine datei geschrieben.

Hier im Testcode steht aber sehr wohl ein dickes delay, gibt das in irgendeiner Weise einen Sekundentakt vor? Ich muss dazusagen, dass ich mit dem Funktionsumfang der Time-Library nicht vertraut bin.

das delay begrenzt lediglich die daten die über seriell übertragen werden, sodass sie etwa einmal pro sekunde kommen, die zeitmessung sollte komplett über die time.h gemacht werden

Wo stammt denn die Time.h Library her? Evtl. liefert das einen Ansatz, wo die fehlenden Sekunden bleiben. Geht die Uhr eigentlich immer vor, oder nach?

also die Time.h kommt von http://arduino.cc/playground/Code/Time und die uhr geht zu langsam, also nach 10 minuten zeigt sie nur 9:59 an, sie geht also demzufolge ?nach? glaube ich

ach ja, die sekunden fehlen ja nich nur bei der time.h implementierung, auch bei einer selbstgeschrieben geht die uhr genauso falsch, hier die andere implementierung:

//Test pattern on a 2x3 matrix of LEDs

int row=0;                          //im multiplexing angezeigte zeile
unsigned long lasttime=0;           //zeit seit letztem korrekten sekundenumstellen
long help;                          //hilfvariable zum sekundentakt
int sekunden=0;                     //sekundenanzeige (<60)
int minuten=0;                      //minutenanzeige (<60)
int stunden=0;                      //stundenanzeige (<24)
int zeit;                           //hilfsvariable, aktuell auf row angezeigte variable
int anzeige[]={0, 0, 0, 0, 0, 0 };  //binärmatrix für anzeige
byte butsek=0;                      //1 wenn sekundenknopf gedrückt, 0 sonst
byte butmin=0;                      //1 wenn minutenknopf gedrückt, 0 sonst
byte buth=0;                        //1 wenn stundennknopf gedrückt, 0 sonst
unsigned long buttime=0;            //entprellen und verlangsamen der zeiteinstellung
int i;                              //zählvariable
int rowpin[]={0,1,2};               //pins fpr sek-, min-, stundenzeile
int colpin[]={3,4,5,6,7,8};


void setup() {        
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(rowpin[0], OUTPUT);  //Sekundenzeile
  pinMode(rowpin[1], OUTPUT);  //Minutenzeile
  pinMode(rowpin[2], OUTPUT);  //Stundenzeile
  pinMode(colpin[0], OUTPUT);  //2^0-Spalte
  pinMode(colpin[1], OUTPUT);  //2^1-Spalte
  pinMode(colpin[2], OUTPUT);  //2^2-Spalte
  pinMode(colpin[3], OUTPUT);  //2^3-Spalte
  pinMode(colpin[4], OUTPUT);  //2^4-Spalte
  pinMode(colpin[5], OUTPUT);  //2^5-Spalte
  pinMode(12, INPUT);  //Set Sekunden
  pinMode(11, INPUT);  //Set Minuten
  pinMode(10, INPUT);  //Set Stunden
  //pinMode(13, OUTPUT);
  
}


void loop() {
for(i=0; i<=5; i++){anzeige[i]=0;}  //anzeige nullen
if(row>15) {                         //nur drei zeilen
  row=0;
}
sekunden=sekunden+butsek;          //uhr stellen wenn knopf gedrückt war
minuten=minuten+butmin;
stunden=stunden+buth;
butsek=0;
butmin=0;
buth=0;
if(sekunden>=60){sekunden=0;}
if(minuten>=60){minuten=0;}
if(stunden>=24){stunden=0;}

digitalWrite(colpin[0],LOW);                //alle spaltenwerte ausschalten
digitalWrite(colpin[1],LOW);
digitalWrite(colpin[2],LOW);
digitalWrite(colpin[3],LOW);
digitalWrite(colpin[4],LOW);
digitalWrite(colpin[5],LOW);

//zeilen multiplexen
digitalWrite(rowpin[0],LOW);
digitalWrite(rowpin[1],LOW);
digitalWrite(rowpin[2],LOW);
if(row<=2){
  digitalWrite(rowpin[row],HIGH);            //Transistor für angezeigte Zeile auf an schalten
}
//ende multiplexen
//stabiles addieren von einer sekunde
help=millis()-lasttime;
if (help>=1000 || help<0) {        //eine sekunde addieren wenn lasttime mehr als 
  lasttime=lasttime+1000;          //1000ms von millis() abweicht, lasttime um 1000ms
  sekunden++;                      //erhöhen und 60er sowie 24er überträge vornehmen
  if(sekunden>=60) {
    sekunden=0;
    minuten++;
    if (minuten>=60) {
      stunden++;
      if (stunden>=24) {
        stunden=0;
      }
    }
  }
}
zeit=0;
switch(row) {                      //hilfsvariable zeit mit korrektem multiplex-
case 0:                            //wert füllen
  zeit=sekunden;
  break;
case 1:
  zeit=minuten;
  break;
case 2:
  zeit=stunden;
  break;
}

if (zeit / 32 == 1) {              //sekunden, minuten und stunden in binär übersetzen
  anzeige[5]=1;
  zeit=zeit-32;
}
if (zeit / 16 == 1) {
  anzeige[4]=1;
  zeit=zeit-16;
}
if (zeit / 8 == 1) {
  anzeige[3]=1;
  zeit=zeit-8;
}
if (zeit / 4 == 1) {
  anzeige[2]=1;
  zeit=zeit-4;
}
if (zeit / 2 == 1) {
  anzeige[1]=1;
  zeit=zeit-2;
}
if (zeit / 1 == 1) {
  anzeige[0]=1;
  zeit=zeit-1;
}



for (int i=0; i<=5; i++) {          //korrekte spalten einschalten
  if (anzeige[i]==1) {
    digitalWrite(colpin[i],HIGH);
  }
}

if (digitalRead(12)==HIGH && abs(millis()-buttime)>=200) {
  butsek=1;                         //knopf gedrückt angeben, wenn knopf gedrückt
  buttime=millis();                 //ist und seit 50 sekunden keine stellung
}                                   //mehr vorgenommen wurde
else {
  butsek=0;
}
if (digitalRead(11)==HIGH && abs(millis()-buttime)>=200) {
  butmin=1;
  buttime=millis();
}
else {
  butmin=0;
}
if (digitalRead(10)==HIGH && abs(millis()-buttime)>=200) {
  buth=1;
  buttime=millis();
}
else {
  buth=0;
}



delay(1); //gewisse mutiplexzeit erzwingen
row++; //nächste zeile anzeigen
}

Ich glaube es liegt an den delays und der Ausführungszeit des loops - das würde die Abweisung im negativen Bereich erklären. Also entweder die Abweichung kompensieren (per zeitmessung Start->Ende vom loop) oder auf ein RTC-Modul die den DS1307 oder ds1337 (kostent etwa 2 Euro, braucht nur 2 Pins) umsteigen.

Hier der erwähnte delayfreie code, liefert die gleiche zeitabweichung, verzichtet aber auf das delay beim multiplexen, was leider zu einem flackern des displays ab und an führt. wie bereits anfangs erwähnt würde ich gerne auf solche module verzichten, da ich ja eigentlich mit dem verbauten quarz auf 100ppm oder genauer messen können sollte

#include <Time.h>

int row=0;                          //im multiplexing angezeigte zeile
unsigned long lasttime=0;           //zeit seit letztem korrekten sekundenumstellen
long help;                          //hilfvariable zum sekundentakt
int sekunden=0;                     //sekundenanzeige (<60)
int minuten=0;                      //minutenanzeige (<60)
int stunden=0;                      //stundenanzeige (<24)
int zeit;                           //hilfsvariable, aktuell auf row angezeigte variable
int anzeige[]={0, 0, 0, 0, 0, 0 };  //binärmatrix für anzeige
byte butsek=0;                      //1 wenn sekundenknopf gedrückt, 0 sonst
byte butmin=0;                      //1 wenn minutenknopf gedrückt, 0 sonst
byte buth=0;                        //1 wenn stundennknopf gedrückt, 0 sonst
unsigned long buttime=0;            //entprellen und verlangsamen der zeiteinstellung
int i;                              //zählvariable
int rowpin[]={0,1,2};               //pins fpr sek-, min-, stundenzeile
int colpin[]={3,4,5,6,7,8};


void setup() {       
  setTime(0,0,0,0,0,0); 
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(rowpin[0], OUTPUT);  //Sekundenzeile
  pinMode(rowpin[1], OUTPUT);  //Minutenzeile
  pinMode(rowpin[2], OUTPUT);  //Stundenzeile
  pinMode(colpin[0], OUTPUT);  //2^0-Spalte
  pinMode(colpin[1], OUTPUT);  //2^1-Spalte
  pinMode(colpin[2], OUTPUT);  //2^2-Spalte
  pinMode(colpin[3], OUTPUT);  //2^3-Spalte
  pinMode(colpin[4], OUTPUT);  //2^4-Spalte
  pinMode(colpin[5], OUTPUT);  //2^5-Spalte
  pinMode(12, INPUT);  //Set Sekunden
  pinMode(11, INPUT);  //Set Minuten
  pinMode(10, INPUT);  //Set Stunden
  //pinMode(13, OUTPUT);
  
}


void loop() {
for(i=0; i<=5; i++){anzeige[i]=0;}  //anzeige nullen
if(row>15) {                         //nur drei zeilen
  row=0;
}

if(butsek==1)
{
  adjustTime(1);
}

if(butmin==1)
{
  adjustTime(60);
}

if(buth==1)
{
  adjustTime(3600);
}

sekunden=second();
minuten=minute();
stunden=hour();

butsek=0;
butmin=0;
buth=0;


digitalWrite(colpin[0],LOW);                //alle spaltenwerte ausschalten
digitalWrite(colpin[1],LOW);
digitalWrite(colpin[2],LOW);
digitalWrite(colpin[3],LOW);
digitalWrite(colpin[4],LOW);
digitalWrite(colpin[5],LOW);

//zeilen multiplexen
digitalWrite(rowpin[0],LOW);
digitalWrite(rowpin[1],LOW);
digitalWrite(rowpin[2],LOW);
if(row<=2){
  digitalWrite(rowpin[row],HIGH);            //Transistor für angezeigte Zeile auf an schalten
}

zeit=0;
switch(row) {                      //hilfsvariable zeit mit korrektem multiplex-
case 0:                            //wert füllen
  zeit=sekunden;
  break;
case 1:
  zeit=minuten;
  break;
case 2:
  zeit=stunden;
  break;
}

if (zeit / 32 == 1) {              //sekunden, minuten und stunden in binär übersetzen
  anzeige[5]=1;
  zeit=zeit-32;
}
if (zeit / 16 == 1) {
  anzeige[4]=1;
  zeit=zeit-16;
}
if (zeit / 8 == 1) {
  anzeige[3]=1;
  zeit=zeit-8;
}
if (zeit / 4 == 1) {
  anzeige[2]=1;
  zeit=zeit-4;
}
if (zeit / 2 == 1) {
  anzeige[1]=1;
  zeit=zeit-2;
}
if (zeit / 1 == 1) {
  anzeige[0]=1;
  zeit=zeit-1;
}



for (int i=0; i<=5; i++) {          //korrekte spalten einschalten
  if (anzeige[i]==1) {
    digitalWrite(colpin[i],HIGH);
  }
}

if (digitalRead(12)==HIGH && abs(millis()-buttime)>=200) {
  butsek=1;                         //knopf gedrückt angeben, wenn knopf gedrückt
  buttime=millis();                 //ist und seit 50 sekunden keine stellung
}                                   //mehr vorgenommen wurde
else {
  butsek=0;
}
if (digitalRead(11)==HIGH && abs(millis()-buttime)>=200) {
  butmin=1;
  buttime=millis();
}
else {
  butmin=0;
}
if (digitalRead(10)==HIGH && abs(millis()-buttime)>=200) {
  buth=1;
  buttime=millis();
}
else {
  buth=0;
}




row++; //nächste zeile anzeigen
}
if (help>=1000 || help<0) {        //eine sekunde addieren wenn lasttime mehr als 
  lasttime=lasttime+1000;          //1000ms von millis() abweicht, lasttime um 1000ms

Wenn Du mehr als 1000 hast und trotzdem nur 1000 addierst, dann verlierst Du Zeit.
Richtiger wäre:

if (help>=1000) {        //eine sekunde addieren wenn lasttime mehr als 
  lasttime=lasttime+help;          //1000ms von millis() abweicht, lasttime um 1000ms

Also die time-Lib macht auch nichts anderes als intern die Sekunden zu zählen. Dabei wird bei jedem Aufruf von "time_t now()" der aktuelle millis()-Wert verwendet, um die seit dem letzten Aufruf vergangenen Sekunden zu zählen und die Zeit zu aktualisieren. Da hier immer auf glatte 1000er geprüft wird, kannst Du schon an dieser Stelle mit einem Fehler von einer Sekunde (genauer 0,999 Sekunden) rechnen. Dieser Fehler ist aber konstant und summiert sich nicht auf.
Sowohl die time-Lib als auch Dein Code verwendet recht häufig die Funktion millis(), was im Prinzip auch nicht schlimm ist. Das hat aber auch Auswirkungen, denn die Werte die von millis() und micros() zurückgeliefert werden, werden intern über timer-interrupts gezählt.
Die Funktion millis() sieht aber vom Code wiefolgt aus:

unsigned long millis()
{
        unsigned long m;
        uint8_t oldSREG = SREG;

        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        cli();
        m = timer0_millis;
        SREG = oldSREG;

        return m;
}

Man sieht, das vor dem Kopieren des Wertes von timer0_millis die Interrupts abgeschaltet werden und danach wieder angeschaltet. Während dieser, zugegeben, recht kurzen Zeitspanne werden keine Interrupts mehr verarbeitet. Es kann also durchaus vorkommen, das ein "Zählimpuls" des Timers verpasst wird. Je häufiger millis() verwendet wird, desto größer ist die Wahrscheinlichkeit, das sowas passiert.
"delay()" verwendet intern übrigens aus micros() zum "zählen", es hilft also auch nix, mit einem großen delay() die Zahl der millis() aufrufe "pro Tag" zu reduzieren.
Um das Ganze zu testen, wäre es z.B. möglich, einfach nur "dumme", geschachtelte Zählschleifen zu Verzögerung zu verwenden, die die keinen Einfluss auf die timer-Interrupts haben.
Also

  1. Zeit syncen und einmal ausgeben (millis() Wert merken)
  2. Zählschleifen, die 10 Stunden o.ä. beschäftigt sind laufen lassen
  3. millis() Wert erneut merken und ausgeben
  4. gemessenen millis() Wert mit aktueller Zeit vergleichen.
    Ist die Abweichung geringer, dann hast Du Deine Fehlerquelle.

Ich will immer noch nicht verstehn, was gegen eine rtc spricht - was meinst du mit 100ppm? Die rtc hat eine Uhrzeit die abgefragt wird - andere Bauteile sind von ihr nicht betroffen... Außerdem hat auch dein delayfreier Code eine gewisse Ausführungszeit - die du vernachlässigst und die die Abweichungen ausmachen können. Für ECHTZEIT-Anwendungen nimmt man eben ECHTZEIT-Bausteine.

EDIT: delay() unterbricht die gesamte Ausführung für den eingegeben Zeitrahmen - der Prozessor macht in dem Moment einfach mal garnix.

Joghurt:

if (help>=1000 || help<0) {        //eine sekunde addieren wenn lasttime mehr als 

lasttime=lasttime+1000;          //1000ms von millis() abweicht, lasttime um 1000ms




Wenn Du mehr als 1000 hast und trotzdem nur 1000 addierst, dann verlierst Du Zeit.
Richtiger wäre:



if (help>=1000) {        //eine sekunde addieren wenn lasttime mehr als
  lasttime=lasttime+help;          //1000ms von millis() abweicht, lasttime um 1000ms

nein, so einfach lässt sich das problem leider nicht beheben, beide methoden sind äquivalent in ihrer ausführung, da ich mich im nächsten schleifendurchlauf ja wieder auf die neue "lasttime" beziehe, ich wollte damit einzig und allein den unwahrscheinlichen fall abfangen das die uhr an einer stelle zwei sekunden gleichzeitig tickt falls ein schleifendurchlauf viieeel zu lange dauert, eigentlich sinnlos, aber egal, auf lange zeiten (mehr als ne stunde) sollte diese methode zeitstabil sein, ist sie aber nicht

ppm bedeutet parts per million, also 10^-6, das bedeutet 100ppm ist eine abweichung von 0,01%. im prinzip spricht gar nichts gegen eine RTC, ich halte es aber eigentlich für sinnlos eine zweite zeitmessvorrichtung zu integrieren, wenn ich eigentlich schon eine, in form des verbauten quarzes (mit für mich ausreichender genauigkeit) habe und das ganze einfach nur genau eine uhr darstellen soll.

die idee mit der schleife werde ich mal verfolgen und werde mal schauen ob es and er verwendung von millis() liegt

na also parts-per-million hätt ich schon gewusst, nur was das mit ner Uhr zu tun hat, war mir nicht klar. Normalerweise wird dieser Ausdruck zum Messen von Konzentrationen benutzt.

Und nun zu deinem Denkfehler: Du hast keine Zeitmesseinrichtung mit ausreichender Genauigkeit - Der Systemtakt ist nicht für Echtzeitaufgaben zu gebrauchen, da (und ich wiederhole mich) verschiedene Faktoren eine Verzögerung der Programmausführung zur folge haben.

hm... ok... dann versuch ich mich mal weiter daran und werde gegebenenfalls noch versuchen mit korrekturwerten zu arbeiten

und ppm wird eben nicht nur im chemielabor genutzt :wink:

Also gut :stuck_out_tongue: - wenn du stur auf eine RTC verzichten willst, musst du deine Uhr eichen.

Dazu benötigst du eine externe Quelle, die über eine Echtzeituhr verfügt - wie etwa einen Computer.

Wenn du einen Button benutzt, um per knopfdruck eine Verbindung zwischen Computer und Arduino herzustellen, kannst du die (Arduino-)Systemzeit mit der Echtzeit abgleichen und hast deann den Kompensationsfaktor. Eigentlich ähnlich wie in deinem Processingsketch. Diese Eichung musst du allerdings mehrmals über einen bestimmten Zeitraum machen um eine Schnittmenge zu bekommen.

Diese Zahl würde ich anschließend im EEPROM des Arduinos ablegen um bei bedarf darauf zurückzugreifen.

ja, die idee hatte ich auch schon und werde das wohl auch so verfolgen... das mit der statistik bekomme ich schon hin, das physikstudium soll ja auch nicht ganz für umsonst gewesen sein :wink:

Wie MarcusW bereits deutlich ausgedrückt hat, wirst Du so nie zu einer sauberen Lösung kommen.

Selbst wenn Du durch softwaremässige Korrekturen eine ausreichende Genauigkeit erreichen solltest, sind diese spätestens bei späteren Programmerweiterungen bzw. Änderungen schnell wieder hinfällig, die Ungenauigkeit nimmt wieder zu.

Hardwaremässig würde der Atmega168/328 für solche Aufgaben den Anschluß eines zweiten Quarzes vorsehen, was vom Arduino aber nicht unterstützt wird. Deshalb ist auch die Lösung, einen Uhren- bzw. dcf77-Baustein zu verwenden, eigentlich unvermeidlich - selbst wenn man voraussetzen kann, daß die verwendete Timerbibliothek bereits optimal programmiert ist.

Glaub' uns - diese Erfahrung wirst Du früher oder später machen. :wink:

Gruß. mmi.

Vielleicht ein genaueres Quarz an einen Arduino-Pin hängen und den mit einem Interrupt versehen?