Hallo zusammen,
nach kräftiger Unterstützung dieses Forums klappt meine Frequenzmessung
mit einem ATmega32 und einem Frequenzgenerator(als Testsignal) ab ca. 20
Hz einwandfrei. Die Werte werden per UART übertragen. Doch gehe ich
niedriger, so erhalte ich willkürliche Werte. Ich weiß nicht, woran es
liegen kann. Die Frequenzen werden nochmal zusätzlich mit einem
Oszilloskop überprüft.
Könnt ihr mir vielleicht weiter helfen?
Ich benutze eine interne Frequenz von 8MHz, Timer1 mit 125kHz, Input
Capture Unit reagiert auf steigende Flanke vom Analog Komparator. Dieser
hat eine Referenzspannung von einigen mV. (Ich habe mehrere
Oszillator-Frequenzen und Taktefrequenzen des Timer1 ausprobiert und
immer bekomme ich das selbe Fehlerbild)
Im Anhang befindet sich der komplette Code.
Hier ist der Ausschnitt aus dem Quellcode: (Nachträglich werde ich noch
eine Mittelung des Wertes einbauen)
while(1)
{
TCNT1 = 0; //Setze Zählerstand T1 auf 0
ICR1=0; //Setze Input Capture Register auf 0
TIFR |= (1<<ICF1); // Input Capture Flag löschen
while (!(TIFR & 1<<ICF1)) //Warte bis nächste positive Flanke
{
if (TIFR & 1<<TOV1) //Ergibt sich innerhalb von 1
Timerüberlauf von T1 keine positive Flanke,
{ // so ist v=0 km/h
UART_SendByte('v');
UART_SendByte(0);
TIFR |= (1<<TOV1); //Timerüberlauf = 0 setzen
}
}
TCNT1 = 0; //Setze Zählerstand T1 auf 0
ICR1=0; //Setze Input Capture Register auf 0
TIFR |= (1<<ICF1); // Input Capture Flag löschen
while (!(TIFR & 1<<ICF1)) //Warte bis nächste positive Flanke
{
if (TIFR & 1<<TOV1) //Ergibt sich innerhalb von 1
Timerüberlauf von T1 keine positive Flanke,
{ //so ist v=0 km/h
UART_SendByte('v');
UART_SendByte(0);
TIFR |= (1<<TOV1);
}
}
Periode = ICR1; // Lese Wert der nächsten positiven Flanke
//Bestimmung der Geschwindigkeit
Frequenz = (125000.0 / (double)Periode);
Die Auswertung der ICP in der main-Schleife verstehe nicht nicht so
ganz, ich würde das über einen Interrupt lösen.
Du überprüfst zwar auf einen Überlauf des Timers, berechnest am Ende
trotzdem immer die Frequenz, die im Falle des Überlaufes nicht stimmt.
Hast du mal ausgerechnet was die niedrigste Frequenz ist die du noch
messen kannst, ohne das der Timer überläuft?
Wenn man schon input capture nutzt, dann sollte man die Differenz von 2
ICP Events nutzen, nicht bei der ersten Flanke nur dem Timer auf 0
setzen und dann messen.
Der Fehler könnte durch die Qualität des Einagnsgsignals verursacht
sein. Gibt es das Problem denn auch bei einem Digitalen Eingangssignal
?
Erstmal Danke für die schnellen Antworten!!!
André Althaus schrieb:> Die Auswertung der ICP in der main-Schleife verstehe nicht nicht so> ganz, ich würde das über einen Interrupt lösen.> Du überprüfst zwar auf einen Überlauf des Timers, berechnest am Ende> trotzdem immer die Frequenz, die im Falle des Überlaufes nicht stimmt.
Der Überlauf des Timer findet nur statt, wenn kein Signal oder eine zu
kleine Frequenz anliegt. Wenn kein Signal anliegt, klappt die Auswertung
ohne Probleme. Wird die Frequenz zu klein, bekomme ich auch diese
willkürlichen Werte.
André Althaus schrieb:> Hast du mal ausgerechnet was die niedrigste Frequenz ist die du noch> messen kannst, ohne das der Timer überläuft?
Die niedrigste Frequenz, welche ohne Fehler angezeigt wird liegt ca. bei
20Hz. An der Stelle ist der Timer gerade mal 6250 also weit vom Überlauf
entfernt. Ich denke, dass es nichts mit dem Überlauf zutun hat, denn der
Fehler tritt weitaus früher auf.
Andreas K. schrieb:> Warum wertest du den Timerüberlauf nicht einfach mit dem passenden> Interrupt aus?
Weil der Interrupt nicht funktioniert hatte. Hab dann einfach wieder die
klassische Variante gewählt, um erst einmal den 1. Fehler zu beheben.
Danach kann ich dann den Quellcode etwas übersichtlicher gestalten.
Ulrich schrieb:> Wenn man schon input capture nutzt, dann sollte man die Differenz von 2> ICP Events nutzen, nicht bei der ersten Flanke nur dem Timer auf 0> setzen und dann messen.
Das könnte ich versuchen, aber meinst du, der Fehler sei dadurch
behoben? Ob ich jetz die Frequenz aus einem Wert berechne oder aus der
Differenz zweier Werte, macht doch keinen Unterschied.
Ulrich schrieb:> Der Fehler könnte durch die Qualität des Einagnsgsignals verursacht> sein. Gibt es das Problem denn auch bei einem Digitalen Eingangssignal> ?
Wenn ich als Eingangssignal ein Rechtecksignal auswähle, dann tritt der
Fehler genauso auf. Auf meinem Oszilloskop ist es ein reiner Sinus bzw.
Rechteck.
Sascha M. schrieb:> An der Stelle ist der Timer gerade mal 6250 also weit vom Überlauf> entfernt.
Bist du dir sicher? Wenn man die 6250 mal 10 nimmt kommt das verdächtig
nahe an 65536 heran also einen 16 Bit Überlauf.
Was misst du denn? Ständig wechselnde Frequenzen, oder systematisch
falsche Werte also immer das gleiche falsche Ergebnis bei einer
konstanten Frequenz?
UR Schmitt schrieb:> Bist du dir sicher? Wenn man die 6250 mal 10 nimmt kommt das verdächtig> nahe an 65536 heran also einen 16 Bit Überlauf.
Bei einer Timerfrequenz von 125kHz (Pro Takt 8us) und einer zu messenden
Periodendauer von 20Hz = 50ms ergibt es einen Counterwert von 6250.
UR Schmitt schrieb:> Was misst du denn? Ständig wechselnde Frequenzen, oder systematisch> falsche Werte also immer das gleiche falsche Ergebnis bei einer> konstanten Frequenz?
Ständig wechselnde Werte. Der Wert springt ständig zwischen
Verschiedenen Werten hin und her...
sashm schrieb:> Ständig wechselnde Werte. Der Wert springt ständig zwischen> Verschiedenen Werten hin und her...
Dann könnte es ein Hardwareproblem sein. Vieleicht fängt sich deine
Schaltung Netzbrumm oder Netzstörungen ein. Bei höheren Frequenzen
merkst du das nicht weil die Messung schnell genug erfolgt.
UR Schmitt schrieb:> Dann könnte es ein Hardwareproblem sein. Vieleicht fängt sich deine> Schaltung Netzbrumm oder Netzstörungen ein. Bei höheren Frequenzen> merkst du das nicht weil die Messung schnell genug erfolgt.
Könnte möglich sein. Ich habe am Eingangspin des Atmegas mein
Oszilloskop angeschlossen und sehe keine Störungen oder sonstige
Verzerrung des Sinussignals.
Könnte ich das mit einem Trenntrafo lösen?
UR Schmitt schrieb:> Blöde Idee:> Du hast aber schon ausgeshlossen daß dein Testgenerator bei den> Frequenzen stabil ist? Nicht daß der da ein Problem hat.
Ideen sind doch nie blöd :)
Das Bild auf dem Oszilloskop sieht sauber aus. Kann dort keine
Verzerrungen feststellen... das wundert mich deshalb wirklich...
Digi Tal schrieb:> du sprichst von Sinussignal....schalte um auf Rechteck; was passiert ?
Der gleiche Fehler tritt auf. Ich weiß wirklich nicht, woran es liegen
könnte!
Dann lass dir doch mal alle Werte ausgeben.
Fang bei ICR1 an.
(Seltsame Ausgabe hast du da. Da werden Buchstaben gesendet und hinten
nach die Zahlen in Binärform. Hast du am anderen Ende der UART ein
Spezialprogramm hängen? Wenn ja, dann würd ich erst mal eine vernünftige
ASCII Ausgabe machen und da ganz einfach ein Terminal drannhängen. Dann
kann man auch beliebige Ausgaben machen ohne am PC Programm rumdoktoren
zu müssen)
Karl Heinz Buchegger schrieb:> Dann lass dir doch mal alle Werte ausgeben.> Fang bei ICR1 an.>> (Seltsame Ausgabe hast du da. Da werden Buchstaben gesendet und hinten> nach die Zahlen in Binärform. Hast du am anderen Ende der UART ein> Spezialprogramm hängen? Wenn ja, dann würd ich erst mal eine vernünftige> ASCII Ausgabe machen und da ganz einfach ein Terminal drannhängen. Dann> kann man auch beliebige Ausgaben machen ohne am PC Programm rumdoktoren> zu müssen)
Ok, ich werde es mal mit allen Werten ausprobieren! Gibt es da eine
elegante Lösung zum Auslesen der Register?
Ich benutze ein Terminalprogramm, welches mir die Daten als Binär, Hex
und Dezimal anzeigt: H-Term. Die Buchstaben hab ich nur zum Testen
eingefügt, da ich am Ende die Geschwindigkeit erhalten möchte, habe ich
das Formelzeichen v gewählt.
Sash uM schrieb:> Ok, ich werde es mal mit allen Werten ausprobieren! Gibt es da eine> elegante Lösung zum Auslesen der Register?
Du brauchst nicht alle Werte, sondern nur die Register die du auch
verwendest. Sind ja bei dir nicht allzuviele.
> Ich benutze ein Terminalprogramm, welches mir die Daten als Binär, Hex> und Dezimal anzeigt: H-Term.
Dann mach dir doch als erstes mal vernünftige Ausgabefunktionen!
Nur mit einem UART_SendByte wirst du auf Dauer nicht weit kommen.
1
voidUART_SendString(char*str)
2
{
3
while(*str)
4
UART_SendByte(*str++);
5
}
und schon kannst du einen String ausgeben
1
....
2
UART_SendString("Fehler: Ueberlauf\n");
3
....
dann noch welche für Zahlen
1
voidUART_SendUI32(uint32number)
2
{
3
charBuffer[10];
4
ultoa(number,Buffer,10);
5
UART_SendString(Buffer);
6
}
7
8
voidUART_SendUI16(uint16_tnumber)
9
{
10
charBuffer[10];
11
utoa(number,Buffer,10);
12
UART_SendString(Buffer);
13
}
14
15
voidUART_SendD(doublenumber)
16
{
17
...
18
}
und schon bist du bereit, deine Register nach Herzenslust auszugeben
1
....
2
UART_SendString("ICR1 :");
3
UART_SendUI16(ICR1);
4
UART_SendString("\n");
5
...
und zwar ohne dass du ständig Bytes im HTerm entschlüsseln musst.
UNd wenn dir das immer noch zu mühsam ist, dann gibt es eben wieder eine
neue Hilfsfunktion
1
voidUART_Dump(char*Label,uint16_tvalue)
2
{
3
UART_SendString(Label);
4
UART_SendUI16(value);
5
UART_SendString("\n");
6
}
und schon ist es kein Thema mehr die Werte von TCNT1, ICR1 und
meinetwegen auch noch PIND auszugeben
1
....
2
UART_Dump("TCNT1 :",TCNT1);
3
UART_Dump("ICR1 :",ICR1);
4
UART_Dump("PIND :",PIND);
5
...
Lass dir die Dinge als Text hinschreiben (OK, der Text "Fehler:
Ueberlauf\n" ist ein bischen lang, da dauert dann die Übertragung schon
seine Zeit, so dass du das Timing deines Programmes eventuell
durcheinander bringst). Dann steht auf deinem Terminal schwarz auf weiss
dort
1
** neue Messung
2
TCNT1 : 8354
3
ICR1 : 8120
4
PIND : 127
5
6
--> Frequenz: 234,8
7
8
** neue Messung
9
TCNT1 : 8359
10
ICR1 : 8122
11
PIND : 127
12
13
--> Frequenz: 234,3
14
15
** neue Messung
16
--> Overflow
17
18
** neue Messung
19
TCNT1 : 8359
und das ist dann schon etwas ganz anderes als wenn man Hex-Bytes mühsam
entschlüsseln muss.
Ich werd nie verstehen, warum es so schwer ist, sich in ein paar Minuten
ein paar Hilfsfunktionen zu machen. Statt dessen wird da lieber mit
Krücken rumhantiert.
OK. Zurück zum Problem:
Ziel ist es heruaszufinden, ob die Werte in ICR1 schon springen oder
nicht und wenn ja um wieviel sie springen.
Sash uM schrieb:> Dieser hat eine Referenzspannung von einigen mV.
Wenn der Signalgenerator ein positives Signal gegen Masse liefert, dann
würde ich AIN0/PB2 auf halbe Signalspannung setzen.
Zum Testen des Codes den AC abschalten und über ICP1/PD6 mit einem
Rechtecksignal reingehen.
Karl Heinz Buchegger schrieb:> Dann mach dir doch als erstes mal vernünftige Ausgabefunktionen!> Nur mit einem UART_SendByte wirst du auf Dauer nicht weit kommen.
Wow, großen Dank für die ganzen Hilfefunktionen. Ich werde mich dann
schnellstmöglich darum kümmern.
MWS schrieb:> Zum Testen des Codes den AC abschalten und über ICP1/PD6 mit einem> Rechtecksignal reingehen.
Das ist auch eine gute Idee. Danke vielmals.
MWS schrieb:> Dürfte zwar nicht der eigentliche Fehler sein, ist aber dennoch falsch:TIFR |=
(1<<ICF1);Das veroderte Zurückschreiben in ein Flag-Register löscht nicht nur das
> gewünschte Bit, sondern alle die gesetzt waren.> Richtig ist's so:TIFR = (1<<ICF1);
Oh, das hatte ich nicht gewusst. Ich bin davon ausgegangen, dass nur das
Bit ICF1 gelöscht wird. Im Datenblatt stand beschrieben, dass zum
Zurücksetzen des Input Capture Flag das Bit ICF1 gesetzt werden muss.
Aber mit dem Befehl
REGISTER1 |= (1<<BIT1)
wird doch nur das Bit1 im Register1 gesetzt, oder?
Sash uM schrieb:> Aber mit dem Befehl> REGISTER1 |= (1<<BIT1)> wird doch nur das Bit1 im Register1 gesetzt, oder?
Da diese Schreibweise identisch ist zu
REGISTER1 = REGISTER1 | (1<<BIT1)
werden daher dann auch alle anderen Bits erneut als 1 in das Register
geschrieben, die auch vorher schon 1 waren. Und da in diesem Register
alle Bits auf Neubeschreiben mit 1 mit einem Zurücksetzen reagieren,
setzt
REGISTER1 |= (1<<BIT1)
alle bereits gesetzten Bits zurück.