Genauigkeit von "millis" ??

Hallo,

habe ich das richtig verstanden daß "millis" direkt aus einem Hardwaretimer / Quarzoszillator kommt? Ich meine, kann man das für eine Uhr gebrauchen unter Voraussetzung daß ein guter Quarz eingebaut ist?

Bei mit läuft seit Jahren eine Uhr auf Basis PIC16F628, guter Quarz, Assemblerprogramm mit Timerinterrupt völlig zufriedenstellund und überlege ob das auf einem Arduino prinzipiell genauso gut funktionieren kann oder doch eine RTC dazu muß...

Wie gut/genau sind eigentlich die Quarze und Resonatoren der aktuellen "originalen" Uno/Nano/Minis in diesem Zusammenhang???

Christian

Für eine Uhr oder stark frequenzabhängige Prozesse kann ich millis nicht empfehlen.

Besser man verwendet direkt einen temperaturkompensieren Oszilator. So einer ist zB in den DS3231 verbaut. ♦ Accuracy ±2ppm from 0°C to +40°C ♦ Accuracy ±3.5ppm from -40°C to +85°C

Bei Quarzen bist du bei einer Abweichung von 10–100ppm.

Es kommt aber auf dem Anwendungszweck an. Für eine Uhr, die in einer bestimmten Intervall über Funk oder NTP aktualisiert wird, sollte auch der interne millis Zähler gut funktionieren. Bei mir leider nicht.

Habe in einer Anwenung bei mir das Problem, dass die Interrupts zu häufig wegen bestimmten Timings gesperrt müssen. Habe es so gelöst, dass ich den SQW Ausgang vom DS3231 mit 1024Hz beschaltet hab. Über einen Timer lese ich diese ein mache dann alle 1/16s einen Interupt. Ich nutzte somit nicht millis als kleinste Zeit, sonder 1/16s.

ich persönlich würde, wenn es ganggenau sein soll, eine externe Uhr dranhängen, batteriegepuffert, wie diese auf I2C-Basis:
http://www.mindsensors.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=77
(mal gesehen an einem NXT, funktioniert aber auch mit Arduinos, und gibt’s bestimmt auch billiger)
Zur Not kann man damit wenigstens millis() “eichen”.

(ps, meine Herren, ist der Forums-Server heute wieder lahm - 3 Minuten Lag-Time nach Rechtschreibkorrektur!!)

Heute ist es nicht schon wieder lahm, immer noch seit 2 Tagen. :zipper_mouth_face:

Die I2C Uhr für das NXT System ist jetzt nicht zwingend das beste, wenn du es relativ genau haben möchtest. Dort sitzt nur ein DS1307 drinnen. Dieser hat 2 entscheidene Nachteile, abgesehen davon, dass ich die Schaltung im inneren der Gerätes nicht kenne, wobei diese nicht großartig von den typischen Schaltungen abweichen wird.

Zum einen ist der DS1307 nur für 5V I2C Systeme geeignet. Heißt, wenn du Sensoren mit 3V3 Volt im Einsatz hast, kann es hier zu Problemen kommen und das Signal muss aufbereitet werden mit Levelshiftern. Des weiteren sind die nicht so genaue wie die DS3231. Gibt locker mal ein paar Minuten im Monat (alle paar Tage hier zu lesen). Vorteil gegenüber den DS3231 sind: Günstiger und auch als DIP verfügbar.

Wenn du nicht selber löten möchtest, dann würde ich dir sowas empfehlen http://www.ebay.de/itm/mini-RTCpro-DS3231-Clock-Module-Temperature-Measure-Sensor-Mini-RTC-Real-Time-/181472175297?pt=LH_DefaultDomain_77&hash=item2a4095a4c1 Alternativ gibt es auch noch diese Varianten mit einer Knopfzelle zum Austauschen. Preise varieren jenach Herkunft zwischen 2~5€, also nicht so teuer.

Hallo,

millis und alles andere triftet weg, weil der µC Takt nicht so genau stabil ist. Muß er ja dafür auch nicht sein. Auch wenn ich es wiederhole, weil es hier schon steht. Nimm eine DS3231 RTC. Die läuft astrein stabil. Hab ich auch im Einsatz. Gibts in der Bucht für ca. 3 Euro für ein fertiges kleines Modul. Und man kann mit der DS3231 verschiedene Alarme programmieren.

Millis ist so genau wie der Systemtakt ist.
Arduinos mit Quarz 20-100ppm, Resonator wie auf dem Arduino UNO ca 5000ppm.
Viele Grüße Uwe

