Hallo zusammen, Testsystem= Atmega8 meine Auswertung eines DCC Protokolls funktioniert mit dem 16bit Timer1 sehr gut. Diesen habe ich bei 8Mhz als Fast/PWM mit "compare A = 696" initialisiert. Ich frage den Signalzustand am Eingang 87us nach dem Flankenwechsel ab. Bei Int0 (positive Flanke) setze ich also den OCR1A = 0 und bei compare frage ich den Eingang ab. soweit so gut. Ich möchte diesen Timer1 jetzt aber gegen den 8bit Timer2 tauschen. Eigentlich bietet dieser doch die gleiche Funktionalität, nur muss ich halt für eine 87us Abfrage den Prescaler und das compare Register ändern, richtig? Leider funktioniert das Programm mit Timer2 jedoch nicht. Da ich das Firmen Oszi grad nicht zur Hand habe, fällt mir auch die Fehlersuche schwer. Habt ihr eine Idee? Der auskommentiere Code // ist für den Timer2 Anbei nur der Code, in dem die Timer auch vorkommen. void Initialisierung (void) { //TCCR2 = (1<<CS21)+(1<<WGM20)+(1<<WGM21); // CS21 = Prescaler 8 // WGM20+21 = Fast PWM //TIMSK = (1<<OCIE2); // Timer2 Compare //OCR2 = 87; //87us bei 8Mhz ICR1 = 0xFFFF; //TOP-Wert für Zähler = 65536 OCR1A = 696; //87us bei 8Mhz TCCR1A = (1<<WGM11); // WGM11+12+13 = Fast PWM TCCR1B = (1<<WGM12)+(1<<WGM13)+(1<<CS10); //CS10 = no Prescaler TIMSK = (1<<OCIE1A); // Timer1 Compare A sei(); //alle interrupts aktivieren } ISR (INT0_vect) //bei interrupt int0 (steigende Flanke auf PD2) { TCNT1 = 0; // Timer 1 zurücksetzten (löst nach 87us einen Interrupt aus) //TCNT2 = 0; // Timer 1 zurücksetzten (löst nach 87us einen Interrupt aus) startcount++; } ISR (TIMER1_COMPA_vect) //ISR (TIMER2_COMP_vect) { dccbit = (~(PIN_D2) & (0x01)); dccbyte <<= 1; dccbyte = dccbyte + dccbit; bitcount++; }
Philipp L. schrieb: > void Initialisierung (void) > { > //TCCR2 = (1<<CS21)+(1<<WGM20)+(1<<WGM21); // CS21 = Prescaler 8 // > WGM20+21 = Fast PWM > //TIMSK = (1<<OCIE2); // Timer2 Compare > //OCR2 = 87; //87us bei 8Mhz Im Fast PWM wirkt OCR2 nicht als TOP und der Timer läuft bis 255. CTC Mode einstellen mit nur WGM21 ohne WGM20 im TCCR. (OCR2 für exakte 87µs auf 86 setzen, da noch eine µs für Rücksetzen auf 0 verbraten wird)
Ja, Top ist 255 und OCR2 sollte doch das compare Register sein? Laut Datenblatt: "Output Compare Register – OCR2" Meine Theorie war, dass der Timer bis 255 läuft, jedoch schon bei OCR2 einen Interrupt "ISR (TIMER2_COMP_vect)" auslöst. Bei jeder positiven Flanke wird dann der TCNT2 = 0 gesetzt. Also die gleiche Funktion wie bei Timer1, nur bezogen auf 8 Bit ? Ich habe auch schon versucht, den "compre match" nach dem Interrupt zu deaktivieren und erst beim Start (positive Flanke) zu aktivieren. Funktioniert leider auch nicht. Wenn ich den Timer als CTC betreibe, muss ich auf Overflow und nicht Compare abfragen, richtig?
Philipp L. schrieb: > Wenn ich den Timer als CTC betreibe, muss ich auf Overflow und nicht > Compare abfragen, richtig? Steht im Datenblatt. Es geht beides. Das OC2 Flag wird bei erreichen von TOP gesetzt und das TOV2 Flag beim Rücksetzen des Zählers auf 0.
Philipp L. schrieb: > Ja, Top ist 255 und OCR2 sollte doch das compare Register sein? > Laut Datenblatt: "Output Compare Register – OCR2" > > Meine Theorie war, dass der Timer bis 255 läuft, jedoch bei OCR2 einen > Interrupt "ISR (TIMER2_COMP_vect)" auslöst. > Bei jeder Flanke wird dann der TCNT2 = 0 gesetzt. Ah, OK. Hatte da nicht durchgeblickt. Hattest du auch in TIMSK den OCIE2 Interrupt enabled? > Wenn ich den Timer als CTC betreibe, muss ich auf Overflow und nicht > Compare abfragen, richtig? Nein, das wäre auch Compare. Overflow tritt nicht ein, da TCNT nicht bis Maximum läuft.
gürteltier schrieb: > Ah, OK. Hatte da nicht durchgeblickt. Hattest du auch in TIMSK den OCIE2 > Interrupt enabled? Ja, habe ich. //TCCR2 = (1<<CS21)+(1<<WGM20)+(1<<WGM21); // Prescaler 8 + Fast PWM //TIMSK = (1<<OCIE2); // Timer2 Compare enable //OCR2 = 87; //87us bei 8Mhz
Philipp L. schrieb: > Leider funktioniert das Programm mit Timer2 jedoch nicht. Was genau funktioniert nicht? Gibt es keinen Compare Match 2 Interrupt? Woran siehst du das es nicht funktioniert? > Habt ihr eine Idee? Ich finde eigentlich keinen Fehler in dem Wechsel zum Timer2. Wie genau müssen die 87µs eingehalten werden? Vielleicht 1µs nach oben oder unten variieren.
gürteltier schrieb: > Wie genau > müssen die 87µs eingehalten werden? Eine 1 ist 58µs, eine 0 >= 116µs. Der Unterschied muß erkannt werden. Das passt also mit den 87µs.
> Was genau funktioniert nicht? Gibt es keinen Compare Match 2 Interrupt? > Woran siehst du das es nicht funktioniert? Es ist eine "komplexere" Geschichte. Mikrocontroller 1 wertet das DCC Protokoll Am Eingang von PD2 aus und gibt bestimmte Bytes über SPI zu Controller2. Dieser zeigt die Werte auf dem Display an. Meine Diagnose beschränkt sich also aktuell noch auf die Displayausgabe. Sobald ich auf Timer2 wechsel, erfolgt keine Aktualisierung der Variablen auf dem Display von Controller2. >> Habt ihr eine Idee? > > Ich finde eigentlich keinen Fehler in dem Wechsel zum Timer2. Wie genau > müssen die 87µs eingehalten werden? Vielleicht 1µs nach oben oder unten > variieren. ich sollte so ca. +-10..15us genau sein. Dies ist eine 1 im DCC Protokoll: | 58us | 58us | +++++++++++++------------- <- Wechsel von Signal + zu - | 87us | <- Es ist also etwas Spielraum vorhanden.
Philipp L. schrieb: > Da ich das Firmen Oszi grad nicht zur Hand habe, fällt mir auch die > Fehlersuche schwer. Für solche Aufgaben reicht ein minimalistischer Logikanalysator zum Preis eines Kantinenessens. Dafür brauchst du kein Oszi. Oder du guckst deinem µC im Simulator auf die Register.
> Für solche Aufgaben reicht ein minimalistischer Logikanalysator zum > Preis eines Kantinenessens. Dafür brauchst du kein Ja, habe ich aber auch nicht zur Hand. Wenn euch kein Fehler auffällt, nehme ich zum Wochenende das Oszi mit Logikanalyser mit.
ich kann zwar erst morgen das Oszi mitnehmen, aber es scheint an der Initialisierung des Timer2 zu liegen. Wenn ich nämlich den Timer1 wie einen 8 Bit Timer initialisiere, funktioniert das Programm noch immer einwandfrei. ICR1 = 255; //TOP-Wert für Zähler = 255 OCR1A = 87; //87us bei 8Mhz TCCR1A = (1<<WGM11); // WGM11+12+13 = Fast PWM TCCR1B = (1<<WGM12)+(1<<WGM13)+(1<<CS11); //CS11 = Prescaler 8 TIMSK = (1<<OCIE1A); // Timer1 Compare A Also scheint es nicht an irgendwelchen Timingproblemen durch den Prescaler oder den begrenzten Top-Wert zu liegen. Was mache ich falsch beim Wechsel von Timer 1 auf den Timer2 ?... Der Timer2 sollte doch mit folgender Initialisierung die gleiche Funktion wie der oben genannte Timer1 haben? //TCCR2 = (1<<CS21)+(1<<WGM20)+(1<<WGM21); // Prescaler 8 // Fast PWM //TIMSK = (1<<OCIE2); // Timer2 Compare //OCR2 = 87; //87us bei 8Mhz Die Interrupt Routine habe ich so geändert: //ISR (TIMER1_COMPA_vect) // ALT ISR (TIMER2_COMP_vect) // Neu Der Reset wurde so angepasst: //TCNT1 = 0; // ALT TCNT2 = 0; // Neu an mehr Stellen erscheinen die Timer nicht, muss doch etwas ganz einfaches sein?
Noch eine Info, es scheint kein Interrupt ausgelöst zu werden. Wenn ich innerhalb der Interrupt Routine "ISR (TIMER2_COMP_vect)" einen Ausgang auf 1 schalte, wird dieser niemals gesetzt..
Ich sehe für Timer2 nur Auskommentiertes. Wie sieht konkret der aktuelle Programmstand aus?
Sorry, das Auskommentierte ist im Programm nicht mehr Auskommentiert. Der obere Teil für die Timer1 Initialisierung ist Auskommentiert. Hatte ich zu einem falschen Zeitpunkt in den Beitrag kopiert. TCCR2 = (1<<CS21)+(1<<WGM20)+(1<<WGM21); // Prescaler 8 // Fast PWM TIMSK = (1<<OCIE2); // Timer2 Compare OCR2 = 87; //87us bei 8Mhz Die Interrupt Routine habe ich so geändert: //ISR (TIMER1_COMPA_vect) // ALT ISR (TIMER2_COMP_vect) // Neu Der Reset wurde so angepasst: //TCNT1 = 0; // ALT TCNT2 = 0; // Neu Ich habe folgendes im Datenblatt gelesen: Writing to the TCNT2 Register blocks (removes) the Compare Match on the following timer clock. Was ist hier mit following clock gemeint, doch nur ein compare im direkt nächsten Takt, oder nicht? Wenn ich TCNT2 auf 0 setzte und OCR2 dauerhaft bei 87 ist, sollte es doch keine Probleme geben?
Wie sieht derzeit dies void Initialisierung aus, möglichst komplett?
void Initialisierung (void) //Timer und Interrupts aktivieren und einstellen { DDRD &= ~(1<<PD2); DDRD &= ~(1<<PD3); DDRB |= (1<<PB1); PORTB = 0x00; Adresse = eeprom_read_byte((uint8_t*) 1); MCUCR |= (1<<ISC01)|(1<<ISC00); MCUCR |= (1<<ISC11)|(1<<ISC10); GICR |= (1<<INT0)+(1<<INT1); TCCR2 |= (1<<CS21)+(1<<WGM20)+(1<<WGM21); TCNT2 = 0; TIMSK = (1<<OCIE2); OCR2 = 87; //ICR1 = 200; //OCR1A = 87; //TCCR1A = (1<<WGM11); //TCCR1B = (1<<WGM12)+(1<<WGM13)+(1<<CS11); //TIMSK = (1<<OCIE1A); sei(); }
Ich benutze den Timer nur in 2 Funktionen: ISR (INT0_vect) { //TCNT1 = 0; TCNT2 = 0; startcount++; } //ISR (TIMER1_COMPA_vect) ISR (TIMER2_COMP_vect) { PORT_B1 = 1; dccbit = (~(PIN_D2) & (0x01)); dccbyte <<= 1; dccbyte = dccbyte + dccbit; bitcount++; } Mir ist da grad noch folgende Kuriosität aufgefallen: Wenn beim Controller sofort nach dem Start das Protokoll anliegt, wird der compare nie erreicht (PB1 bleibt aus). Wenn der Eingang beim Controllerstart aber auf "5V ODER 0V ODER in der Luft hängt" , wird der compare erreicht. Danach kann ich auch das Signal anlegen und alles läuft super. Aber es darf beim Start kein Signal anliegen. Verstehe ich nicht....
OCR2 wird nach Loslaufen des Timer2 im Fast PWM gesetzt. OCR2 wird im Fast PWM dann erst nach einem kompletten Timerdurchlauf bis MAX beim BOTTOM upgedatet und erst danach kann beim zweiten Hochlauf der erste Compare Interrupt erfolgen. OCR1A setzt du vor Setzen des modes und Starten des Timer1. Der Compare Interrupt kann sofort beim ersten Hochlauf des Timers erfolgen, da OCR1A im noch Normalmode sofort upgedatet wird. Ein Strohhalm aber vielleicht OCR2 mal vor dem Setzen von TCCR2 initialisieren.
> Ein Strohhalm ...
Klingt pausibel; da bei laufendem Protokoll ständig TCNT2=0 gesetzt
wird, wird OCR2 wegen der Pufferung im PWM-Modus nie übernommen.
> Ein Strohhalm aber vielleicht OCR2 mal vor dem Setzen von TCCR2 > initialisieren. Manchmal liegt die Lösung doch so nah... Danke!!
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.