Hallo! 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) * Pins für: Start, Stopp, Takt, serielle Übertragung der Zählerstände. Evtl. Zurücksetzen. * Gute Verfügbarkeit in Deutschland, preiswert. Michael
Takte deinen ATMega extern mit nem billigen TCXO statt dem onboard-Quarz und der Dropps ist gelutscht. Andererseits kann ich mir nicht vorstellen, wieso ein normaler UNO für so eine läppische ms-Zählung zu ungenau sein soll. Millisekunden sind für praktisch jeden halbwegs aktuellen µC absoluter Pillepalle.
:
Bearbeitet durch User
Michael schrieb: > Hallo! > > 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. > * Pins für: Start, Stopp, Takt, serielle Übertragung der Zählerstände. > Evtl. Zurücksetzen. Haben alle ausreichend. > * Gute Verfügbarkeit in Deutschland, preiswert. Ist bei den Meisten gegeben.
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.
:
Bearbeitet durch User
Ich würde Michael schrieb: > 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. Siehe z.B. https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf Kapitel 8.5 Low Frequency Crystal Oscillator > 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. > Welchen Mikrocontroller würdet Ihr empfehlen http://stefanfrings.de/stm32/stm32l0.html 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.
:
Bearbeitet durch User
Michael schrieb: > Millisekunden-Stoppuhr bauen. > Millisekunden-Zählung > Ganggenauigkeit +- 5 ppm. Finde den Fehler… (Falls nicht gerade Tagelang am Stück Millisekunden gezählt werden sollen.) PS. ppm steht nicht für ›parts per millisecond‹.
Löte den Resonator aus und stelle die Verbingung lt. Bild her: http://mino-elektronik.de/bilder/Fmeter_6LED/UNO_R3_takt_1_5_1.jpg Damit wird der ATmega328 vom lokalen 16 MHz Quarz versorgt. Michael schrieb: > * Gute Verfügbarkeit in Deutschland, preiswert. Das Stück Litze gibt es hierzulande zu kaufen.
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.
Michael schrieb: > 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.
Sherlock schrieb: > Michael schrieb: >> 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. Wer - eher Du als Michael. > Der interne Taktgeber ist in der Tat ungenau, Wie ungenau? > hat aber 8 MHz. Welche? Die Masse meiner hat 16 MHz, nur die 3,3V-Version des ProMini wird mit 8 MHz getaktet.
> Andererseits kann ich mir nicht vorstellen, wieso ein normaler UNO für > so eine läppische ms-Zählung zu ungenau sein soll. Weil er keinen Quarz hat, sondern ein Keramikresonator.
Michael schrieb: > Welchen Mikrocontroller würdet Ihr empfehlen Arduino Uno. Michael schrieb: > weil der interne 16 MHz-Taktgeber eine zu große Gangungenauigkeit hat. Michael schrieb: > Ganggenauigkeit +- 5 ppm Eng. Das schaffen 32768 Uhrenquartze gerade eben aber die liefern keine Millisekunde Auflösung. 10ppm gäbe es https://de.rs-online.com/web/p/schwingquarz/1735927 > 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. Niemand zwingt dich, schlecht zu programmieren. Michael schrieb: > 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. https://www.mouser.de/ProductDetail/Pletronics-Inc/UCE4031035LK015000-16.0M
Vielen Dank für alle Antworten. 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 | void setup() { |
2 | Serial.begin(9600); |
3 | //noInterrupts();
|
4 | }
|
5 | |
6 | void loop() { |
7 | Serial.print(millis()); |
8 | Serial.println(" ms"); |
9 | float x; |
10 | //waist some time:
|
11 | for (long int t = 0; t < 5000; t++) {x = sin(t);} |
12 | Serial.println(x); |
13 | }
|
Michael
Michael schrieb: > Ich wollte aber für meine Hobby-Lernzwecke eben eine genauere Stoppuhr > implementieren. Michael schrieb: > Leider hat niemand meine Frage nach dem geeigneten, simplen > Mikrocontroller beantwortet Doch. Es wurden mehrere Controller, RTCs genannt. Michael schrieb: > (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.
:
Bearbeitet durch User
Michael schrieb: > Vielen Dank für alle Antworten. > > 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?
Michael schrieb: > Vielen Dank für alle Antworten. > > 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.
Maxim B. schrieb: > 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?
Michael schrieb: > 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. fchk
Michael schrieb: > 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. Reicht Dir das nicht?
Maxim B. schrieb: > meine erste Wahl wäre ATMega1284P. Und kein Arduino jeglicher Art. 16k > SRAM, JTAG-Debug. 16k SRAM für eine Stoppuhr? Meinst du kBit?
:
Bearbeitet durch User
Michael schrieb: > Leider hat niemand meine Frage nach dem geeigneten, simplen > Mikrocontroller beantwortet. Annähernd jeder mit Hardware Timer und vernünftiger Programmierung. Michael schrieb: > (1.) Ich will eine Lösung ohne einen Umbau des Arduino. Schmeiß dich doch auf den Boden und schreie ganz laut "Ich will aber, ich will".
:
Bearbeitet durch User
Michael schrieb: > 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.
Obelix X. schrieb: > Michael schrieb: >> Leider hat niemand meine Frage nach dem geeigneten, simplen >> Mikrocontroller beantwortet. > > Annähernd jeder mit Hardware Timer und vernünftiger Programmierung. Interrupts sollte er noch können... PIC10Fxxx ;D
Michael schrieb: > 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.
Als unabhängiger neutraler Beobachter versuche ich mal, möglichst wenig in Frage zu stellen. Natürlich kann man alles anders machen. Michael schrieb: > für meinen Arduino Uno Rev3 > manche Programmbibliotheken (z.B. OneWire) > ein peripheres Modul Dieser Arduino ist also nicht verhandelbar und da läuft schon irgendwas, was kaum geändert werden kann. Also ist so ein Modul vernünftig. > Z.B. dem DS3231 RTC Maxim B. schrieb: > 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.
Michael schrieb: > Außer mit dem Arduino Uno habe ich keine Erfahrung mit Mikrocontrollern. Bauform B. schrieb: > 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ß.
:
Bearbeitet durch User
Mi N. schrieb: > Wie will er denn sicherstellen, > daß die Abfrage des peripheren Zählers im ms-Raster funktioniert? Die Abfrage ist nicht zeitkritisch, die passiert ja erst, wenn alles erledigt ist. > Die zeitgerechte Triggerung von 'start' und 'stopp'-Signalen kann > ja auch durch interne Blockaden behindert werden. Der Einwand ist allerdings mehr als berechtigt :(
AVR Datasheet: "Two 16-bit Timer/Counter Type B (TCBn) can be combined to work as a true 32-bit input capture." Damit kann man sehr lange Millisekunden zählen.
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.
Hallo Michael, Michael schrieb: > 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. Ok. Michael schrieb: > 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. Ok. Michael schrieb: > (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. LG, Sebastian
:
Bearbeitet durch User
Sebastian W. schrieb: > Und wenn die Interrupts gesperrt sind, dann werden diese Überläufe nicht > gezählt, und dadurch gehtmillis() > falsch. Na und, das zugehörige Flag wird aber weiterhin gesetzt! ...
Michael schrieb: > Meine Idee ist, ein peripheres Modul aufzubauen 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. Mi N. schrieb: > 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. Da haben wir die Casus Knacksus.
:
Bearbeitet durch Moderator
Sebastian W. schrieb: > C:\Program Files > (x86)\Arduino\hardware\arduino\avr\cores\arduino\wiring.c ohne Worte Sebastian W. schrieb: > 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.
Clemens S. schrieb: > 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. ;-)
Clemens S. schrieb: > 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.
Sebastian W. schrieb: > 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. LG, Sebastian
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.
Manfred P. schrieb: >> Der interne Taktgeber ist in der Tat ungenau, >> hat aber 8 MHz. > Wie ungenau? > Welche? Die Masse meiner hat 16 MHz Normalerweise meinen Leute hier im Forum den internen R/C Oszillator. Dieser hat bei den klassischen AVR 8 MHz +/-10%, soweit ich mich erinnere. Im gleichen Beitrag wie ich darauf hin der (interne) Quarz-Oszillator > nicht weniger genau, als ein 32 kHz Uhrenquarz ist.
:
Bearbeitet durch User
Beitrag #7830553 wurde vom Autor gelöscht.
Norbert schrieb: > … das gibt 'ne Stoppuhr wie sie die Welt noch nicht gesehen hat. Diese wird auch schon dazu gehören, denn unter 200 s darf man keine Zeiten messen. Andernfalls werden die 'geforderten' 5 ppm überschritten ;-)
Michael schrieb: > Leider hat niemand meine Frage nach dem geeigneten, simplen > Mikrocontroller beantwortet. Doch, habe ich: Sherlock 🕵🏽♂️ schrieb: >> Welchen Mikrocontroller würdet Ihr empfehlen > http://stefanfrings.de/stm32/stm32l0.html 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.
Hallo! 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. Sebastian W. schrieb: > 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. Sherlock 🕵🏽♂️ schrieb: > 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. Clemens L. schrieb: > 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. Bauform B. schrieb: > 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 €. Peter D. schrieb: > 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. Michael
:
Bearbeitet durch User
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.... Versuch: Michael schrieb: > 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.
:
Bearbeitet durch User
Michael schrieb: > 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 ...
Michael schrieb: > 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?
:
Bearbeitet durch User
Rainer W. schrieb: > 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".
Sherlock 🕵🏽♂️ schrieb: > Michael schrieb: >> 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...
Motopick schrieb: > 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. Motopick schrieb: > Welchen positiven Effekt, sollte "0,5 ppm" bei einer Uhr, die gerade > mal 1 ms aufloesen kann, haben? 16 MHz kostet z.Z. weniger als 1 €, billiger als manche mit 50 ppm. Und schlechter wird es mit 0,5 ppm bestimmt nicht arbeiten.
:
Bearbeitet durch User
Michael schrieb: > 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. Michael schrieb: > 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. Nimm den DS3231 und sei glücklich! Sherlock 🕵🏽♂️ schrieb: > 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? Ganz einfach: Man muß oft durch 32 teilen und ab und zu durch 33 - jede Millisekunde :-)
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.
Michael schrieb: > Peter D. (peda) schlägt den AT89C2051 vor. Vorschlagen würde ich ihn nicht mehr. Ich wollte nur darlegen, daß man schon mit sehr wenigen Ressourcen Zeiten und Frequenzen genau messen konnte. Es gibt als Upgrade den AT89LP4052 oder AT89LP51RD2 und der Wickenhäuser und SDCC sollen wohl auch recht guten Code erzeugen.
Was redet ihr immer von Interrupts?! Ihr braucht keine Interrupts bei einem Zeitzähler. Lasst den Timer laufen und vergleicht das Counter Register... 8Bit mit Frequenz an PD5 (Timer 1 input) sollte einem die interne Frequenz nicht reichen.
1 | #include <avr/io.h> |
2 | |
3 | int main(void) |
4 | { |
5 | DDRD &= ~(1 << DDD5); // PD5 säubern |
6 | PORTD |= (1 << PORTD5); // PD5 PullUp ein, Eingang |
7 | TCCR1B |= (1 << CS12) | (1 << CS11) | (1 << CS10); |
8 | // Timer 1 starten, Rising Edge |
9 | |
10 | while (1) |
11 | { |
12 | //TCNT1 Register vergleichen(da steht die ZEIT!) |
13 | } |
14 | } |
Das ist es, mehr braucht es nicht....
Ob S. schrieb: >> 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.
Mi N. schrieb: >> 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? > > 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. 'nuff said, EOD
Axel S. schrieb: > 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.
Axel S. schrieb: > 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.
:
Bearbeitet durch Moderator
Lothar M. schrieb: > 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? ;-)
Michael schrieb: > 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. Michael schrieb: > 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. LG, Sebastian
Maxim B. schrieb: > 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.
Jens M. schrieb: > 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.
Vorschläge kommen hier, da bin ich zutiefst erschüttert! Für eine Millisekunden Stoppuhr kann man doch — wenn man die ernsthaft betreiben möchte — alles unterhalb einer Caesium-Fontäne vergessen.
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.
Norbert schrieb: > Für eine Millisekunden Stoppuhr kann man doch — wenn man die ernsthaft > betreiben möchte — alles unterhalb einer Caesium-Fontäne vergessen. Die sind doch schon wieder veraltet, bis dieses Projekt fertig wird. Man sollte gleich auf die übernächste Generation setzen ;) https://nachrichten.idw-online.de/2024/09/04/die-erste-atomkern-uhr-der-welt
Bauform B. schrieb: > Die sind doch schon wieder veraltet, bis dieses Projekt fertig wird. Man > sollte gleich auf die übernächste Generation setzen ;) Der Gedanke ist ja gut, aber gibt's dafür denn auch eine Arduino Lib? Sonst sehe ich die nächste große Enttäuschung auf dieses Forum zusteuern.
Mi N. schrieb: > 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. Bauform B. schrieb: > 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. |
Jens M. schrieb: > 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
Bauform B. schrieb: > Die sind doch schon wieder veraltet, bis dieses Projekt fertig wird. Man > sollte gleich auf die übernächste Generation setzen ;) Thorium Nuclear Clock!
Michael schrieb: > 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?
Adam P. schrieb: >> 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.
Jens M. schrieb: > 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.
:
Bearbeitet durch User
Maxim B. schrieb: > 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.
Oder noch besser: TCXO mit 2*F_CPU nehmen und mit 1/2 74AHCT74 teilen.
Maxim B. schrieb: > Oder noch besser: Schade, daß Du das nicht begründet hast. Dann könnte man diesen Vorschlag schön zerlegen. Er ist nämlich großer Unfug!
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. https://de.statista.com/statistik/daten/studie/1032379/umfrage/orte-in-deutschland-mit-einer-temperatur-von-ueber-40-grad-celsius/ also nichts für das Armaturenbrett im PKW
:
Bearbeitet durch User
Mi N. schrieb: > Er ist nämlich großer Unfug! Doch: man bekommt SICHER 50:50 Takt, weder 55:45 oder 40:60, was in anderen Varianten nicht auszuschließen wäre.
Maxim B. schrieb: > Mi N. schrieb: >> Er ist nämlich großer Unfug! > > Doch: man bekommt SICHER 50:50 Takt, weder 55:45 oder 40:60, was in > anderen Varianten nicht auszuschließen wäre. Dann misst sich die Millisekunde gleich viel symmetrischer…
Norbert schrieb: > Dann misst sich die Millisekunde gleich viel symmetrischer… Deine Aussage zeigt, daß du Datasheet für Mikrocontroller noch nicht kennst.
:
Bearbeitet durch User
Maxim B. schrieb: > Kuck mal Datasheet. 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?
Der Drops ist übrigens gelutscht, der Threadstarter ist hier schon seit über 'ner Woche nicht mehr an Bord.
Harald K. schrieb: > schon seit > über 'ner Woche nicht mehr an Bord Die Popcorn-Tüte ist längst leer ... ;-)
Harald K. schrieb: > Der Drops ist übrigens gelutscht Schon längst, nachdem man nicht mal erfahren darf wozu das Ganze und die unheimlich hohe Genauigkeit dienen soll.
Wastl schrieb: > Schon längst, nachdem man nicht mal erfahren darf wozu das > Ganze und die unheimlich hohe Genauigkeit dienen soll. Als moderner Ersatz für den guten alten Abreißkalender.
Harald K. schrieb: > Der Drops ist übrigens gelutscht, der Threadstarter ist hier schon seit > über 'ner Woche nicht mehr an Bord. Das ist doch wie immer völlig unwichtig. Hugo H. schrieb: > Die Popcorn-Tüte ist längst leer ... ;-) Dann schwingt Dich auf, hole Waffel-Eier, Gelee-Hasen oder Pfannkuchen mit Eierlikör, damit Du in der Fastenzeit nicht verhungern mußt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.