Hallo, ist es nicht möglich diesen Takt zu "eichen"? Die Arduino´s haben doch XTAL1 und XTAL 2. Man könnte doch an XTAL2 einen z.B. 22pF Kondensator anschließen, und an XTAL1 einen 15 bis 40pF Trimmer. Damit sollte sich der Quarz doch ziemlich "genau" einstellen lassen. Gruß und Spaß Andreas

Hallo Andreas,

das mit dem Trimmer ist keine schlechte Idee, aber nicht machbar! Es wird nicht möglich sein, den Quarz ohne extra Hardware genauer zu trimmen. Das Problem ist, dass diese immer eine Abweichung bei Temperaturabweichungen haben werden. Somit auch der Trimmer hinfällig.

Bei den meist nur noch eingesetzen Resonatoren wird das nicht besser. Für UART reichen diese noch aus, aber für hochgenaue Anwendungen nicht mehr.

Zumal es für den Anwendungszweck einer Uhr sowieso nicht vorteilhaft ist, diesen nur über den MCU laufen zu lassen. Der Stromverbrauch ist höher, als bei einem RTC-IC. Hier kann man den Arduino/MCU in den SleepMode versetzen und entsprechend Aufwecken, wenn wieder was gemacht werden muss. Die RTC braucht deutlich weniger Strom und desweiteren läuft diese über die Backup Batterie weiter.

http://shelvin.de/den-arduino-quarz-takt-genauer-bestimmen/

Oft wird davon ausgegangen, daß durch Eichung oder andere Maßnahmen ein ungenaues System supergenau werden kann. Dem ist nicht so. Den Fehler, den ein System hat, setzt sich aus Fehlern mit verschiedenen Quellen zusammen. Die Fehler sind Teilweise quantifizierbar und darum können sie kompensiert werden, andere sind aber zufällig und darum nicht vorhersehbar und korrigierbar. Im Falle eines Quarzes gibt es die Temperaturabhängigkeit und die Alterung. Der Temperaturfehler wird bei genauen Taktgeneratoren durch Erwärmen auf 50°C konstant gehalten. Einige hochgenaue RTC messen die Temperatur und kompensieren dann dementsprechend die Zeit bzw haben ein Register in denen man einen Korrekturwert abspeichert.

eie RTC hat den Vorteil daß sie die eingestellte Zeit nicht verliert da sie eine Backupbatterie hat. Grüße Uwe

ich weiß jetzt nicht, ob du dich bezüglich Eichung auf meinen Post beziehst - grundsätzlich hast du damit ntl Recht.

Deine obigen Aussage "Millis ist so genau wie der Systemtakt ist." in diesem Zusammenhang aber sicher zu relativieren, denn mein Post bezog sich vor allem auf den Fall, dass Timer-Interrupts immer wieder den Systemtaktgeber "aushebeln". Hier käme also zu statistischen Schwankungen (z.B. durch Umgebungstemperatur) noch ein systematischer Fehler hinzu, wie groß der letztendlich ist, ist ntl sehr programmspezifisch und individuell. Auch ist letzlich keine Aussage daüber getroffen worden, wie genau denn wirklich die Zeitmessung und Messgenauigkeit von millis stimmen sollte - im ms-Bereich, im Sekundenbereich - oder im Stunden - oder Tagesbereich ? Dann wäre die Anschluss-Frage, wie genau denn die RTCs messen können oder müssten, und ob Messfehler im (Milli-) Sekundenbereich hinnehmbar sind, wenn wenigstens (im Extremfall) die Tagestunde oder das Tagesdatum bei Sommer/Winterzeit oder Schaltjahren stimmt.

Erst wenn man das weiß (ich hoffe, ich habe da nichts überlesen!) kann man sicher exakt eine maßgeschneiderte Lösung anbieten.

Daher jetzt erstmal meine Verständnisfrage an den TO - : wo liegt denn genau der Hund begraben?

elektron_:
habe ich das richtig verstanden daß “millis” direkt aus einem Hardwaretimer / Quarzoszillator kommt? Ich meine, kann man das für eine Uhr gebrauchen unter Voraussetzung daß ein guter Quarz eingebaut ist?

Die millis()-Zählung wird direkt vom Systemtakt des Controllers abgeleitet und ist daher von der Langzeitgenauigkeit her so genau, wie der beabsichtigte Systemtakt von 16 MHz eingehalten wird.

elektron_:
Wie gut/genau sind eigentlich die Quarze und Resonatoren der aktuellen “originalen” Uno/Nano/Minis in diesem Zusammenhang???

