ich möchte mit folgendem Code die Periodendauer (in µs) einer Rechteckschwingung messen.
Es klappt soweit auch ganz gut, jedoch kommen in bestimmten Abständen Ausreißer die ich mir nicht ganz erklären kann.
Danke für die schnelle Antwort.
Gibt es eine Möglichkeit sich nicht immer auf die andauernd anwachsende micros-Zeit zu beziehen.
Z.B. einen Timer zu starten der wieder auf 0 gesetzt werden kann?
Wenn du das detachInterrupts / attachInterrupts weglässt, sollte micros() sich innerhalb deiner interrupt-Routine nicht ändern. Dann funktioniert die Differenz-Bildung auch bei Überlauf.
Oder du machst in TMessen:
unsigned long current = micros(); // nur einmal lesen
T=current-last;
last=current;
Edit: Aber eigentlich sollten mit deiner Methode nur ein paar micros fehlen ... Differenzbildung geht auch über den Überlauf hinweg richtig
Kurze Zwischenfrage: Du sagst, dass das zu messende Signal 8000 kHz hat.
Mit t=125 µS=0,125ms=0,000125s ergibt sich f=1/t=8000Hz. Oder habe ich einen Denkfehler?
[Edit] Und mit welchem Arduino-Board experimentierst du? Pin 5 deutet auf einen Arduino Due hin, oder?
Was sollten denn diese Aufrufe innerhalb der Interrupt-Routine bewirken, ausser das Interrupt-System völlig aus dem Takt zu bringen?
Und im übrigen, rechne bitte mal nach, wie oft Deine loop-Funktion läuft, wie viele Zeichen da wohl pro Sekunde ausgegeben werden sollen, wieviele Zeichen pro Sekunde bei der gesetzten Baudrate tatsächlich über die Schnittstelle rausgehen und wie oft pro Sekunde der serielle Sendepuffer wohl schätzungsweise überläuft!
Selachii:
Leider besteht das Problem trotz „Serial.flush()“ weiterhin.
Leider stören sich auch regelmäßig die Timer-Interrupts beim Senden über die serielle Schnittstelle und die Rising-Interrupts Deiner Frequenz, da es ziemlich kleine gemeinsame Vielfache zwischen der Baudrate (9600) und der Frequenz (8000) gibt.
68000 = 48000
59600 = 48000
D.h. ein Konflikt tritt rein rechnerisch alle 48000 Schwingungen = ca. 6 Sekunden auf.
Kommt das ungefähr hin, ein Fehler alle ca. 6 Sekunden?
Oder mit welcher Häufigkeit gibt es die Ausreißer (circa) bei den Messwerten?
Blöde Frage, aber warum verwendest Du nicht pulseIn()?
Weil das ein ganz anderer Ansatz ist ... ohne Interrupts ist zu einfach
Aber, was mir auffällt: volatile unsigned long T;
darf eigentlich in loop() nicht "einfach so" verwendet werden, da der Zugriff auf die 4 byte von T von der Interrupt-Routine unterbrochen werden kann.
Rein theoretisch müsste es so aussehen:
void loop()
{
noInterrupts(); // oder cli();
unsigned long tmp = T;
interrupts(); // oder sei();
Serial.println(tmp);
Serial.flush();
}
Da aber der "richtige" Wert nur ca. 125 ist, spielt das hier keine Rolle und dein Effekt rührt wohl daher, dass Serial oder gar Timer-Interrupts manchmal deinen Interrupt 5 blockieren.
Da du ja sowieso asynchron zur Messung deine Ausgaben machst: Wie wäre es mit einer "statistischen" Auswertung ( max/min/avg ) oder sammeln eines Histogramms ( Anzahl Werte <123, 123, 124, 125, 126, 127 , >127 ) und Ausgabe erst nach der Messung ? Da brauchst du auch nicht so auf den Schirm zu starren, um Ausreisser zu sehen, bevor sie durchgerauscht sind.
Das mit dem Input Capture Interrupt scheint auf jedenfall sehr nützlich zu sein, da es hardwareseitig abläuft und dadurch nicht so schnell durch andere Interrupts gestört werden kann (... wenn ich das richtig verstanden habe).
Ist das Ganze in dieser Form auch auf den ARM basierenden DUE übertragbar oder sollte dazu das Datenblatt zu Rate gezogen werden?
Leider fange ich gerade erst an mich in solche µc-Themen einzulesen...
Deswegen auch die Frage:
Gibt es innerhalb der "Arduino-Sprache" die Möglichkeit hardwareseitig die ankommenden Impulse zu zählen und den Zähler dann im "Hauptprogramm" auszulesen und im Anschluss einen Reset durchzuführen (dazu die Zeit-Diff. mittels micros() ermitteln)?
Nein, wenn Du nach Hardware frägst, dann ist die Sprache schon aussen vor. Die Sprache heisst c++ und kann sowas nicht. Höchstens irgendwelche Libraries könnten sowas. Und nein, die UNO und die DUE Hardware sind nicht ausreichend kompatibel um sowas 1:1 zu übernehmen.