Hallo liebes Forum, ich habe ein Problem mit dem PORT B und dem Timer0 beim AT90CAN128 auf dem STK500 und hoffe auf hilfreiche Antworten. Der Timer hat ein OC0A Ausgang und liefert an diesem ein Rechtecksignal, das gleiche Rechtecksignal möchte ich in der ISR auch erzeugen. Das Problem bei unten stehendem Code ist, dass das Bit PORTB1 relativ häufig beim verlassen der ISR nochmal toggelt, d.h. es kommen entweder kurze Impulse oder ein high bzw. low Pegel, der doppelt so lange ist. Das Problem kann man beheben, indem man in der main vor dem Port-Zugriff den globalen Interrupt deaktiviert und danach wieder aktiviert oder man im AVR-Studio die Code-Optimierung auf -Os stellt. Hat jemand eine Lösung unter der Voraussetzung, dass ich den Interrupt in der main nicht deaktivieren möchte und die Code-Optimierung auf -O0 lasse? Dass ich keine Tastenentprellung habe ist mir bewusst, ändert aber an dem Phänomen nichts. Besten Dank für Eure Hilfe <c> #include <avr/io.h> #include <avr/interrupt.h> ISR(TIMER0_COMP_vect) { PORTB ^= (1<<PB4); } int main(void) { // Port B - LED´s, STK500 PORTB = 0x00; // Output Low DDRB = 0xff; // Output // Port E - Taster, STK500 PORTE = 0xff; // Pull-up DDRE = 0x00; // Input // Timer0 TCCR0A = 0x51; TCNT0 = 0; OCR0A = 0xFF; TIMSK0 |= (1<<OCIE0A); TIFR0 |= (1<<OCF0A); sei(); // Globaler Interrupt Enable while(1) { if(PINE & (1<<PB0)) PORTB |= (1<<PB1); else PORTB &= ~(1<<PB1); } return(0); } </c>
Ganz verstehe ich deine Problembeschreibung nicht. Du erzeugst ein Signal an PB4 (in der ISR) und PB1 (in main-while als Reaktion auf ein Eingangssignal auf PINE.0) und du erzeugst ein Signal an OC0A? Das Signal an PB1 soll synchron zu OC0A sein. Wie soll das gehen, wenn PINE.0 ein Taster (unentprellt) ist? Oder hast du OC0A mit PINE.0 verbunden? Ansonsten zu dem Problem der Unterberechung einer I0-Portmanipulation durch einen Interrupt: Schau nach, ob sich beim AT90CAN128 PB1 an PORTB bereits toggeln lässt indem du das PB1 Bit in PINB setzt. Bei "modernen" AVR ist das möglich und da das eine Maschinenanweisung ist, unterbricht der Timer das nicht. Wenn das nicht geht, würde ich Inline Assembler mit den Instruktionen SBI und CBI benutzen, um das eine Bit zu setzen bzw. zu löschen. Damit bekommst du auch eine nicht unterbrechbare Maschinenanweisung. Also quasi von Hand programmieren, was der Optimizer bei -Os macht (s. Disassemblerlistung)
Hallo Stefan, danke für die schnelle Antwort. In deinem ersten Abschnitt hast du den Sachverhalt richtig erkannt. nicht PORTB1 soll synchron zu OC0A sein sondern PORTB4, siehe ISR. OC0A ist fest auf PORTB7 und gibt mir ein Rechtecksignal, dass ich mit folgendem Register TCCR0A = 0x51 (hier hatte ich ein Fehler, es muss 0x1D heißen) einstelle. Es wird nicht synchron sein, aber sagen wir quasi synchron (die rund 10 Takte sollen keine Rolle spielen). Zum Taster, den betätige ich zu keinem Zeitpunkt, dennoch tritt das Problem durch die Zeile -> PORTB |= (1<<PB1); auf. Das Bit beim schreiben in PINB funktioniert, ändert aber am Verhalten nichts. Hinweis, würde ich in der main statt dem PORTB einen beliebig anderen PORT ansteuern, so tritt das Problem nicht auf. Wie funktioniert das mit dem Inline-Assembler? Im Anhang zeig ich mal ein Oszillogramm, rot=OC0A; blau=PORTB4 Gruß DS
Ah mit dem Diagramm wird das klarer! Also das OC0A = PORTB.7 Signal wird gestört. Das sieht nach einem Interrupt in dieser Sequenz aus: PORTB &= ~(1<<PB1); Das ist ja aufgeschlüsselt so etwas: tmp = PORTB; // hier ist OC0A z.b. LOW tmp &= ~(1<<PB1); // hier irgendwo wechselt OC0A nach HIGH PORTB = tmp; // hier bekommt OC0A den alten LOW Wert zurück :-( Ich würde hier die CBI/SBI Inline Assembler Methode für die Manipulation von PORTB.1 benutzen, wenn -Os nicht möglich ist. Inline Assembler bin ich nicht sattelfest, d.h. ich müsste auch erst hier nachsehen: http://www.nongnu.org/avr-libc/user-manual/inline__asm.html Vielleicht so etwas: asm("cbi %0, 1" : : "I" (_SFR_IO_ADDR(PORTB)) ); // PORTB.1 löschen asm("sbi %0, 1" : : "I" (_SFR_IO_ADDR(PORTB)) ); // PORTB.1 setzen
Vielen Dank für die schnelle Hilfe. if(PINE & (1<<TASTER0)) asm("sbi %0, 1" : : "I" (_SFR_IO_ADDR(PORTB)) ); else asm("cbi %0, 1" : : "I" (_SFR_IO_ADDR(PORTB)) ); hat das Problem gelöst. Schönen Abend noch Gruß DS
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.