Auf “alten” Arduino-Boards mit einem Schwinquarz als Taktgeber (z.B. Board “DUEMILANOVE”) wird der Takt auf <100 ppm eingehalten. Das entspräche einer Gangabweichung von ca. 86400*100/1000000 = maximal rund 9 Sekunden pro Tag. In typischen Fällen wahrscheinlich weniger, da Schwingquarze bei Zimmertemperatur oft sogar eine geringere Abweichung haben. Diese alten Boards mit Schwingquarz muss man im Handel allerdings mit der Lupe suchen.

Auf “neuen” Arduino-Boards mit einem keramischen Resonator als Taktgeber (z.B Board “UNO R3”) wird der Takt aber nur auf <3000 ppm eingehalten. Das entspräche einer Gangabweichung von ca. 86400*3000/1000000 = rund 259 Sekunden pro Tag.

Je genauer der Systemtakt eingehalten wird, desto genauer kannst Du eine Uhrzeit vom Systemtakt ableiten. Und wie genau innerhalb der verschiedenen Technologien (Schwingquarz/Resonator) der Takt tatsächlich eingehalten wird, hängt von der Typenstreuung und der Temperatur ab.

D.h. die Genauigkeit hängt nicht vom Controller ab, sondern von der angeschlossenen Hardware zur Takterzeugung. Ist der Takt genauer, dann ist auch die daraus abgeleitete Zeit genauer.

Moment - und was ist mit Rechenzeit-konsumierenden Timer-Interrupts...?

HaWe: Moment - und was ist mit Rechenzeit-konsumierenden Timer-Interrupts...?

Was soll damit sein?

Der Verbrauch von Rechenzeit, auch innerhalb von Interrupt-Behandlungsroutinen, ändert an der Korrektheit der Zeitzählung absolut nichts.

Erst wenn man selbst in einem Sketch eigene Interrupt-Behandlungsroutinen schreibt, die "zu lange" laufen oder man Interrupts für zu lange Zeit sperrt, können im System angeforderte Interrupts verlorengehen. Wobei "zu lange" bedeuten würde, dass ein anderer Interrupt bzw. eine Interruptsperrung länger laufen müßte als die Zeit zwischen zwei Timer-Interrupts, um einen Timer-Interrupt komplett ausfallen zu lassen.

Da die Timer0-Interrupts mit einem Takt von (glaube ich) einmal pro Millisekunde laufen, wäre "zu lange" also jede Interruptbehandlung, die länger als 1ms läuft. 1000 Mikrosekunden!

Wer bei klarem Verstand ist, schreibt Interrupt-Behandlungsroutinen, die vielleicht mal 4 oder 8 Mikrosekunden laufen. Im äußersten Notfall vielleicht mal eine mit einem "analogRead()", die dann 130 µs läuft. Aber man schreibt einfach keine Interruptbehandlungen von 1000 Mikrosekunden Dauer.

Und dann geht auch mit Interrupts oder bei gesperrten Interrupts keine Zählung verloren, sondern wird allenfalls mal um die Zeit einer Interruptbehandlung oder einer Interruptsperrung verzögert, also nach 4 oder 8 Mikrosekunden wieder "aufgeholt", weil dann der wartend gestellte Interrupt einfach etwas später ausgeführt wird.

In manchen Konfigurationen sperren allerdings Arduino-Programmierer die Interrupts für längere Zeit im Sketch, zum Beispiel bei der Ansteuerung von WS2812 LED-Controllern, da diese ein äußerst exaktes Timing benötigen, das mit laufenden Interrupts nicht einzuhalten ist. Solche Programme, in denen Interrupts "zu lange" gesperrt werden, um ein einwandfreies Timing aufrechtzuerhalten, sind allerdings eher die Ausnahme als die Regel, und wer so etwas programmiert sollte sich darüber im klaren sein was passiert, wenn er ellenlang die Interruptausführung im Programm blockiert.

genau das meinte ich -
millis ist NICHT so genau wie der cpu-Takt, denn es wird u.U. ZUSÄTZLICH durch den Gebrauch von Timer-Interrupts verfälscht. Das hat nichts mit “bei Verstand sein” zu tun, und solche unsachlichen Bemerkungen gehöen einfach nicht hierhin - es ist ein grundsätzliches Problem mit Timer-Interrupts, und du zitierst ja selber ein entsprechendes Beispiel. Ob das nun häufig oder selten ist, ist ebenfalls völlig belanglos, denn es geht ja hier um eine grundsätzliche, allgemeine Erörterung.

