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.
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
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.
Hi, hast du fuer dein Problem nun eine Loesung gefunden? Gruß, Dirk
Nein leider noch nicht :-( Ich habe jetzt auch mal einen Frequenzgenerator angeschlossen, aber der Efekt ist der selbe. Irgendwas mit ICF1 stimmt nicht.
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
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.
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?
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
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?
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!
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!!!!
...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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.