Forum: Compiler & IDEs Timer Input Capture Unit Problem


von Steffen (Gast)


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.

von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

Sorry, hier der Anhang

von Steffen (Gast)


Lesenswert?

So ein Mist, wo liegt der Fehler? :-(

von Dirk (Gast)


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

von Steffen (Gast)


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.

von Dirk (Gast)


Lesenswert?

Hi,

hast du fuer dein Problem nun eine Loesung gefunden?

Gruß,

Dirk

von Steffen (Gast)


Lesenswert?

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

von pebisoft (Gast)


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

von Steffen (Gast)


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.

von Steffen (Gast)


Angehängte Dateien:

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?

von OldBug (Gast)


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

von Steffen (Gast)


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?

von OldBug (Gast)


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!

von Steffen (Gast)


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!!!!

von OldBug (Gast)


Lesenswert?

...dann sag mir doch bitte mal, was ein:
1
    sprintf(g_temp, "%d", 40000);
2
    lcd_puts(g_temp);

auf Deinem Display anzeigt ;)

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.