www.mikrocontroller.net

Forum: Compiler & IDEs Timer Input Capture Unit Problem


Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
bin mal wieder auf ein Problem gestoßen. Ich habe vor die Zeit zwischen
zwei Impulsen zu messen um darauß auf die Drehzahl eines Motors zu
kommen (mit ATmega16).
Klingt ja eigentlich einfach, dachte ich mir auch aber leider hackt es
noch.
Die Einstellungen:

TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS11) | (1<<CS10);

//Noise Canceler -->ICNC1
//Aufsteigende Flanke -->ICES1
//Prescaler-->64

SREG |= (1<<7);  //Global Interrupt Enable (Muss das überhaupt sein?)

Ich habe mir vorgestellt die Input Capture Flag abzufragen. Wenn die
Flag gesetzt ist (1) dann wird doch das Zählergebnis von TCNT1L/H nach
ICR1L/H kopiert.

Aber die If-Anweisungen funktionieren irgendwie nicht:

if(ICF1==1){ //Input Capture Flag
...
das selbe bei der Overflow Flag
if(TOV1==1){
...
Ich bekomme keine Ausgabe über das LCD.
Im Anhang ist das Programm, darin enthalten ist noch eine ADC Routine
die ich aber mit einer while(0) zum testen übersprungen habe.

Autor: Steffen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, hier der Anhang

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ein Mist, wo liegt der Fehler? :-(

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich bin nun kein Profi werde aber versuchen Dir zu helfen.

>SREG |= (1<<7);  //Global Interrupt Enable (Muss das überhaupt sein?)

Das geht einfacher mit: sei();

>sreg = SREG;

Hierzu habe ich selber eine Frage: Wieso rettest du das SREG ? Das
sollte doch der Compiler selber machen.

Zu deinem eigentlichen Problem bin ich mir recht unsicher.

Ich wuerde dieses ganz anders machen.

Ich wuerde eine Variable nehmen und diese als Flag Register fuer deine
Sachen nehmen.

Beispiel:
#define ICF_FLAG 0
#define TIMER0_OVFFLAG 1



// Globale Variable als Flag Register
volatile unsigned char  Status_byte


SIGNAL(InputCapture)
{
  Status_byte |= (1<<ICF_FLAG);
}

SIGNAL(SIG_OVERFLOW0)
{
  Statusbyte |= (1<<TIMER0_OVFFLAG);
}

Jetzt kannst du in der Main diese Flags abfragen

int main(void)
{
   if (Status_byte & (1<<ICF_FLAG))
   { // ICF FLAG WURDE GESETZT }

   if (Status_byte & (1<<TIMER0_OVFFLAG))
   { // TIMER0_OVFFLAG WURDE GESETZT }
}

Mfg
Dirk

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Dirk,

das mit dem SREG hab ich aus dem AVR Tutorial entnommen. Als ich deinen
Vorschlag gelesen hatte, bin ich auf die Idee gekommen die If
Anweisungen so zu formulieren:

if(TIFR & (1<<ICF1)){
...
}
if(TIFR & (1<<TOV1)){
...
}
Das Ergebnis, er hat anscheindend die Overflow Flag erkannt und gibt
mir jetzt "Motor aus" auf dem LCD aus. Sobald ich mit einem Taster
ein Signal am ICP simuliere (schnelles betätigen des Tasters),
verschwindet die Meldung auch wieder. Aber eigentlich sollte er mir
anstatt eines leeren LCD die Drehzahl ausgeben.

Ansonsten werde ich mal deine Variante mit Interrupt ausprobieren.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hast du fuer dein Problem nun eine Loesung gefunden?

Gruß,

Dirk

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein leider noch nicht :-(
Ich habe jetzt auch mal einen Frequenzgenerator angeschlossen, aber der
Efekt ist der selbe. Irgendwas mit ICF1 stimmt nicht.

Autor: pebisoft (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die drehzahl damit kontrollieren geht sehr schlecht. wenn die batterie
leerer wird, stimmt schon alles nicht mehr.
ausser du betreibst über netzteil dann geht es quasimoro.
mfg pebisoft

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Fehler gefunden warum er nicht die if Anweisung mit ICF1
ausführt. Ich hatte noch den Interrupt für Input Capture (TICIE1)
"eingeschaltet".
Allerdings sind die Werte total kaotisch. Bei 200Hz (Signal an ICP)
z.B. bekomme ich -22528 RPM, dabei müssten es eigentlich genau 6000 RPM
sein.

RPM=78125/timer_wert*60

Wieso wird das Ergbnis manchmal negativ?
Bei 1kHz schwangt der Wert sehr stark und leider auch total falsch.

Autor: Steffen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Der neuste Stand:

Ich hab das ganze mal mit den Interrupts (Input Capture und Overflow)
umgeschrieben.
Ich lass mir jetzt auch den Timerwert ausgeben um besser zu debugen.
Den Code hab ich mir etwas abgeschaut und umgeschrieben.

Hier das Ergebnis:
Bei einer Frequenz von 200Hz (Signal) und der Frequenz 156,25kHz des
Timers, müsste der Timerwert (16Bit) genau 780 betragen. Aber auf dem
Display sind es nur 78 und die errechnete Umdrehung ist -25600!
Etwas eigenartig denn wenn ich richtig liege entspricht der Wert des
Timers = (1/200Hz)/(1/156250Hz) = 0,005s/0,0000064 = 780!
Was ist da Faul?

Hab ich einen Fehler in der Berechnung? Wieso bekomme ich solche Werte
bei der Umdrehung raus?

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, naja...

Möglicherweise wieder 'nur' ein Anzeigeproblem!?

[..]
float rpm=0;
[..]
sprintf(g_temp," RPM %d", rpm); // zwischen_erg anstatt rpm
[..]

Das passt nicht wirklich zusammen, oder? ;)
Probiere es mal mit

sprintf(g_temp," RPM %f", rpm); // zwischen_erg anstatt rpm

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also daran liegt es nicht, allerdings hast du mich auf einen Fehler beim
deklarieren der Variablen hingewiesen!
Es muss natürlich so sein:

float zwischen_erg;
unsigned int rpm = 0;

Was ich nicht verstehe, selbst wenn der Inhalt vom Timer falsch ist
(und das ist er) müsste er mir doch trotzdem ein dazu passendes
Ergebnis errechnen. Macht er aber nicht. :-(

Bei den sprintf() Funktionen gibt er mir diese Warnung raus,

"implicit declaration of function `sprintf'"

hat das was zu bedeuten, also hat das Einfluß auf die Anzeige?

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na super...

Du hast wahrscheinlich vergessen, die printf-Lib einzubinden (dem
Linker bekannt machen).
Trotzdem: unsigned int kann ebenfalls nicht mit dem %d Formatstring
korrekt angezeigt werden. Dafür gibt es %u!

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich muss dich enttäuschen, das Programm arbeitet Einwandfrei!
Ich hab den Fehler gefunden, das Problem lag am Clock ich hatte die
falschen fuse bits gesetzt.

Oh man bin ich froh das es funktioniert. :-)

Aber trotzdem an alle nochmal vielen Dank!!!!

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...dann sag mir doch bitte mal, was ein:
    sprintf(g_temp, "%d", 40000);
    lcd_puts(g_temp);

auf Deinem Display anzeigt ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.