Daher darf ich nochmals auf meine obigen Posts verweisen, insb. hierauf :

Dann wäre die Anschluss-Frage, wie genau denn die RTCs messen können oder müssten, und ob Messfehler im (Milli-) Sekundenbereich hinnehmbar sind, wenn wenigstens (im Extremfall) die Tagestunde oder das Tagesdatum bei Sommer/Winterzeit oder Schaltjahren stimmt.
Erst wenn man das weiß (ich hoffe, ich habe da nichts überlesen!) kann man sicher exakt eine maßgeschneiderte Lösung anbieten.
Daher jetzt erstmal meine Verständnisfrage an den TO - :
wo liegt denn genau der Hund begraben?

HaWe: millis ist NICHT so genau wie der cpu-Takt, denn es wird u.U. ZUSÄTZLICH durch den Gebrauch von Timer-Interrupts verfälscht.

Nein, es wird bei korrekter Programmierung absolut NICHTS beim Timing "verfälscht", sondern der millis() Zähler wird absolut exakt und völlig zuverlässig alle 16 Millionen Takte um genau 1000 weiter hochgezählt, wenn man keinen Dreckscode programmiert.

Wobei ich mit dreckigem Code solchen Code meine, der Interrupts viel zu lange laufen läßt oder blockiert, so daß angeforderte Interrupts überlaufen und nicht ausgeführt werden.

Sauberer Code = sauberes Timing.

der Code kann sauber sein, aber wenn Timer-gesteuerte Berechnungen lange dauern, dann dauern sie halt lange, dann ist das aber kein "Dreckscode" - so etwas disqualifiziert dich nur selber als ernstzunehmenden Ratgeber. Solche abwertenden Termini gehören einfach nicht in eine sachliche Diskussion, und sachlich falsch (weil allgemein betrachtet unrichtig) ist dein Post also auch noch. Warten wir doch besser ab, was der TO zu seinen "Genauigkeitsproblemen" zu berichten hat.

Der Timer ruft alle x µS ( y Taktzyklen) einen Interrupt auf und die Interruptroutine erhöht den Millis()-Zähler.

Wenn jetzt der Sketch die Intterupts schlecht verwendet und diese Interrupt so häufig sind daß die Timerinterrupts (teilweise) nicht bearbeitet werden und verlorengehen dann ist millis() falsch.

Grüße Uwe

Hallo, hä!? "Timerinterrupts (teilweise) nicht bearbeitet werden und verlorengehen dann ist millis() falsch."

Diese millis() holen sich den Wert doch von einem internen Zähler des Atmel. Spannung an- Zähler startet. Beispiel: Spannung an- Zähler an, nach 5 Minuten Zähler bei 5000

jetzt Spannung an- Zähler an, "Drecks Code" , nach 5 Minuten Zähler bei 3000 oder Zähler bei 7000.

Läuft der interne Zähler des Atmel nicht unanbhängig von "allem"? Oder gibt es diesen Zähler nicht, und er wird durch millis() generiert? Gruß und Dank Andreas

Der Zähler selbst schon. Aber Interrupts können sich standardmäßig nicht gegenseitig unterbrechen, da beim Eintritt in eine ISR das globale Interrupt Enable Flag im SREG Register gelöscht wird. Das ist ja der Grund weshalb millis() in ISRs nicht aktualisiert wird. Man kann einmal den aktuellen Wert auslesen, aber der bleibt dann bis man die ISR verlässt. Aus dem gleichen Grund geht delay() nicht, da selbst ständig millis() abfragt. delayMicroseconds() machst dagegen NOPs in inline Assembler und funktioniert.

Wobei die meisten Interrupts die während eines anderen Interrupts eintreffen 1 Takt nach dem Ende der ISR abgearbeitet werden, da sie ihre entsprechenden Interrupt Flags setzen. Erst wenn zwei Interrupts auf dem gleichen Vektor eintreffen und nicht verarbeitet werden gehen Informationen verloren.

SkobyMobil: Läuft der interne Zähler des Atmel nicht unanbhängig von "allem"?

Doch, der Timer0-Zähler läuft unabhängig. Aber nicht bis 5000 oder 7000.

Als 8-Bit Zähler läuft der Timer0-Zähler stets von 0 bis 255 und bei der nächsten Zählung springt er auf 255+1= 0 um, und es wird ein Interrupt ausgelöst, der dann abgearbeitet sein muss, bevor der Zähler wieder das nächste mal überläuft.