Pages: [1] 2   Go Down
Author Topic: Arduino Periodendauer messen  (Read 1889 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
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)  :

Code:
...
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 Offline
Full Member
***
Karma: 5
Posts: 193
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ist das der ganze Code?

Addi
Logged

  / \    _|  _| o
 /--\ (_| (_| |

Germany
Offline Offline
Edison Member
*
Karma: 46
Posts: 2310
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So wie es aussieht, findet hier ein Variablenüberlauf statt: http://arduino.cc/en/Reference/UnsignedLong
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Offline Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Faraday Member
**
Karma: 56
Posts: 2974
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

Code:
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 Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, habe jetzt den Code wie folgt verändert um den Einfluss des Überlaufs zu reduzieren:

Code:
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:
Code:
...
125
125
125
9
125
125
125
125
125
...
125
1125
125
125
124
125
...
Logged

Germany
Offline Offline
Edison Member
*
Karma: 46
Posts: 2310
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Offline Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ja, stimmt.
Woran könnten die Abweichungen liegen bzw. wie kann ich diese minimieren?
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 134
Posts: 2854
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Erst einmal danke  für die Antworten.
Leider besteht das Problem trotz „Serial.flush()“ weiterhin.

Code:
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 Offline
Faraday Member
**
Karma: 134
Posts: 2854
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Blöde Frage, aber warum verwendest Du nicht
pulseIn()?
http://arduino.cc/en/Reference/PulseIn
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2974
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Blöde Frage, aber warum verwendest Du nicht pulseIn()?
Weil das ein ganz anderer Ansatz ist ... ohne Interrupts ist zu einfach  smiley-wink

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:
Code:
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

0
Online Online
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Benutze doch den Input Capture Interrupt. Schau Dir mal mein Beispiel hier an: http://blog.blinkenlight.net/experiments/measurements/power-grid-monitor-2/.
Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Newbie
*
Karma: 1
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Pages: [1] 2   Go Up
Jump to: