Forum: Mikrocontroller und Digitale Elektronik Frequenzmessung mit ATMega und Input Capture


von Third E. (third-eye)


Lesenswert?

Hallo,

ich will mit einem ATMega32U4 mit 16MHz-Quarz, Vorteiler 8, eine 
Frequenzmessung mit dem Timer1 realisieren, bzw. erst einmal eine 
Periodendauermessung mit der Pseudoeinheit "Timer Ticks".
Ich bekomme von einem Drehzahlsensor 48 TTL-Impulse pro Umdrehung. Die 
Drehzahlmessung soll in einem Bereich von ca. 10 bis 1000 Umdrehungen 
pro Minute funktionieren, was einer Frequenz von 8 Hz bis 800 Hz 
entspricht.
Ich habe da was programmiert. Beschreibung:

Ich verwende die Input Capture-Funktion des Timer1. In dessen ISR setze 
ich ein Flag, dass ein Impuls gekommen ist (in meinem Fall die fallende 
Flanke). Außerdem nulle ich hier den TCNT1-Wert.

Außerdem wird beim Überlauf von Timer1 eine Variable "ueberlaeufe" 
inkrementiert.

In der Hauptschleife wird folgendes berechnet, wenn das Flag gesetzt 
ist:

timer_ticks = 65536 * (ueberläufe + KORREKTUR_UEBERL) + ICR1 + 
KORREKTUR_ICR

KORREKTUR_UEBERL und KORREKTUR_ICR sind Konstanten, die ich 
experimentell angepasst habe, dass der Wert stimmt. KORREKTUR_UEBERL ist 
1 und KORREKTUR_ICR 4.

Während die Berechnung erfolgt, sind die Interrupts gesperrt, um 
atomaren Variablenzugriff zu garantieren.

Das ganze funktioniert, aber das geht bestimmt eleganter. Vielleicht 
kann ich mir diese Korrigiererei irgendwie sparen.

Ich vermute, dass es vorteilhaft ist, einen ICR-Wert zwischenzuspeichern 
und die Differenz mit dem darauffolgenden ICR-Wert zu berechnen, anstatt 
jedes mal den TCNT-Wert zu nullen, richtig?

Ich habe auch was programmiert, wenn die Anzahl an Überläufen einen 
bestimmten Wert überschreitet, dass dieser genullt wird. Das greift 
dann, wenn mein Motor steht, es aber ab und zu Drehzahlimpulse gibt, 
weil er gerade an der "Grenze" steht und das Drehzahlsignal flattert.

Wie könnte ich es lösen, dass nachdem der Motor mal gestanden hat, die 
erste Berechnung nicht "Müll" liefert?

Danke.
Third-Eye

von Stefan (Gast)


Lesenswert?

Erklär mal genauer, wozu die Korrektur-Konstanten dienen? Was wird da 
korrigiert?

> Ich verwende die Input Capture-Funktion des Timer1.
> Außerdem nulle ich hier den TCNT1-Wert.

Aua, das kann nicht gut gehen. Denn zwischen dem Interrupt und der 
Ausführung dieses "nullen" befehl verstreicht eine unbekannte Zeit. Die 
ist nicht konstant, kann folglich auch nicht durch eine Konstante 
korrigiert werden.

Die Capture Funktion erfasst doch den Zählerstand zum Zeitpuntk des 
Ereignisses. Den musst du verwenden. Und du darfst den Zähler nicht 
zurücksetzen, sondern must die Zählerstände von zwei 
aufeinanderfolgenden Ereignissen voneinander subtrahieren.

Wenn der Zähler 16 bit hat und du für die Variablen ebenfalls unint16_t 
verwendest, dann ergibt die Subtraktion auch nach einem Zähler-Überlauf 
stets das richtige Ergebnis.

von Stefan (Gast)


Lesenswert?

> Wie könnte ich es lösen, dass nachdem der Motor mal gestanden hat,
> die erste Berechnung nicht "Müll" liefert?

Der erste Interrupt liefert noch kein Meßergebnis. Erst nach zwei 
Interrupts kannst Du die Differenz der beiden Zählerstände berechnen, 
und die leifert dann auch keinen Müll. Dabei spielt es keine Rolle, ob 
der Zähler irgendwann genullt wird (was du nicht tun sollst), oder 
nicht.

Du brauchst bloss eine Variable, die anzeigt, ob nach Start des Motors 
mindestens zwei Interrupts stattfanden. Das könnte ein Integer sein, der 
bei jedem Interrupt hochgezählt wird, aber maximal bis auf 2.

Motor starten:
counter=0;

Bei Interrupt:
if (counter<2) counter++;
previous=current;
current=ICR1;

In der Auswertung (main-loop):
if (counter==2) {
  diff=current-previous;
  ... nun die Zeit in Drehzahl umrechnen und anzeigen
}

von Ulrich (Gast)


Lesenswert?

Bei dem begrenzten Wertebereich wird man die Überläufe vom Timer 
vermutlich nicht wirklich brauchen, zumindest wenn der Vorteiler passend 
eingestellt ist. Wenn man die Überläufe braucht, muss man etwas 
aufpassen wenn Überlauf und ICP Ereignis fast gleichzeitig kommen - da 
kann es passieren das der Überlauf Interrupt zu spät kommt und so in 
seltenen Fällen einen Falschen Wert liefert.

Die Berechnung über die Differenz aus 2 mit ICP gemessenen Zeiten ist 
der bessere/genauere Weg, um kommt so ohne die Korrekturwerte aus.

Die Erkennung ob der Motor gestanden hat, und auch um andere Ausreißer 
zu reduzieren könnte man machen indem man mehrere Periodendauern misst 
und dann etwa von 3 oder 5 Messungen den Median nimmt. Die eigentliche 
Messung für eine Periode geht ja sehr schnell. Ggf. könnte man auch 
Werte Unterdrücken (kein neuer gültiger Wert) wenn sie zu sehr 
schwanken.

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
Noch kein Account? Hier anmelden.