Hallo Allerseits, ich zerbrech mir grad den Kopf über einer ziemlich einfachen Aufgabe. Ich möchte gerne mit dem Timer 1 zwei Interrupts auslösen, einmal bei OCR1A match und einmal mit OCR1B match. Mit OCR1A hauts einwandfrei hin, nur mit B geht gar nix. Zum messen toggle ich zwei verschieden Ports in den ISRs. Was mir aber schon nicht komisch vorkommt, dass es im DB unter den Modi nur einen gibt der bis OCR1A zählt, und nix mit OCR1B? mein Code: (Mega8 16MHz) TCCR1B|= (1<<CS11)|(1<<WGM12); //Systemtakt durch 8 teilen OCR1A = 1000; OCR1B = 10000; TIMSK|=(1<<OCIE1A)|(1<<OCIE1B); DDR_OUT|=(1<<CLK)|(1<<ENABLE)|(1<<DIRECTION); sei(); ... ISR(TIMER1_COMPA_vect) { PORT_OUT^=(1<<CLK); } ISR(TIMER1_COMPB_vect) { PORT_OUT^=(1<<ENABLE); } Der A läuft, nur der B tut gar nix, außer ich setze beide OCRs auf den gleichen Wert? Komischerweise kommt beim B auch etwas raus, wenn ich den A auf 10000 und B auf 1000 setze??? Kann mir jemand sagen, wo mein Denkfehler liegt? Danke Philipp
Wenn ich mich nicht irre, betreibst du den Timer im "Clear Timer on Compare Match"-Modus...
Hatte ich auch schon mal. Ich bin davon ausgegangen: Im DB nicht für OCR1B beschrieben, also geht CTC dafür nicht.
Philipp Putzer schrieb:
> Kann mir jemand sagen, wo mein Denkfehler liegt?
Überlege mal, wie der CTC-Mode konkret mit einem Compare-Match
funktioniert. Und dann versuchst du mal, es auf einen Timer und zwei
Compare-Matches zu erweitern. Dann wirst du es schon merken.
hh!, genau, das isses! Man klar. Der zählt mir am Ende immer nur bis zum OCR1A, oder bis zu dem niedrigeren halt! Mal schaun was sich da machen lässt!
Philipp Putzer schrieb:
> oder bis zu dem niedrigeren halt!
laut Datenblatt ist der TOP-Wert im CTC-Modus immer OCR1A
Moin, kleiner Denkanstoss: Nimm FastPWM mit TOP in ICR1. Gruß, Stefan
nimm doch den "Mode 12" (Datenblatt S. 99) WGM13 und WGM 12 = 1, WGM 11 und WGM 10 = 0 mit ICR1 = x kannst du für x deinen CTC wert eingeben und hast für den fall daß OCR1A und OCR1B < ICR1 beide comparewerte zur verfügung.
ok, das werd ich mal versuchen. Momentan verwende ich den Timer 1 und den Timer 2 im CTC Modus. Nur wenn ich das Programm erweitere und noch mehr timer brauchen sollte kann ich auf den ICR vom T1 zurückgreifen und kann den T2 für sonstwas verwenden Vielen Dank für die Hilfe! Gruß Philipp
Das mit dem ICR1 ist Quatsch, damit sind die beiden Compares nicht unabhängig. Du mußt in den Interrupts einfach nur OCR1A/B += Intervall_A/B; machen und aus die Maus. Der Timer muß durchlaufen ohne Clear on Compare, sonst geht die Addition nicht. Und den Overflow- und den Capture-Interrupt kannst Du dann auch noch uneingeschränkt benutzen. Peter
Peter Dannegger schrieb: > Das mit dem ICR1 ist Quatsch, damit sind die beiden Compares nicht > unabhängig. > > Peter ich will dir nicht gern wiedersprechen, ich tus aber dennoch, da ich das genau in der kombination bei mir im aktuellen projekt problemlos laufen habe: (ist allerdings bei mir auf basis atmega1280, sollte aber egal sein, da der 16 bit timer ja gleich aufgebaut ist, hier mal meine codeschnipsel: initialisierung: // Timer 5 CTC Mode aktivieren + Vorteiler (256) setzen TCCR5B |= (1<<WGM52) | (1<<WGM53)| (1<<CS52); // Vergleichswert setzen ICR5 = 26473; //39062 Schritte ->ca. 1s (39062*25.6µs) // Interrupt wird durch Compare Match (B und C) ausgelöst TIMSK5 = (1<<OCIE5B) | (1<<OCIE5C); //ISR wird ausgelöst und hier die zugehörigen ISR: ISR(TIMER5_COMPB_vect) { if(Display_Verzoegerung_Temp >= Display_Verzoegerung) { // Display wird abgedunkelt auf Schlafmodus (Pin PH3!) Displaybeleuchtung = 0; Display_Verzoegerung_Temp = 0; //Variable rücksetzen } else if(Displaybeleuchtung == 1) { Display_Verzoegerung_Temp ++; //Wenn Display nicht im Schlafmodus -> Variable Hochzählen, sonst nichts tun } else { OCR5B = ICR5 + 10; //Comparewert auf einen Wert jenseits des Zählbereichs legen und damit Interrupt stoppen (Alternative zum Demaskieren) } } ISR(TIMER5_COMPC_vect) { if(Hauslicht_Aktiv == 2) { if(Hauslicht_Zeit_Temp >= Hauslicht_Zeit) { //Hauslicht wieder abschalten Hauslicht_Aktiv = 3; Hauslicht_Zeit_Temp = 0; } else { Hauslicht_Zeit_Temp ++; } } else { OCR5C = ICR5 + 10; //Comparewert auf einen Wert jenseits des Zählbereichs legen und damit Interrupt stoppen (Alternative zum Demaskieren) } } sinn des ganzen ist bei mir: einen 1 sec timer im hintergrund laufen zu haben. wenn ich dann eine der beiden aktionen ausführen will starte ich diese mit den folgenden zeilen im hauptprogramm: OCR5B = TCNT5; oder OCR5C = TCNT5; da der code bei mir funktioniert gehe ich davon aus, daß er richtig ist. ich habe somit (bei meinem controller) die möglichkeit 3 "virtuelle" timer mit der selben zeitbasis zu starten welche aber unabhängig voneinander laufen. so wie ichs verstanden habe will er das so machen. wenn er nat. COMPA 10 mal häufiger als COMPB ausführen möchte geht dies so nicht direkt. ich habe den jeweiligen interrupt hier gestoppt, indem ich den comparewert über den CTC wert lege. das hat den hintergrund, daß ich eben nur die eine zuweisung benötige um den timer wieder zu starten und nicht den interrupt noch maskieren muss. aber das nur am rande, den Compare A habe ich noch frei, da ich ihn derzeit noch nicht benötige.
Christian B. schrieb: > Peter Dannegger schrieb: >> Das mit dem ICR1 ist Quatsch, damit sind die beiden Compares nicht >> unabhängig. >> >> Peter > > ich will dir nicht gern wiedersprechen, ich tus aber dennoch, da ich das > genau in der kombination bei mir im aktuellen projekt problemlos laufen > habe: Du hast für alle deine Interrupts dieselbe Zeitbasis (1 Sekunde) und wozu du in deiner Anwendung einen Compare-Match benötigst, ist mir ehrlich gesagt schleierhaft. Deine 2 virtuellen 1-Sekunden Timer hättest du auch ganz bequem in eine einzige ISR packen können. Aber gut, so kannst du durch den Wert im OCR Register die Funktionalität ein bzw. ausschalten. Du benutzt sie Quasi als Flag, der tatsächliche OCR Wert ist mehr oder weniger uninteressant. Hauptsache im ICR1 Bereich bzw. ausserhalb. Aber versuch doch mal das ganze so aufzusetzen, dass der Compare Match A alle 300 Take und der Compare Match B alle 500 Takte kommt. Da wirst du Schiffbruch erleiden :-) Das geht nur so, wie Peter das vorschlägt.
das mag sein, aber wie ich bereits schrieb: ich habs so verstanden, daß er eine zeitbasis für beide verwenden will. andernfalls sieht die sache natürlich auch anders aus. wobei, wenn mans geschickt anstellt geht auch das, die endaktion die die beiden compares bei mir ausführen wird einmal nach ca 20 sek (B) und einmal nach ca, 1,5 min (C) ausgeführt. beide werte sind aber sekundengenau variabel einstellbar bis reichlich 4 minuten.
Christian B. schrieb: > das mag sein, aber wie ich bereits schrieb: ich habs so verstanden, daß > er eine zeitbasis für beide verwenden will. Das geht leider aus dem Ursprungsposting nicht klar hervor. Soll es etwas mehr PWM artiges sein oder sollen die Comparematch tatsächliche Taktzähler sein. Ersteres geht mit dem Copmare Match Registern wenn man darauf achtet, dass der Endwert des Timers nicht von einem der beiden abhängt, also so wie du das hast. Letzteres geht aber nur mit der vom Peter vorgeschlagenen Methode vernünftig. Allerdings kann man auch ersteres damit machen :-) > wobei, wenn mans geschickt anstellt geht auch das, > die endaktion die die beiden compares bei mir ausführen > wird einmal nach ca 20 sek (B) und einmal nach ca, 1,5 min (C) > ausgeführt. Für das, was du da machst, hätte man überhaupt keinen Compare Match benötigt :-) Das lässt sich ganz bequenm mit jeweils einem Software-Zähler, der von einem Startwert auf 0 runterzählt erledigen. Der Timer fungiert dann nur noch als 1-Sekunde Zeitsignal.
1 | ISR( Overflow vom Timer 5 ) // so eingestellt, dass er jede Sekunde |
2 | // aufgerufen wird
|
3 | {
|
4 | if( Display_Verzoegerung_Temp > 0 ) { |
5 | Display_Verzoegerung_Temp--; |
6 | if( Display_Verzoegerung_Temp == 0 ) |
7 | // Display wird abgedunkelt auf Schlafmodus (Pin PH3!)
|
8 | Displaybeleuchtung = 0; |
9 | }
|
10 | |
11 | if( Hauslicht_Zeit_Temp > 0 ) { |
12 | Hauslicht_Zeit_Temp--; |
13 | if( Hauslicht_Zeit_Temp == 0 ) |
14 | Hauslicht_Aktiv = 3; |
15 | }
|
16 | }
|
Zum einschalten des Displays, weist du der Variablen Display_Verzoegerung_Temp die Zeit in Sekunden zu, nach der es sich deaktivieren soll. Selbiges für Hauslicht_Zeit_Temp. Wird eine Taste gedrückt, wird einfach nur die jeweilige xxx_temp Variable wieder auf die verzögerungszeit gesetzt. Ist das Display noch aktiv, so beginnt die Zeit erneut zu laufen ... der Timer wird retriggert. Und natürlich kann man noch 20 bis x weitere derartige Countdown-Timer nach demselben Muster machen. Sind beide bereits abgeschaltet, wird zwar die ISR noch aufgerufen, aber das bischen Rechenzeit, das dabei verbraucht wird, fällt unter "ferner liefen".
das hätte dann aber einen nachteil: wenn ich z.b. einen wert nach 4 sek haben will und das nach deiner methode mache dann habe ich bei 4 durchläufen das ergebnis in einem bereich von 4-5 oder 3-4 sekunden, je nach zählweise. in dem einen extremfall kann es ja sein, daß der zähler eben gerade aus der isr kommt wenn das neue signal getriggert wird. dann läuft er einmal komplett durch bis zum ersten hochzählen. der andere extremfall ist, daß die aktion getriggert wird und quasi mit dem folgenden takt die isr ausgelöst wird, somit würde ich eine sekunde unterschied haben. gut, man kann sich nun drüber streiten ob 1 sek bei max 4 min laufzeit etwas ausmacht, das würde ich eher als "rauschen" abtun und währe mir egal. wenn ich aber etwas nur 2 sekunden lang z.b. machen möchte dann macht es imho schon einen unterschied, ob das einmal 2 und einmal 3 sekunden lang dauert. alternativ könnte man eine 16 bit zählvariable verwenden und die zeitbasis auf 100ms stellen. ein "rauschen" von 100ms würde bei 1 sek nicht weiter stören, auch nicht bei 1 sek abarbeitungszeiten. aber das führt jetzt weg vom toppic und hilft dem threadersteller überhaupt nicht weiter. er wollte ja etwas mit beiden comparewerten machen, daher lag für mich der verdacht nahe, daß es sich um die selbe zeitbasis handelt, sonst macht es ja wenig bis keinen sinn. man darf ja auch nicht vergessen, daß ich bei meinem controller 6 timer zur verfügung habe, ich kann also etwas verschwenderisch damit umgehen wenn ich will :)
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.