Offline
Newbie
Karma: 0
Posts: 9
|
 |
« on: November 24, 2012, 10:38:16 am » |
Hallo, 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. volatile unsigned long T=0,last=0; void setup () { Serial.begin(9600); pinMode(5,INPUT); attachInterrupt(5,TMessen,RISING); }
void loop () { Serial.println(T); }
void TMessen () { detachInterrupt(5); T=micros()-last; last=micros(); attachInterrupt(5,TMessen,RISING); }
Ausgabe (Rechtecksignal mit FG erzeugt,ca. 8000Hz) : ... 124 124 4294966420 124 124 124 1124 124 123 123 4294966420 124 124 124 124 124 124 124 124 124 124 124 124 123 ...
|
|
|
|
« Last Edit: November 24, 2012, 04:38:45 pm by Selachii »
|
Logged
|
|
|
|
|
Offline
Full Member
Karma: 3
Posts: 186
|
 |
« Reply #1 on: November 24, 2012, 11:05:14 am » |
Ist das der ganze Code?
Addi
|
|
|
|
|
Logged
|
/ \ _| _| o /--\ (_| (_| |
|
|
|
|
Germany
Offline
Edison Member
Karma: 33
Posts: 1788
Arduino rocks
|
 |
« Reply #2 on: November 24, 2012, 11:08:22 am » |
So wie es aussieht, findet hier ein Variablenüberlauf statt: http://arduino.cc/en/Reference/UnsignedLong
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 9
|
 |
« Reply #3 on: November 24, 2012, 11:23:04 am » |
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?
|
|
|
|
« Last Edit: November 24, 2012, 11:40:22 am by Selachii »
|
Logged
|
|
|
|
|
Germany
Offline
Edison Member
Karma: 27
Posts: 1486
|
 |
« Reply #4 on: November 24, 2012, 11:44:47 am » |
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
|
|
|
|
« Last Edit: November 24, 2012, 11:55:42 am by michael_x »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 9
|
 |
« Reply #5 on: November 24, 2012, 12:42:37 pm » |
Ok, habe jetzt den Code wie folgt verändert um den Einfluss des Überlaufs zu reduzieren: volatile unsigned long T=0,last=0;
void setup () { Serial.begin(9600); pinMode(5,INPUT); attachInterrupt(5,TMessen,RISING); }
void loop () { Serial.println(T); }
void TMessen () { unsigned long current = micros(); if (current>last) {T=current-last;} last=current; }
Allerdings treten noch immer einige "Störungen" auf: ... 125 125 125 9 125 125 125 125 125 ... 125 1125 125 125 124 125 ...
|
|
|
|
|
Logged
|
|
|
|
|
Germany
Offline
Edison Member
Karma: 33
Posts: 1788
Arduino rocks
|
 |
« Reply #6 on: November 24, 2012, 01:39:13 pm » |
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?
|
|
|
|
« Last Edit: November 24, 2012, 01:52:33 pm by sth77 »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 9
|
 |
« Reply #7 on: November 24, 2012, 04:38:11 pm » |
Ja, stimmt. Woran könnten die Abweichungen liegen bzw. wie kann ich diese minimieren?
|
|
|
|
|
Logged
|
|
|
|
|
Germany S-H
Offline
God Member
Karma: 27
Posts: 774
|
 |
« Reply #8 on: November 25, 2012, 09:45:16 am » |
Ja, stimmt. Woran könnten die Abweichungen liegen bzw. wie kann ich diese minimieren?
detachInterrupt(5); ... attachInterrupt(5,TMessen,RISING); 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! Ändere Deine loop-Funktion mal auf: void loop () { Serial.println(T); Serial.flush(); } Und wie sieht es dann aus?
|
|
|
|
« Last Edit: November 25, 2012, 02:08:05 pm by jurs »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 9
|
 |
« Reply #9 on: December 11, 2012, 04:57:41 am » |
Erst einmal danke für die Antworten. Leider besteht das Problem trotz „Serial.flush()“ weiterhin. volatile unsigned long T=0,last=0;
void setup () { Serial.begin(9600); pinMode(5,INPUT); attachInterrupt(5,TMessen,RISING); }
void loop () { Serial.println(T); Serial.flush(); }
void TMessen () { unsigned long current = micros(); if (current>last) {T=current-last;} last=current; }
|
|
|
|
|
Logged
|
|
|
|
|
Germany S-H
Offline
God Member
Karma: 27
Posts: 774
|
 |
« Reply #10 on: December 11, 2012, 06:04:32 am » |
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. 6*8000 = 48000 5*9600 = 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?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 18
Posts: 1295
|
 |
« Reply #11 on: December 11, 2012, 08:32:54 am » |
Blöde Frage, aber warum verwendest Du nicht pulseIn()? http://arduino.cc/en/Reference/PulseIn
|
|
|
|
|
Logged
|
|
|
|
|
Germany
Offline
Edison Member
Karma: 27
Posts: 1486
|
 |
« Reply #12 on: December 11, 2012, 09:29:01 am » |
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. In >100 µs hast du eigentlich Zeit genug ...
|
|
|
|
|
Logged
|
|
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 9
|
 |
« Reply #14 on: December 11, 2012, 12:41:15 pm » |
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)?
|
|
|
|
« Last Edit: December 11, 2012, 12:45:48 pm by Selachii »
|
Logged
|
|
|
|
|
|