Ich möchte für meinen Arduino Uno Rev3 zu Hobbyzwecken eine Millisekunden-Stoppuhr bauen. Ich möchte nicht auf die Arduino-interne Millisekunden-Zählung zurückgreifen, weil der interne 16 MHz-Taktgeber eine zu große Gangungenauigkeit hat. Auch möchte ich nicht einen externen Takt auf dem Arduino verarbeiten, weil manche Programmbibliotheken (z.B. OneWire) Interrupts und somit die Zählung eines Taktsignal zeitweilig abstellen können.
Meine Idee ist, ein peripheres Modul aufzubauen, das auf dem Takt eines Echtzeit-Moduls basiert. Z.B. dem DS3231 RTC, der unter Anderem ein 32 kHz-Rechtecksignal bereitstellt; Ganggenauigkeit +- 5 ppm. Ein simpler Mikrocontroller sollte in diesem Takt einen Zähler erhöhen, und bei Anfrage des Arduino ausgeben. Ein 32-bit Zähler wäre genügend. Die Schnittstelle vom Mikrocontroller zum Arduino sollte folgende Funktionen unterstützen:
Start-Signal (PinX): Zwischenspeichern des aktuellen Zählerstands in einen Speicher „start“ auf dem Mikrocontroller.
Stopp-Signal (PinY): Zwischenspeichern des aktuellen Zählerstands in einen Speicher „stopp“ auf dem Mikrocontroller.
Übertragung der Speicher „start“ und „stopp“ zum Arduino. Evtl. I2C-Protokoll? Oder was der Arduino Uno Rev3 sonst noch unterstützt.
Zurücksetzen des Zählers auf 0. Per separatem Pin oder anderem Protokoll?
Ein typischer Messvorgang würde so ablaufen:
Die Stoppuhr erhöht den aktuellen Zähler laufend im eingehenden Takt. Der Arduino gibt das Start-Signal an die Stoppuhr. Die Stoppuhr speichert den aktuellen (Start-)Zählerstand. Die Zeit verrinnt. Der Arduino gibt das Stopp-Signal an die Stoppuhr. Die Stoppuhr speichert den aktuellen (Stopp-)Zählerstand. Der Arduino gibt das Kommando zur Übertragung der Zählerspeicher. Die Start- und Stoppzählerstände werden an den Arduino übertragen. Die Differenz der Zähler, die Zeitdauer, wird auf dem Arduino berechnet..
Optional wäre auch ein Abfragen der Zählerstände (Start-Zähler und aktueller Stand) nützlich, während einer laufenden Messung. Das darf dann aber die Bearbeitung eines Stoppsignals nicht verzögern.
Außer mit dem Arduino Uno habe ich keine Erfahrung mit Mikrocontrollern. Mit PC-Programmierung reichlich.
Welchen Mikrocontroller würdet Ihr empfehlen im Hinblick auf die folgenden Randbedingungen:
Programmierung bevorzugt in C oder C++. Zur Not in Assembler.
Kostenlose Entwicklungsumbgebung für Windows 10 sollte es geben.
Programm aufspielen per Arduino Uno Rev3 möglich. (Oder Hardware-Schnittstelle max. 15 EUR)
Ich möchte für meinen Arduino Uno Rev3 zu Hobbyzwecken eine
Millisekunden-Stoppuhr bauen. Ich möchte nicht auf die Arduino-interne
Millisekunden-Zählung zurückgreifen, weil der interne 16 MHz-Taktgeber
eine zu große Gangungenauigkeit hat.
Wie meinen? Das ist zwar kein echter Quarz und nur ein Resonator, aber der hat auch um die 1% Genauigkeit.
Meine Idee ist, ein peripheres Modul aufzubauen, das auf dem Takt eines
Echtzeit-Moduls basiert. Z.B. dem DS3231 RTC, der unter Anderem ein 32
kHz-Rechtecksignal bereitstellt; Ganggenauigkeit +- 5 ppm. Ein simpler
Mikrocontroller sollte in diesem Takt einen Zähler erhöhen, und bei
Anfrage des Arduino ausgeben. Ein 32-bit Zähler wäre genügend. Die
Schnittstelle vom Mikrocontroller zum Arduino sollte folgende Funktionen
unterstützen:
Alles Käse. Löte den Resonator runter und einen genauen Takt drauf, ggf. auch aus einem genauen Quarzozilaltor, der mit VCC/GND versorgt werden muss. Alternativ kann man einen 32,768 kHz Takt in TOSC1 einspeisen und Timer2 damit betreiben. Allerdings wird es dann etwas kniffelig, ein Auflösung von 1ms zu bekommen. Da muss man in Software einiges tricksen.
Außer mit dem Arduino Uno habe ich keine Erfahrung mit Mikrocontrollern.
Man braucht hierfür aber keine ZWEI Mikrocontroller!
Welchen Mikrocontroller würdet Ihr empfehlen im Hinblick auf die
folgenden Randbedingungen:
Programmierung bevorzugt in C oder C++. Zur Not in Assembler.
Praktisch jeder Arduino. Selbst der Nano/Micro reicht.
Kostenlose Entwicklungsumbgebung für Windows 10 sollte es geben.
Arduino.
Programm aufspielen per Arduino Uno Rev3 möglich. (Oder
Hardware-Schnittstelle max. 15 EUR)
Braucht man nicht, weil fast alle Arduinos per USB programmierbar sind.
Man kann auch noch mehr tricksen. Den Resonator am "echten" AVR beim Arduino Uno ablöten und die 16 MHz vom Quarz, welcher den Hilfs-AVR für die USB-Verbindung treibt (U3) auf den Haupt-AVR legen.
U3 Pin 2 (XTAl2) an ZU4 Pin 9 (XTAL1)
Der Quarz hat vermutlich +/-50ppm oder weniger Fehler.
Ich möchte nicht auf die Arduino-interne Millisekunden-Zählung
zurückgreifen, weil der interne 16 MHz-Taktgeber
eine zu große Gangungenauigkeit hat.
Ich glaube, da hast du etwas durcheinander gebracht. Der interne Taktgeber ist in der Tat ungenau, hat aber 8 MHz. Arduino Boards werden aber immer mit einem Keramik Resonator (auch ungenau) oder Quartz angetrieben. Ein normaler 16 MHz Quarz ist nicht weniger genau, als ein 32 kHz Uhrenquarz.
Auch möchte ich nicht einen externen Takt auf dem Arduino verarbeiten,
weil manche Programmbibliotheken (z.B. OneWire) Interrupts und somit
die Zählung eines Taktsignal zeitweilig abstellen können.
Die Timer zählen Takte unabhängig von der Interruptfreigabe. Viele AVR Modelle bieten sogar die Möglichkeit, einen zweiten Quarz extra für diesen Zweck anzuschließen.
Meine Idee ist, ein peripheres Modul aufzubauen, das auf dem Takt eines
Echtzeit-Moduls basiert. Z.B. dem DS3231 RTC, der unter Anderem ein 32
kHz-Rechtecksignal bereitstellt; Ganggenauigkeit +- 5 ppm. Ein simpler
Mikrocontroller sollte in diesem Takt einen Zähler erhöhen, und bei
Anfrage des Arduino ausgeben.
Wenn dein Arduino eine Interruptsperre hat, wird er das Zwischenspeichern des aktuellen Zählerstands verzögert auslösen und daher ebenso die falsche Zeit erhalten. Damit gewinnst du nichts. Mache dir lieber Gedanke, wie du einen internen Timer dazu verwenden kannst.
Der hat sogar eine kalibrierbare RTC mit eigenem 32 kHz Quarz, falls du dazu unbedingt eine RTC verwenden willst. Ich würde allerdings eher einen Timer mit dem 8 MHz Hauptquarz takten, denn das lässt sich leichter auf exakte Millisekunden runter teilen.
Alternativ habe ich auch noch eine Stoppuhr auf ATmega48/88/328 Basis:
http://mino-elektronik.de/fmeter/fm_software.htm#bsp6
Die Zeitbasis kann man ja auf 1 kHz reduzieren und wenn es tatsächlich auf 5 ppm genau sein müßte, kann man einen TCXO verwenden. 10 MHz oder 20 MHz habe ich in der Schublade. Irgendeine Platine dazu müßte ich auch noch haben.
Welchen Mikrocontroller würdet Ihr empfehlen im Hinblick auf die
folgenden Randbedingungen:
...
Nimm einen ATmega328, so wie er auch auf dem einen oder anderen Arduino drauf ist. Der besitzt Timer/Zähler, die du für deinen Zweck nutzen kannst und unabhängig vom Prozessor ist. Das brauchst du nicht extern aufzubauen.
Auch möchte ich nicht einen externen Takt auf dem Arduino verarbeiten,
weil manche Programmbibliotheken (z.B. OneWire) Interrupts und somit die
Zählung eines Taktsignal zeitweilig abstellen können.
Ein typischer Messvorgang würde so ablaufen:
Die Stoppuhr erhöht den aktuellen Zähler laufend im eingehenden Takt.
Der Arduino gibt das Start-Signal an die Stoppuhr. Die Stoppuhr
speichert den aktuellen (Start-)Zählerstand. Die Zeit verrinnt. Der
Arduino gibt das Stopp-Signal an die Stoppuhr. Die Stoppuhr speichert
den aktuellen (Stopp-)Zählerstand
Das kann problemlos ein interner Hardwarezähler des Arduino machen.
Man konnte versuchen einen TXCO zu nutzen als Taktquelle für den Arduino aber die laufen mit 3.3V.
Leider hat niemand meine Frage nach dem geeigneten, simplen Mikrocontroller beantwortet.
Manche zweifelten den Sinn einer besseren Genauigkeit als die Arduino-interne
Millisekunden-Zählung an oder verwechselten Auflösung mit Genauigkeit.
Der Arduino Uno Rev3 speist, ab Werk, den Millisekunden-Zähler über einen 16 MHz ceramic resonator (CSTCE16M0V53-R0). Das läuft über den TCNT0 – Timer/Counter Register des ATmega328P und die Timer/Counter0 overflow interrupt service routine. Dieser Taktgeber hat laut Datenblatt (https://www.mouser.de/datasheet/2/281/p16e-522700.pdf) eine mögliche Ungenauigkeit von "Initial Frequency Tolerance ±0.5%" also 5000 ppm. Es mag viele Anwendungen geben, für die das genau genug ist. Ich wollte aber für meine Hobby-Lernzwecke eben eine genauere Stoppuhr implementieren. Der von mir avisierte DS3231 RTC hat eine mögliche Ungenauigkeit von 5 ppm - tausend mal besser.
Manche haben vorgeschlagen, das Arduino-Board "aufzubohren", um einen genaueren Takt zu haben. Das ist im Prinzip ein konstruktiver Beitrag; aber das war gar nicht meine Fragestellung.
(1.) Ich will eine Lösung ohne einen Umbau des Arduino.
(2.) ist da noch die Sache mit dem Interrupt und Zählerblockiern. Selbst wenn der Arduino-Oszillator perfekt wäre, könnten eingebundene Libraries (OneWire) über eine Interruptsperre den Millisekunden-Zähler verfälschen. Das kann man umgehen mit meinem Lösungsansatz des externen Zählers.
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise zu lange sperrt, geht der Millisekunden-Zähler falsch. Wer es nicht glaubt, dass der Zähler von den Interrupts abhängt, lasse bitte mal folgenden Code laufen auf einem Arduino Uno Rev3. Einmal mit auskommentiertem //noInterrupts() und einmal mit aktivierten noInterrupts():
(1.) Ich will eine Lösung ohne einen Umbau des Arduino.
Dann kauf eben einen mit Quarz der Due hat einen. (- soeben wurde ein weiterer Controller genannt.)
Du bist gerade in der "nicht ein Geisterfahrer sondern hunderte" Situation.
Die Lösung ist nicht mehr Controller sondern besser programmieren.
Deine gezeigte Routine hat kein Problem mit dem internen Timer. Der stimmt. Du fragst ihn nur unregelmäßig ab, da die serielle Ausgabe eine variable Zeit dauert. (Mehr oder weniger Zeichen)
Wenn du ihn mit einem Interrupt abfragst, das Ergebnis speicherst und dann ausgibst, ist das alles kein Problem.
Der due bietet sogar DMA. Damit kannst du den seriellen Datentransfer aufrecht erhalten, während dieser seriell sendet, ohne dass der Prozessor irgend etwas tun muss.
Stell dir das als drei Blöcke vor:
Block1 zählt genau die Zeit
Block2 (Interrupt) liest Zeitstempel aus Block1 aus und speichert diese
Block3 versendet die gespeicherten Daten über die serielle Schnittstelle
Die Blöcke laufen parallel und haben keinen zeitlichen Einfluss aufeinander.
Als weiteren Irrweg kannst du auch ein RTC Modul verwenden. Die haben teilweise einen Interrupt eingang und liefern dafür einen Zeitstempel.
Oder wir haben deine Anforderungen alle falsch verstanden und du willst eine Stoppuhr mit max einer Millisekunde Messzeitraum und 5ppm Auflösung bauen. Dann lautet deine Lösung TDC.
Zusammenfassung: komm aus deiner Sackgasse und dir wird geholfen.
Leider hat niemand meine Frage nach dem geeigneten, simplen
Mikrocontroller beantwortet.
Was soll man auch jemandem antworten, dessen gesamte geistige
Komfortzone nur aus "Adruinos" besteht?
Eine ms-Stoppuhr koennte schon ein uralter 4 bit-Controller von
Oki stemmen, und wuerde sich dabei noch langweilen.
Wenn es leistungsmaessig sparsam zugehen soll, waere ein MSP430FG4617
(m)ein guter Kandidat. Der kann LCD(-onGlass) direkt treiben.
Leider kein billiges Vergnuegen. Von Atmel gaebe es den ATMEGA169,
und von ST diverse STM8 die das auch koennten.
Fuer das uebliche LCD waere ein kleiner PIC mit einem 4096 kHz Quarz
meine erste Wahl. Bei der Auswahl auf einen internen Oszillator achten.
Den Quarz braucht es "nur" zur genauen Messung. Nach der Messung
schaltet man wieder auf den internen 30 kHz Takt.
Weitere externe Komponenten braucht es da ueberhaupt nicht.
Was willst du eigentlich mit "OneWire" an einer Stoppuhr?
Aus ueblichen RTCs kommt auch kein 1 ms Takt?
Leider hat niemand meine Frage nach dem geeigneten, simplen
Mikrocontroller beantwortet.
Hallo,
meine erste Wahl wäre ATMega1284P. Und kein Arduino jeglicher Art. 16k SRAM, JTAG-Debug.
Manche zweifelten den Sinn einer besseren Genauigkeit als die
Arduino-interne
Millisekunden-Zählung an oder verwechselten Auflösung mit Genauigkeit.
Der Arduino Uno Rev3 speist, ab Werk, den Millisekunden-Zähler über
einen 16 MHz ceramic resonator (CSTCE16M0V53-R0). Das läuft über den
TCNT0 – Timer/Counter Register des ATmega328P und die Timer/Counter0
overflow interrupt service routine. Dieser Taktgeber hat laut Datenblatt
(https://www.mouser.de/datasheet/2/281/p16e-522700.pdf) eine mögliche
Ungenauigkeit von "Initial Frequency Tolerance ±0.5%" also 5000 ppm.
Das ist wohl zu viel.
Wenn du wirklich genau willst, bei Mouser gibt es TG2520SMN 16.0000M-MCGNNM0 mit nur 0,5 ppm, 16 MHz, kostet nur 0,85 € pro Stück. Allerdings braucht es 2,8-3,3 Volt Speisung und Ausgang ist mit "Clipped sine wave". Deshalb ist zusätzlich noch 3V oder 3V3 Spannungsregler (das wird auch auf Frequenzstabilität positiv wirken) notwendig. Und für Ausgang noch zusätzlich AHCT-Invertor, evtl. mit Schmitt-Trigger, so wie 74AHCT1G14.
meine erste Wahl wäre ATMega1284P. Und kein Arduino jeglicher Art. 16k
SRAM, JTAG-Debug.
Gibt es einen besonderen Grund fuer 128 k Flash und 16 k RAM?
Ein Glass-LCD kann er ja wohl nicht direkt treiben.
Und JTAG gibt es schon fuer Controller die einige Nummern kleiner sind.
Wenn man es fuer so etwas simples, wie einen 1 kHz-Zaehler braucht.
Wenn du wirklich genau willst, bei Mouser gibt es TG2520SMN
16.0000M-MCGNNM0 mit nur 0,5 ppm, 16 MHz, kostet nur 0,85 € pro Stück.
Welchen positiven Effekt, sollte "0,5 ppm" bei einer Uhr, die gerade
mal 1 ms aufloesen kann, haben?
Messzeiten von einem Jahr?
Manche zweifelten den Sinn einer besseren Genauigkeit als die
Arduino-interne Millisekunden-Zählung an
Du sollst ja auch nicht den ms-Zähler der Arduino-Umgebung nutzen, sondern einen Hardwarezähler eines Timers.
(2.) ist da noch die Sache mit dem Interrupt und Zählerblockiern. Selbst
wenn der Arduino-Oszillator perfekt wäre, könnten eingebundene Libraries
(OneWire) über eine Interruptsperre den Millisekunden-Zähler
verfälschen. Das kann man umgehen mit meinem Lösungsansatz des externen
Zählers.
1wire kann man auch anders implementieren, beispielsweise über einen UART. Dann können die Interrupts problemlos aktiv bleiben, weil der UART das Timing macht.
Leider hat niemand meine Frage nach dem geeigneten, simplen
Mikrocontroller beantwortet.
Du kannst gerne einen weiteren Arduino verwenden oder der Einfachheit wegen, einen einzelnen ATmega/tiny - meinetwegen auch mit dem Bootloader des UNO R3.
Ein sehr günstiger TCXO wurde Dir genannt, die 3 V Versorgungsspannung wird mit einer Zenerdiode oder weissen LED stabilisiert und das Ausgangssignal ist groß genug, um damit einen ATxyz kapazitiv eingekoppelt zu takten.
Ein 32-bit Zähler wäre genügend. Die Schnittstelle vom Mikrocontroller
sollte folgende Funktionen unterstützen:
Start-Signal
Stopp-Signal
Übertragung der Speicher „start“ und „stopp“
Zurücksetzen des Zählers auf 0
Der SN74LV8154 hat nur einen Zwischenspeicher, aber soweit ich sehe, kannst du einfach bei 0 starten. Sechs Eingänge und acht Ausgänge; wenn dein Arduino nicht genügend freie GPIOs hat, kannst du die Zahl mit einem Decoder (74xx138) und/oder einem Shift-Register (74xx165) verringern.
Wer es nicht glaubt, dass
der Zähler von den Interrupts abhängt
Das hat doch hier nie auch nur ein einziger bezweifelt, daß unbedarfte Programmierung Seiteneffekte haben kann und wird. Unsinnig häufige serielle Ausgaben sind der Todesstoß für jeden Programmablauf.
Die Arduino-Libs sind darauf optimiert, daß ein Anfänger damit schnell zurecht kommt. Sie sind jedoch nicht auf möglichst geringe Seiteneffekte und CPU-Last optimiert.
Für 1-wire gibt es z.B. Interrupt basierte Lösungen für den AVR, die keine riesen CPU-Zeit vergeuden.
Wie schon vorgeschlagen wurde, gibt es Quarzoszillatoren entsprechender Genauigkeit. Der µC-Typ und die Firmware haben bei sinnvoller Strukturierung keinerlei Einfluß auf die Genauigkeit.
TG2520SMN16.0000M-MCGNNM0 mit nur 0,5 ppm, 16 MHz, kostet nur
0,85 € pro Stück.
Eindeutig diesen. Weil viel billiger und trotzdem genauer.
Ein 32-bit Zähler wäre genügend
Start-Signal (PinX)
Stopp-Signal (PinY)
Übertragung der Speicher zum Arduino. Evtl. I2C-Protokoll?
Vorzugsweise UART; ist einfacher zu programmieren.
Zurücksetzen des Zählers auf 0. Per separatem Pin oder anderem
Protokoll?
Protokoll, weil man sowieso ein Mini-Protokoll für die Übertragung der Speicher und die optionale Abfrage braucht.
Die Differenz der Zähler, die Zeitdauer, wird auf dem Arduino berechnet
Das geht nach ca. 7 Wochen Dauerbetrieb schief (32-Bit Overflow).
Optional wäre auch ein Abfragen der Zählerstände (Start-Zähler und
aktueller Stand) nützlich, während einer laufenden Messung.
Kein Problem für den uC auf dem Modul.
Außer mit dem Arduino Uno habe ich keine Erfahrung mit Mikrocontrollern.
Mit PC-Programmierung reichlich.
Welchen Mikrocontroller würdet Ihr empfehlen im Hinblick auf die
folgenden Randbedingungen:
Programmierung bevorzugt in C oder C++. Zur Not in Assembler.
Kostenlose Entwicklungsumbgebung für Windows 10 sollte es geben.
Programm aufspielen per Arduino Uno Rev3 möglich.
Pins für: Start, Stopp, Takt, serielle Übertragung der Zählerstände.
Gute Verfügbarkeit in Deutschland, preiswert.
STM32C011J4M6 oder J6M6. Bei Reichelt 1.35€, bei Digikey 0.69€. Die 32-Bit CPU ist keinen Verschwendung, weil man für die 32-Bit Zähler nicht aufpassen muss.
SO-8 Gehäuse; das geht von der Pinanzahl plus-minus-Null auf
wird zu 100% in C programmiert; GCC gibt es direkt bei ARM
kann die Millisekunden problemlos per Interrupt zählen
braucht ansonsten keine Interrupts
muss nicht geflasht werden, braucht kein Programmiergerät. Das Programm kann über die vorhandene UART-Verbindung vom Arduino ins RAM geladen werden. Oder per USB-UART Adapter vom PC aus.
SO-8 Gehäuse; das geht von der Pinanzahl plus-minus-Null auf
Das meinst Du jetzt ernst?
Der TO ist der Meinung, ein externes Taktsignal könne von einem UNO R3 nicht schnell genug behandelt werden. Wie will er denn sicherstellen, daß die Abfrage des peripheren Zählers im ms-Raster funktioniert? Die zeitgerechte Triggerung von 'start' und 'stopp'-Signalen kann ja auch durch interne Blockaden behindert werden.
Vielleicht ist es doch einfacher, auf ein RP2040 Pico-Board umzusteigen, das fix und fertig günstiger ist als jede Zusatzschaltung. Erfahrungsgemäß haben diese günstigen Boards einen recht genau laufenden Quarz mit <= 5 ppm ohne extra Abgleich. Über den Temperaturbereich wurde zwar nichts gesagt, aber die Drift des Oszillators ist bei 'menschengerechten' Umgebungstemperaturen nicht sehr groß.
Er redet ja immer nur von Arduino Uno Rev 3 - es ist ein Atmega328P - der hat 3 Timer. Die werden auch beim stoppen der jeglicher ISR durch seine "One-Wire Bibliothek" nicht gestoppt - die Timer laufen weiter. Er kann ein Überlauf verpassen, ja - aber dann vergleicht man halt die Timercounter...
1ms bei 5ppm - da lacht dich der 328er aus. Ernsthaft... Schau über deinen "Arduino" Tellerand hinaus - such dir das DB und leg los.
Dieser Taktgeber hat laut Datenblatt
(https://www.mouser.de/datasheet/2/281/p16e-522700.pdf) eine mögliche
Ungenauigkeit von "Initial Frequency Tolerance ±0.5%" also 5000 ppm. Es
mag viele Anwendungen geben, für die das genau genug ist. Ich wollte
aber für meine Hobby-Lernzwecke eben eine genauere Stoppuhr
implementieren. Der von mir avisierte DS3231 RTC hat eine mögliche
Ungenauigkeit von 5 ppm - tausend mal besser.
Manche haben vorgeschlagen, das Arduino-Board "aufzubohren", um einen
genaueren Takt zu haben. Das ist im Prinzip ein konstruktiver Beitrag;
aber das war gar nicht meine Fragestellung.
(1.) Ich will eine Lösung ohne einen Umbau des Arduino.
(2.) ist da noch die Sache mit dem Interrupt und Zählerblockiern. Selbst
wenn der Arduino-Oszillator perfekt wäre, könnten eingebundene Libraries
(OneWire) über eine Interruptsperre den Millisekunden-Zähler
verfälschen. Das kann man umgehen mit meinem Lösungsansatz des externen
Zählers.
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise zu lange
sperrt, geht der Millisekunden-Zähler falsch. Wer es nicht glaubt, dass
der Zähler von den Interrupts abhängt, lasse bitte mal folgenden Code
laufen auf einem Arduino Uno Rev3. Einmal mit auskommentiertem
//noInterrupts() und einmal mit aktivierten noInterrupts():
Das stimmt auch. Der Grund dafür ist aber nicht, dass der Timer nicht weiterlaufen würde! Der Grund dafür ist, dass die Arduino-IDE den Timer so programmiert, dass er Mikrosekunden zählt, um damit delayMicroseconds() umsetzen zu können. Und da auf dem Atmega328P dieser Timer ein 16-Bit-Zähler ist, läuft er nach 65ms über und erzeugt einen Interrupt. Und wenn die Interrupts gesperrt sind, dann werden diese Überläufe nicht gezählt, und dadurch geht millis() falsch. Schau dir den entsprechenden Quellcode gerne einmal unter C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\wiring.c an.
Eine möglich Lösung für deine Stoppuhr wäre also, anstelle eines zweiten Atmega328P eine genaue externe 1kHz-Taktquelle an deinen Arduino Uno an Pin D5 anzuschließen, und diesen Pin als "T1" zu konfigurieren, so dass er Timer 1 hochzählt. Der würde dann nur alle 65 Sekunden überlaufen und einen Interrupt auslösen, und dann hättest du weitere 65 Sekunden um darauf zu reagieren bevor der nächste Interrupt den vorherigen "überschreibt". Und dein Stoppuhr-Signal würdest du an Pin D8 anschließen. Diesen Pin kann man als "ICP1" konfigurieren. Dann merkt sich bei einem Signal auf diesem Pin der Atmega328P des Arduino den aktuellen Stand des Timers 1 in einem Register (auch wenn Interrupts gesperrt sein sollten!) und fordert einen Interrupt an. Und wenn dieser Interrupt behandelt wird, kannst du den Wert des Registers auslesen und bekommst die genaue Millisekunde, zu der das Signal aufgetreten ist, selbst wenn deine Interruptroutine erst etwas verzögert aufgerufen werden sollte.
So eine Lösung halte ich für einfacher machbar als diejenige mit zwei Mikrocontrollern, vor allem wenn du noch dabei bist, dich in die Hardware einzuarbeiten.
Das ist wirklich mal eine schräge Idee (wenn offenbar auch eine recht zeitgemäße).
Zusammenfassend gilt: du brauchst keinen zusätzlichen Mikrocontroller suchen, der auf dem Arduino verbaute µC kann das locker und luftig. Denn bei den üblichen 16MHz Taktfrequenz kann der dank RISC-Architektur pro Millisekunde etwa 16'000 Maschinenbefehle ausführen. Es kann bestenfalls sein, dass er durch schlechte Software oder blockierende Bibliotheken an der zeitgerechten Ausführung gehindert wird. Dann sollte man sich aber eher die schlecht programmierte Software vorknüpfen, als ein Coprozessorsystem zu etablieren.
keine Erfahrung mit Mikrocontrollern.
Wie gesagt: das Datenblatt deines µC enthält den Weg zur Lösung der Aufgabe.
Dass man für eine ultra genau gehende Uhr eine entsprechend ultra genaue Taktquelle braucht, steht dann auf einem anderen Blatt.
daß die Abfrage des peripheren Zählers im ms-Raster funktioniert? Die
zeitgerechte Triggerung von 'start' und 'stopp'-Signalen kann ja auch
durch interne Blockaden behindert werden.
Eine möglich Lösung für deine Stoppuhr wäre also, anstelle eines zweiten
Atmega328P eine genaue externe 1kHz-Taktquelle an deinen Arduino Uno an
Pin D5 anzuschließen, und diesen Pin als "T1" zu konfigurieren, so dass
er Timer 1 hochzählt.
und damit der zählende Atmega nicht überläuft kann man einen dritten Atmega an den ersten hängen und den Pin überlauf Interrupt dorthin geben, dann kann dieser damit gezählt werden. Damit hast du einen echten 64 bit Zähler. Diesen Wert kann dann er erste Atmega per SPI auslesen, und über die serielle Schnittstelle den korrekten Wert der Stoppuhr ausgeben, wenn der Trigger Pin TC1B auslöst.
und damit der zählende Atmega nicht überläuft kann man einen dritten
Atmega an den ersten hängen und den Pin überlauf Interrupt dorthin
geben, dann kann dieser damit gezählt werden. Damit hast du einen echten
64 bit Zähler. Diesen Wert kann dann er erste Atmega per SPI auslesen,
und über die serielle Schnittstelle den korrekten Wert der Stoppuhr
ausgeben, wenn der Trigger Pin TC1B auslöst.
Ja.. also ich wäre da für einen vierten Atmega. Der Überwacht ob zwischen Atmega 1 und 3 aktuell keine SPI Tätigkeit stattfindet. Nicht das genau in den acht Takten der Wert überläuft und nicht gezählt wird - nur zur Sicherheit... versteht sich. ;-)
und damit der zählende Atmega nicht überläuft kann man einen dritten
Atmega an den ersten hängen und den Pin überlauf Interrupt dorthin
geben
Wer hat nicht schon von einem High-Performance Arduino cluster geträumt.
Wenn man die dann auch noch noch mehrdimensional vernetzt…
… das gibt 'ne Stoppuhr wie sie die Welt noch nicht gesehen hat.
Eine möglich Lösung für deine Stoppuhr wäre also, anstelle eines zweiten
Atmega328P eine genaue externe 1kHz-Taktquelle an deinen Arduino Uno an
Pin D5 anzuschließen, und diesen Pin als "T1" zu konfigurieren, so dass
er Timer 1 hochzählt.
Du kannst natürlich dazu auch das SQW-Signal einen DS3231 verwenden. Bei 32768Hz liefert es alle ~30uS einen Zählimpuls, und so genau ließe sich dann auch die Millisekunde bestimmen. Damit würde Timer 1 zwar schon alle 2 Sekunden überlaufen. Ich kenne aber keine Arduino-Bibliothek, die die Interrupts derart lange sperren würde.
Ich hatte zuerst mit 80C51 angefangen, konkret AT89C2051. Der hat nur 2 16Bit-Timer. Ein Timer ging für die UART als Baudratengenerator drauf, blieb also nur noch einer übrig. Den konnte man teilen und hatte somit 2 * 8Bit Timer/Counter. Damit war es dann kein Problem, einen Frequenzmesser zu bauen. Der Zeitbasisteiler liefert somit alle 256 CPU-Zyklen einen Interrupt zum Zählen der höherwertigen Bytes. Der andere 8Bit Timer zählt das Eingangssignal. Der C51 Compiler hat sehr kompakten Code erzeugt, so daß kein Interrupt verloren ging. Durch das float Format war die Auflösung auf 6 Digits begrenzt. Das Ergebnis wurde gemultiplext angezeigt und auch über die UART gesendet.
Später habe ich dann das Zahlenformat mit Assembler aufgebohrt. Die Rechnung f_in = f_cpu * count_in / count_cpu ist ja nicht zeitkritisch.
Es ist also kein Problem, mit nur 2 8Bit-Timer/Counter beliebig genau zu messen. Die Zählweite ist nur durch den verfügbaren SRAM limitiert.
Vermutlich ist dieser dir nicht simpel genug. Schade, denn der hat sogar einen seriellen Bootloader (einige Modelle der Serie auch USB) ab Werk dabei und kann mit der Arduino IDE programmiert werden.
Ich will eine Lösung ohne einen Umbau des Arduino (Uno)
Dann nimm doch einen ATmega328 mit Quarz. Simpler wird es nicht. Statt Quarz kannst du auch einen hoch präzisen Oszillator als Taktquelle verwenden.
Selbst wenn der Arduino-Oszillator perfekt wäre, könnten
eingebundene Libraries (OneWire) über eine Interruptsperre den
Millisekunden-Zähler verfälschen.
Sehe ich nicht so. Die Timer/Counter zählen von ganz alleine ohne Software. Du nimmst z.B. einen 8,192 MHz Quarz (oder Taktgeber), stellst den Prescaler des 16 Bit Timer/Counter auf 1024 und lässt ihn frei laufend die Takte zählen. Das TCNT Register zählt dann acht Takte pro Millisekunde.
Mit der "Input Capture" Funktion kannst du den aktuellen Zählerstand bei einem Signal von einem Pin in ein ICR Register kopieren. Auch das passiert ohne Software. Danach hast du alle Zeit der Welt, dieses Register per Software auszulesen.
Beim Auslesen teilst du den Wert aus dem Register durch 8, so kommst du auf glatte Millisekunden.
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise
zu lange sperrt, geht der Millisekunden-Zähler falsch.
Wer es nicht glaubt
Niemand zwingt dich, die millis() Funktion zu benutzen.
Von den etlichen Beiträgen kann ich aus Zeitgründen nur auf manche eingehen.
Zum Verständnis der Verfälschung der eingebauten Arduino-internen Zeitzählung durch Interruptsperren möchte ich das Problem nochmals zahlenmäßig darlegen:
Der Oszillator-Takt (16 MHz) wird in den 8-bit Timer/Counter Register TCNT0 eingespeist in einem Prescaler-Teilverhältnis von 64:1. Wenn dieses Register überläuft, also nach 64 * 256 Oszillator-Zyklen, wird per Interrupt die Service Routine TIMER0_OVF_vect aufgerufen. In dieser werden die internen Zählervariablen für die millis() und micros() entsprechend aufgestockt. Wenn per noInterrupts() der Aufruf von TIMER0_OVF_vect blockiert wird für weniger als 64 * 256 Zyklen, ist das unproblematisch. Das entsprechende Interruptflag wird gesetzt und nach Ablauf der Interruptsperre wird TIMER0_OVF_vect aufgerufen. Dauert die Sperre länger als 2 x 64 x 256 Zyklen, werden zwei oder mehr TIMER0_OVF_vect-Aufrufe ausgelassen, aber nur einer nachgeholt. Dann wird die Zeitzählung falsch. Am Interruptflag lässt sich nicht ablesen, wie viele Interrupts ausgelassen wurden.
Eine möglich Lösung für deine Stoppuhr wäre also, anstelle eines zweiten
Atmega328P eine genaue externe 1kHz-Taktquelle an deinen Arduino Uno an
Pin D5 anzuschließen, und diesen Pin als "T1" zu konfigurieren, so dass
er Timer 1 hochzählt.
Du nimmst z.B. einen 8,192 MHz Quarz (oder Taktgeber), stellst
den Prescaler des 16 Bit Timer/Counter auf 1024 und lässt ihn frei
laufend die Takte zählen. Das TCNT Register zählt dann acht Takte pro
Millisekunde.
Von Sebastian W. (wangnick) und später von Sherlock (rubbel-die-katz) wurde ein Ansatz vorgeschlagen, den ich mal ausprobieren werde, wenn ich einen externen Taktgeber gekauft habe.
Der Vorschlag ist den 16-bit Timer/Counter TCNT1 des Arduino zu verwenden und in mit einem akkuraten externen Takt zu versehen. Bei dem von mir avisierten Taktgeber DS3231 RTC mit 32 kHz würde ein Überlauf erst nach 2 Sekunden stattfinden. D.h. wenn eine Interruptsperre nicht länger als 2 Sekunden geht - und ansonsten wäre etwas sehr faul im System - würden keine Zählerverluste auftreten.
Was man wissen muss, ist dass der TCNT1 für die PWM-Funktion der Pins 9 und 10 und in der Servo-Library verwendet wird. Solange man die nicht braucht, geht der Ansatz wohl. Sonst nicht.
Von den vorgeschlagenen Mikrocontrollern waren manche ‚überqualifiziert‘ für die einfache Zählaufgabe.
Der SN74LV8154 hat nur einen Zwischenspeicher, aber soweit ich sehe,
kannst du einfach bei 0 starten. Sechs Eingänge und acht Ausgänge; wenn
dein Arduino nicht genügend freie GPIOs hat, kannst du die Zahl mit
einem Decoder (74xx138) und/oder einem Shift-Register (74xx165)
verringern.
Clemens L. (c_l) hat einen sehr simplen Chip genannt, den SN74LV8154 Zweifach-Binärzähler, 16 Bit. Fast genau was ich wollte, wenn er direkt seriell mit dem Arduino kommunizieren könnte.
STM32C011J4M6 oder J6M6. Bei Reichelt 1.35€, bei Digikey 0.69€. Die
32-Bit CPU ist keinen Verschwendung, weil man für die 32-Bit Zähler
nicht aufpassen muss. ...
Bauform B. (bauformb) hat den Mikrocontroller STM32C011J4M6 vorgeschlagen. Der scheint die von mir gestellten Anforderungen zu erfüllen (siehe meine ursprüngliche Anfrage). Ich muss das Datenblatt noch genauer studieren. Bemerkenswert, dass es den in der Familienpackung schon für 0,287 € pro Stück gibt. Einzeln 1,52 €.
Ich hatte zuerst mit 80C51 angefangen, konkret AT89C2051. ...
Peter D. (peda) schlägt den AT89C2051 vor. Sieht interessant aus. Da werde ich mal prüfen, wie ich ein Programm aufspielen würde. Ich will eigentlich keine Programmier-Hardware kaufen.
Diskussion sinnlos - er hat sich auf die "Zwei-Chip Version" so eingeschossen das er den Wald vor Bäumen nicht sieht - und das Ziel liegt wirklich, wirklich so nah vor ihm. Ich bin raus....
IMER0_OVF_vect-Aufrufe ausgelassen, aber nur einer nachgeholt. Dann
wird die Zeitzählung falsch. Am Interruptflag lässt sich nicht ablesen,
wie viele Interrupts ausgelassen wurden.
NEIN! Du zählst nicht die Anzahl der Interrupte sondern die Counter - und wenn du das Ding ne Sekunde laufen läst und der CPU dabei zu 105% ausgelastet ist - du zählst den Counter!!!!! Dein einzigster Gegner ist der BOF. Wenn der Timer auf 1ms läuft dann kannst du den 65 Sekunden laufen lassen ohne ihn zurück zu setzen.
Manchmal fragt man sich echt - mit dem 328p fliegen Drohnen GPS gestüzt, da laufen zeitkritisch 3D Drucker mit Marlin und Klipper und hier wird wegen nem simpelsten Timer nen zweiter MC genommen - unbegreiflich.
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise zu lange
sperrt, ...
Daran wäre der Programmierer Schuld, der das Ding in die Welt gesetzt hat und derjenige, der diese Bibliotheksfunktion in seinem Code nutzt. Natürlich kann einem immer der Himmel auf den Kopf fallen ...
Daran wäre der Programmierer Schuld, der das Ding in die Welt gesetzt
hat und derjenige, der diese Bibliotheksfunktion in seinem Code nutzt.
Dass die Bibliotheken im Arduino Umfeld teilweise richtig schlecht sind ist ja nichts Neues. Der Fokus liegt da auf "einfach" oder zumindest "scheinbar einfach".
Bei dem
von mir avisierten Taktgeber DS3231 RTC mit 32 kHz würde ein Überlauf
erst nach 2 Sekunden stattfinden.
Der liefert aber nicht 32 kHz, sonder 32,768 kHz.
Aus dem Datenblatt:
the 32kHz pin is enabled and outputs a 32.768kHz square-wave signal
Mit welcher Zauberei willst du daraus exakte Millisekunden ableiten?
Nun, wirklich exakt geht natürlich nicht. Aber hinreichend exakt geht wahrscheinlich schon. Der Fehler durch den unvermeidlichen Jitter wegen der nicht ganzzahlig teilbaren Frequenzen addiert sich halt zum Grundfehler der Taktquelle.
Muß man halt einfach ausrechnen, ob man damit noch im zulässigen Bereich ist.
Wobei mir in dem ganzen Thread nicht wirklich klar geworden ist, wie genau es am Ende wirklich sein muss und schon garnicht, warum es so genau sein muss...
Gibt es einen besonderen Grund fuer 128 k Flash und 16 k RAM?
Ja. Grund ist so: es ist billiger, gleich mehrere IC zu kaufen. Auch es ist leichter, immer möglichst mit gleichen zu tun zu haben. Deshalb nehme ich fast immer ATMega1284P, es sei denn ich brauche mehr Pins oder USARTs usw.
Ein Glass-LCD kann er ja wohl nicht direkt treiben.
Das ist ja schlechteste von allen Anzeigen, die ich überhaupt kenne. Deshalb ist Manko nicht zu groß. Lieber LED-Anzeige, oder auch ILI9341-Bildschirm mit Hintergrundbeleuchtung.
Was man wissen muss, ist dass der TCNT1 für die PWM-Funktion der Pins 9
und 10 und in der Servo-Library verwendet wird. Solange man die nicht
braucht, geht der Ansatz wohl. Sonst nicht.
Was man wissen muß, der Arduino braucht die ganze Zeit eine Versorgungsspannung. Solange man diese nicht woanders braucht, geht der Ansatz wohl. Sonst nicht.
Bei dem
von mir avisierten Taktgeber DS3231 RTC mit 32 kHz würde ein Überlauf
erst nach 2 Sekunden stattfinden. D.h. wenn eine Interruptsperre nicht
länger als 2 Sekunden geht
Ach so. Es muß Millisekunden genau sein und aber 2 s Verzögerung stören bei der Stoppuhr nicht.
Der Typ Mikrokontroller, den Du letztendlich auswählst, ist egal.
Die haben alle programmierbare Teiler.
An dieser Stelle geht es um die Peripherie und sonst Garnichts.
Wichtig ist nur der Taktgeber. Üblicherweise ein Quarz. Hier variieren die Genauigkeiten und natürlich die Preise - und zwar stark.
Low- und Least-Cost-Lösungen haben eine entsprechende Genauigkeit und gehen zwischendurch auch mal etwas spazieren (Grundgenauigkeit und vor allem Temperaturdrift).
Ein richtig guter, am besten ein geheizter Quarz, kann aber schon mal der Geldbörse eine Schlankheitskur verpassen.
Aber wie gesagt: Solange Du den Mikroprozessor selbst innerhalb seiner Spezifikationen betreibst ist der Name völlig unwichtig.
Der liefert aber nicht 32 kHz, sonder 32,768 kHz.
Mit welcher Zauberei willst du daraus exakte Millisekunden ableiten?
Nun, wirklich exakt geht natürlich nicht. Aber hinreichend exakt geht
wahrscheinlich schon.
Außerdem: selbst wenn du einen perfekten 1kHz Takt hast und Input Capture benutzt, kann der Zählerstand bis 999.9µs falsch sein. Man könnte sogar behaupten, der 32768Hz Takt ist ca. 32-fach genauer.
the 32kHz pin is enabled and outputs a 32.768kHz square-wave signal
Mit welcher Zauberei willst du daraus exakte Millisekunden ableiten?
Ganz einfach: Man muß oft durch 32 teilen und ab und zu durch 33 - jede
Millisekunde :-)
Das klappt aber dann nur im Mittel bzw. bei langen Zeiten. Bei einer kurzen Zeit - sagen wir 10ms - ist der Fehler dann schon eheblich gegenüber der angeblichen Genauigkeit von 5ppm.
Wenn man wie der TO 1,000000ms Auflösung bei gleichzeitig hoher Genauigkeit will, bringt einen die DS3231 nicht weiter. Dann muß es schon ein Taktgeber sein, dessen Frequenz ganzzahlig durch 1000 teilbar ist.
Aber der ganze Thread ist natürlich hochgradiger Schwachsinn. Schon der ATMega328 hat 3 (drei!) Hardwaretimer. Selbst wenn man sich dann darauf versteift, das Arduino-Framework zu verwenden und das dann einen (!) Timer mißhandelt, hat man immer noch zwei weitere. Wie ein Vorredner schon bemerkte: das "Problem" braucht nicht mehr µC, sondern weniger dämliche Programmierung.
Das klappt aber dann nur im Mittel bzw. bei langen Zeiten. Bei einer
kurzen Zeit - sagen wir 10ms - ist der Fehler dann schon eheblich
gegenüber der angeblichen Genauigkeit von 5ppm.
Bei 10 ms ist der Fehler (Jitter) 0,3%, was eigentlich nicht schlecht und besser als die ms Auflösung des 1 kHz Taktes ist.
Wie geschrieben können <= 5 ppm erst ab 200 s erreicht werden.
Aber der ganze Thread ist natürlich hochgradiger Schwachsinn.
Da stimmen WIR Dir alle zu. Offensichtlich hat der TO nur Erfahrung, LIBs auf einem PC zusammenzuklicken. Hier die Arduino IDE zu verwenden und sich auf das zu versteifen, was man alles nicht machen darf, ist eh der verkehrte Weg.
Wenn man wie der TO 1,000000ms Auflösung bei gleichzeitig hoher
Genauigkeit will
Dann ist immer noch die Frage, ob man diese ultraexakte 1,000000ms tatsächlich überhaupt braucht.
Denn die Abtastung mit exakt 1,000000ms ergibt bezogen auf das Start-Stop-Signal hat ja bereits einen Jitter von +-500,000µs (im Grunde sogar fast +-1ms, denn es könnte ja sein, dass die beiden Signale zum jeweils ungünstigsten Zeitpunkt abgetastet werden). Insofern ist diese exakte 1,000000ms sowieso nur Augenwischerei.
Wenn dann so ein Jitter tolerabel ist, dann muss letztendlich einfach nur die reale Abtastzeit kleiner oder gleich 1ms sein.
Und wenn der Jitter nicht tolerabel ist, dann reicht eben auch eine Abtastung mit ultragenauen 1,000000 ms nicht aus. Dann muss das Start-Stop-Signal deutlich schneller abgetastet werden und/oder die Uhr deutlich höher auflösen.
Und wenn der Jitter nicht tolerabel ist, dann reicht eben auch eine
Abtastung mit ultragenauen 1,000000 ms nicht aus. Dann muss das
Start-Stop-Signal deutlich schneller abgetastet werden und/oder die Uhr
deutlich höher auflösen.
Was mit der Input Capture Funktion spielend möglich ist, so man sie denn beherrscht. Damit kann man die Eingangssignale mit dem vollen Timer/Oszillatortakt auflösen, beim vielgepriesenen Arduino Uno 16 MHz bzw. 62,5ns. Ob das den Ansprüchen des OP genügt? ;-)
Zum Verständnis der Verfälschung der eingebauten Arduino-internen
Zeitzählung durch Interruptsperren möchte ich das Problem nochmals
zahlenmäßig darlegen:
Der Oszillator-Takt (16 MHz) wird in den 8-bit Timer/Counter Register
TCNT0 eingespeist in einem Prescaler-Teilverhältnis von 64:1. Wenn
dieses Register überläuft, also nach 64 * 256 Oszillator-Zyklen, wird
per Interrupt die Service Routine TIMER0_OVF_vect aufgerufen. In dieser
werden die internen Zählervariablen für die millis() und micros()
entsprechend aufgestockt. Wenn per noInterrupts() der Aufruf von
TIMER0_OVF_vect blockiert wird für weniger als 64 * 256 Zyklen, ist das
unproblematisch. Das entsprechende Interruptflag wird gesetzt und nach
Ablauf der Interruptsperre wird TIMER0_OVF_vect aufgerufen. Dauert die
Sperre länger als 2 x 64 x 256 Zyklen, werden zwei oder mehr
TIMER0_OVF_vect-Aufrufe ausgelassen, aber nur einer nachgeholt. Dann
wird die Zeitzählung falsch. Am Interruptflag lässt sich nicht ablesen,
wie viele Interrupts ausgelassen wurden.
Du hast völlig recht. Genau so wird es in wiring.c gemacht. Und meine Erinnerung an einen 16-bit-Timer 0 auf dem Atmega328P war falsch.
Von Sebastian W. (wangnick) und später von Sherlock (rubbel-die-katz)
wurde ein Ansatz vorgeschlagen, den ich mal ausprobieren werde, wenn ich
einen externen Taktgeber gekauft habe.
Ok. Viel Spaß und Erfolg!
Was man wissen muss, ist dass der TCNT1 für die PWM-Funktion der Pins 9
und 10 und in der Servo-Library verwendet wird. Solange man die nicht
braucht, geht der Ansatz wohl. Sonst nicht.
Stimmt.
Die PWM-Funktion der Pins 9 und 10 ergibt sich übrigens aus dem Atmega328P-Datenblatt durch die alternative Funktion OC1A des Hardwarepins PB1 und OC1B von PB2. Wenn man andenkt, die Hardwareresourcen eines Mikrocontrollers so wie hier Timer 1, die Alternativfunktion T1 von PD5, und die Alternativfunktion ICP1 von PB0 zu verwenden, dann fallen deren anderen Funktionen natürlich auch weg. Und wenn man so etwas ausprogrammiert, dann muss man dieses Datenblatt eh genau studieren.
Wenn du wirklich genau willst, bei Mouser gibt es TG2520SMN
16.0000M-MCGNNM0 mit nur 0,5 ppm, 16 MHz, kostet nur 0,85 € pro Stück.
Allerdings braucht es 2,8-3,3 Volt Speisung und Ausgang ist mit "Clipped
sine wave". Deshalb ist zusätzlich noch 3V oder 3V3 Spannungsregler (das
wird auch auf Frequenzstabilität positiv wirken) notwendig. Und für
Ausgang noch zusätzlich AHCT-Invertor, evtl. mit Schmitt-Trigger, so wie
74AHCT1G14.
Der TCXO ist schick, aber:
der Ausgang ist lt. Dabla "0,8Vpp min", d.h. es könnte mit einem AHCT gehen, könnte aber auch nicht. Oder les ich das falsch?
Mein Ansatz wäre: lass den Inverter weg und kopple das Signal mit einem Kondensator (k.A, 2-stellige pF?) auf den Eingang des auf "Quarz" eingestellten µCs, zusätzlich evtl. mit einem Spannungsteiler von vielleicht 2x 100k oder so den Eingang in die Mitte der Versorgungsspannung ziehen.
Der µC sieht so einen normalen Quarz und der interne Kram kann seinen normalen Job machen.
Oder: einen TCXO nehmen, der Rechteck/CMOS ausgibt und den dann mit einem Pegelwandler 74LVC1T45 auf 5V umsetzen.
Mein Ansatz wäre: lass den Inverter weg und kopple das Signal mit einem
Kondensator (k.A, 2-stellige pF?) auf den Eingang des auf "Quarz"
eingestellten µCs, zusätzlich evtl. mit einem Spannungsteiler von
vielleicht 2x 100k oder so den Eingang in die Mitte der
Versorgungsspannung ziehen.
Falls hier noch irgendjemand lesen sollte:
1 nF nach XTALin (o.ä.) und bloß keinen zusätzlichen Spannungsteiler verwenden!
Typische Oszillatorschaltungen in µCs verwenden einen internen Inverter mit hochohmigem Widerstand für die Gegenkopplung. Da stellt sich der richtige Pegel für optimale Empfindlichkeit von alleine ein.
Der Mensch hat etwa 200..300ms Reaktionszeit auf visuelle Reize. Zwar kompensieren sich die Zeiten bei Start und Stop weitgehend, aber eben nicht perfekt. Daher ist eine Schrittweite von 10ms vollkommen ausreichend, wie sie auch die käuflichen Stoppuhren haben. Eine Auflösung von 1ms täuscht mehr vor, als real möglich ist.
Erst z.B. bei Betätigung durch Lichtschranken läßt sich eine höhere Genauigkeit erzielen.
1 nF nach XTALin (o.ä.) und bloß keinen zusätzlichen Spannungsteiler
verwenden!
OK, danke für den Tipp.
Ist das dann eigentlich eine "Geht meistens"-Bastelkiste oder wäre das tatsächlich im Rahmen der Datenblätter "legal"?
Ich hab auf Anhieb nicht gefunden, wie hoch der Quarz-Wechselspannungsanteil sein muss, z.B. beim ATmega328P.
Die sind doch schon wieder veraltet, bis dieses Projekt fertig wird. Man
sollte gleich auf die übernächste Generation setzen ;)
Hatte letztens eine Werbung für Chip Scale Atomic Clock, ein auflötbares Modul mit einem TCXO, der von einer Atomreferenz gezogen wird.
Gepflegte 2600 Mäuse für 10MHz auf etwa 30x30x10mm, mit
1
short-term stability (Allan Deviation) of 3.0 × 10–10 at τ = 1 sec, typical long-term aging of <9 × 10–10/month, and maximum frequency change of ±3 × 10–10 over the operating temperature range of –40°C to +80°C.
Ist das dann eigentlich eine "Geht meistens"-Bastelkiste oder wäre das
tatsächlich im Rahmen der Datenblätter "legal"?
Ich hab auf Anhieb nicht gefunden, wie hoch der
Quarz-Wechselspannungsanteil sein muss, z.B. beim ATmega328P.
Bei ATmega48/88/328 hatte ich das schon vor > 10 Jahren gemacht: Problemlos.
Gerade bei den 48/88/328P Controllern ist die Amplitude am Quarz sehr klein, daß man bei Betrieb mit >= 16 MHz die 'full swing'-Option einschalten muß.
Im Schaltplan hatte ich C12 mit .1u angegeben aber immer 1 nF bestückt: http://mino-elektronik.de/fmeter/fm48.png
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise zu lange
sperrt, geht der Millisekunden-Zähler falsch.
Dann verwende die Arduino IDE einfach nicht.
Nimm das Microchip Studio und schreib den Code selber, dann weißt du zu 100% was dein Code anstellt.
1ms ist jetzt echt kein Hexenwerk.
Hat der Threadersteller eigentlich irgendwo erwähnt, was diese hyperpräzise Stopuhr steuern und was mit ihr gemessen werden soll?
Drückt da ein Mensch auf einen Knopf? Ist da eine Lichtschranke, geht es um Pferderennen, Autorennen oder die Zeit, die Schantalle mal wieder das Bad blockiert?
Wenn eine Bibliotheksfunktion die Interrupts ungeschickterweise zu lange
sperrt, geht der Millisekunden-Zähler falsch.
Dann verwende die Arduino IDE einfach nicht.
Es liegt nicht an der Arduino IDE. Es liegt an den Bibliotheken, die alle glauben sie wären die einzigen auf der Hardware. Dazu noch der häufige Mangel an Dokumentation, auf welche Hardware sie auf welche Weise zugreifen. Das führt dazu, daß man oft noch nichtmal zwei Arduino Fremd-Bibliotheken im gleichen Projekt verwenden kann.
Der TCXO ist schick, aber:
der Ausgang ist lt. Dabla "0,8Vpp min", d.h. es könnte mit einem AHCT
gehen, könnte aber auch nicht. Oder les ich das falsch?
Hysteresis für 74AHCT1G14 ist 0,4 V. Was kleiner ist als 0,8Vpp. Obere und untere threshold voltage können zwar stark schwanken, aber Trennkondensator und Poti lösen das Problem. Oder besser mit Poti ausprobieren und danach zwei feste Widerstände einlöten.
Oder besser mit Poti
ausprobieren und danach zwei feste Widerstände einlöten.
Abgesehen davon, daß das völlig unnötig ist, ist diese Fummelei auch eher schlechter.
Wenn eine Verstärkung benötigt werden sollte (bei AVRs jedenfalls nicht), dann bitte einen Inverter wie zum Beispiel 74AUP1GU04 verwenden.
solange der µC nicht in der Sonne über 60°C aufheizt könnte man den ja mit einer Heizung auf 50°C konstant halten und so wegdriften durch Temperatur verhindern.
Temperatur konstant in engen Bereichen zu halten ist einfacher als genaue Takte zu halten. Mit 50°C könnte man die genaue ms leichter einhalten und korrigieren, zumal auch einige µC eingebaute Temperaturmessungen für Timerkorekturen erlauben.
Es geht nicht um Temperaturen aufs °C genau zu halten nur um 20°C-60°C zu vermeiden.
Du meinst, dass der 328P bei 5V und 16MHz nur innerhalb eines Tastverhältnis-Bereiches von 40:60 bis zu 60:40 spezifiziert ist?
Welcher TCXO macht's denn schlechter?