Ich habe ein DS3231 RTC Modul in meinem Anfängerpaket mit dem UNO zusammen bekommen. Wie kann ich mir den 32k Pin oder den SQW Pin des DS3231 zu nutze machen um die Messergebnisse (auch bei längerer Messung genau(er) zu halten? Hat jemand ein Beispiel für mich?
Oder gibt es da andere Mittel und Wege?
zu der lib gehören mehrere Beispiele eines behandelt deinen Wunsch.
wenn Du eine Langzeit Stopuhr bauen willst und eine Auflösung von 1 s reicht könntest Du die Unix Zeit auslesen und die Differenz zwischen start und stop bilden.
Du hast ja sicher aus den Antworten hier schon mitbekommen das Dein Lösungsansatz mit Interupt nicht wirklich zielführend ist. Versuche das erst mal mit Deinem millis() Ansatz ohne Interupt , dabei lernst Du dann auch schon mal ein paar Dinge.
Ob Du die 32kHz brauchst?
Denke, ms-genau sollte halbwegs reichen.
Lasse Dir den Sekunden-Takt ausgeben und polle in der loop(), zu welcher millis()-Zeit Der kam.
Wird <=1000 Unterschied sein.
Bei Start/Stop merkst Du Dir den Abstand zum Sekunden-Signal.
Daraus - und der Anzahl der Sekunden-Signale während der Messung - berechnest Du die Zwischenzeit.
Auf Millisekunden wirst Du So wohl nicht kommen, aber ich denke, zumindest recht nahe dran.
Du brauchst keinen Interrupt, Pollen des Taster und des Sekunden-Signal wären (mehr oder minder) die einzigen Aufgaben der loop() (Anzeige während der Messung wird das Ergebnis stark beeinflussen)
Anzeige nur mit Sekunden während der Messung und nur wenn sich diese ändert. Nur neu anzeigen, was sich geändert hat.
Das sollte das Problem entschärfen.
danke für die ersten Tipps und danke für die freundliche Aufnahme im Forum.
Da das mein erste mal ist, wo ich selber was 'Bastel' ist mein Ziel wie bei den meisten
Anfängern wahrscheinlich zu hoch. Trotzdem -finde ich- wächst man mit den Aufgaben.
Inspiriert hat mich ein Schwimmwettkampf meiner Kinder. Dort wurde mit Stoppuhren gemessen und ich dachte, dass das auch anders gehen kann.
Jetzt versuche ich (zum Glück ohne Erfolgsdruck ) eine Arduino-Basierte Stoppuhrbox mit 4 Kanälen. Deshalb hätte ich gerne die Präzision einer guten Stoppuhr mit minuten, sekunden, zehntel und hundertstel.
Die Interrupts habe ich gewählt weil ich vermutet habe, dass ich so auf jeden Fall die Drücker in der richtigen Reihenfolge stoppe.
Das die Interrupts zu viel machen (serial.print) ist ein guter Hinweis. Das ist schon rausgeflogen. Ich Zeige nur noch an, wenn der status STOPPED ist.
@michael_x: Was ich leider nicht verstanden habe ist der Punkt
- volatile Variable größer als 1 byte müssen auch in loop unter geschlossenem Interrupt geändert werden.
Sollte ich diese 4-Kanal-Stoppuhr hinbekommen würde ich eine Übertragung an einen "Master Arduino" per RS485 ins Fassen. Für mich ambitioniert (wie die Stoppuhr in dem Format auch, aber ich hab Blut geleckt 8) )
Nehmen wir an, Du willst ein int (also 2Byte) lesen. Nach dem 1. Byte schlägt der Interrupt zu und ändert das 2. Byte. Du liest also Mist.
volatile int myInt;
...
int myTempInt;
nointerrupt();
myTempInt = myInt; // hier pfuscht keiner dazwischen
interrupt();
// jetzt mit myTempInt weiter arbeiten
Alle Variablen, Die größer als 1 Byte sind (int, long, float) können sowohl beim Lesen wie beim Schreiben durch einen Interrupt unterbrochen werden - und der Interrupt kann diese variablen auch lesen/beschreiben - wenn Das mitten drin passiert, hast Du Müll.
So musst Du die Interrupts sperren, die Daten schreiben/lesen, die Interrupts wieder frei geben.
Volatile verhindert, daß die Daten in Registern (sehr schnelle Speicher) behalten werden, da ja in der Zwischenzeit - der Sketch weiß Nichts von Interrupts - genau ein Solcher den Wert verändert haben kann.
Der Arduino aber 'denkt', daß Er gerade ja noch mit genau dieser variable gearbeitet hat - nun soll Er 1 dazu zählen - und statt den aktuellen Wert aus dem Speicher auszulesen, macht Er nur 'Erinnerung plus ein' und speicher das nun falsche Ergebiss ab.
Wieder Müll.
In einer ISR werden Flags (Flaggen) gesetzt.
Diese sind, da Die ja im Hauptprogramm ausgewertet werden, ebenfalls volatile.
Aber, da maximal Byte, ohne Probleme auslesbar.
Denke aber: Brauchst Du nicht - für Hunderstel reicht ein Arduino gerade so.
Baue zuerst eine Uhr, Die per Knopfdruck den aktuellen millis()-Wert als Startwert übernimmt und beim nächsten Knopfdruck millis() als Stop-Wert.
Mit millis() bekommst Du die Millisekunden seit Start des µC (so ungefähr ... der Arduino ist keine hoch präzise Uhr, aber für Hundertstel sollte Das reichen).
Tasten(ent)prellen wird Dir auch noch begegnen
Wenn Das läuft - einen Taster für Start, vier Taster für Stop - also vier Stop-Zeiten.
Dann kann man langsam mit der Metall-Anschlagplatte ins Schwimmbecken - dort sollte die Versorgung aber aus einer Power-Bank bestehen - Sicher ist halt sicher.
Für eine Stoppuhr im Minutenbereich brauchst du imho keinen RTC.
Auch bei 4 Lanes wird sich kaum ein größerer Fehler ergeben als bei einer Handmessung.
Einen "Abbruch-Button" würde ich noch vorsehen, damit du die Messung stoppen und resetten kannst bevor alle 4 Lanes stopp gemeldet haben (z.B. bei Fehlstart).
jetzt wo ich weiß was das werden soll gibts 2 Möglichkeiten.
a)
Die Erste wie schon Micha und noiasca schrieb ohne RTC. Die Resonatorgenauigkeit sollte reichen für den kurzen Messzeitraum. Kannst dir auch eine Arduino Chinaclone mit Quarz suchen.
Du programmierst einen Timer in gewünschter Auflösung und lässt ihn laufen. Die TimerCounter Differenzen, ggf. mit Überläufen, rechnest du in deine gewünschte Zeitangabe um.
b)
Wenn du Spass am basteln hast, kannste auch den RTC 32kHz Takt an einen Timereingang anschließen und auch hier den Timercounter, ggf. mit Überläufen, am Ende auslesen und umrechnen.
Du kannst den 32kHz Takt auch an einen normalen Interruptpin anschließen, PCINTs reicht auch, und lässt im Interrupt einen Zähler hochzählen. Hat den gleichen Endeffekt.
c)
Wenn dir eine Genauigkeit von +/- 4µs reichen nimmste einfach micros().
Hast viele Möglichkeiten zum Ziel und lernst eine Menge.
Die Resonatorgenauigkeit sollte reichen für den kurzen Messzeitraum
Finde ich auch.
Um es sich vorstellen zu können: Eine echte Sekunde dauert 1000 +- 1 Arduino-millis().
Nach 100 Sek zeigt der Arduino evtl. eine ZehntelSekunde anders als die Handgestoppte Zeit. Bei 1000 Sekunden (eine Viertelstunde) kann schonmal eine ganze Sekunde Unterschied zu sehen sein, das ist mehr als bei zwei manuell getriggerten echten Stoppuhren. Wenn man will, kann man also zeigen, dass der Arduino ungenau ist.
Wenn allerdings alle 4 Kanäle auf einem einzigen Arduino gemessen werden, passen die Zeiten relativ zueinander "genau". Zumal die Unterschiede an der hochgenauen Hundertstel klar zu sehen sind.
Die Probleme, wenn ich es realisieren sollte, wären eher mechanischer Art
(spritzwasserdichtes Gehause, ausreichend lesbare Anzeige, zuverlässige Taster (Anschlag-Sensor ?) usw. )
michael_x:
Die Probleme, wenn ich es realisieren sollte, wären eher mechanischer Art
(spritzwasserdichtes Gehause, ausreichend lesbare Anzeige, zuverlässige Taster (Anschlag-Sensor ?) usw. )
Diese Sorge gilt für uns. Der TO muss erstmal das Programm sauber hinbekommen.
Wir würden dabei sicherlich schon an bzw. in Klassen denken.
Der TO sollte zumindestens struct für seine Daten verwenden, so als Hinweis, sonst endet der Sketch im Kaos.
Eine DS3231 Library hat meistens auch eine Funktion um den 32khz Eingang einzuschalten.
Ja, und wenn auch nicht, die Uhr selber kann das.
Ein einsames kleines Bit will geändert werden.
Mit dem Signal einfach auf einen Eingang mit Interrupt in einer Funktion hochzählen.
Muss gar nicht, denn der ATMega328P hat einen Zählereingang an Timer 1
Da Timer1 ein 16 Bit Zähler ist, reicht dann ein Interrupt alle 2 Sekunden
Auch eine Alternative:
Weg mit der RTC
Einen nackten ATMega328p mit einem Uhrenquarz betreiben.
Dann kann die Stoppuhr auch Monate an einer CR2032 laufen. (ohne Display)
combie:
Ja, und wenn auch nicht, die Uhr selber kann das.
Ein einsames kleines Bit will geändert werden.
Ja und initialisiert werden muss diese auch noch, da der TO ja sowieso den DS3231 nutzt, vielleicht benötigt er auch noch Uhrzeit/Datum.. dann lohnt sich ein Lib schon. (ich mache das auch per Hand, da die Libs teils Frequenzen verwürfeln.)
combie:
Muss gar nicht, denn der ATMega328P hat einen Zählereingang an Timer 1
Da Timer1 ein 16 Bit Zähler ist, reicht dann ein Interrupt alle 2 Sekunden
Den verstehe ich jetzt nicht.. ist doch egal wie man es macht, man kann auch T0 nehmen wenn man das Core umschreibt Achja ,also ich finde den DS3231 Perfekt für einen Präzisionstimer.. da kommt kein Uhrenquarz hinterher.