Hallo allerseits, habe vor kurzem mit der AVR Programmierung angefangen und habe da grade ein Problem, das mich etwas verwirrt. Kurze Beschreibung: Attiny24A, simple Schaltung, Tastendruck an INT0 soll globale Variable setzen, main dann entsprechend handeln. Klappt nur nicht. Relevante Code-Teile sehen so aus: /* GLOBALE VARIABLEN */ volatile uint8_t diceButtonPressed = 0; // Wuerfeltaste /* INTERRUPT-ROUTINEN */ /* Bei Tastendruck Start des Wuerfelvorgangs. */ ISR(EXT_INT0_vect) { diceButtonPressed = 1; PINB |= (1<<TEST_OUT_PIN); // Test-LED Interrupt erreicht reti(); } .... int main(void) { uint8_t dicevalue = 0; initPorts(); initInterrupts(); while(1) { if (diceButtonPressed) { ...do a lot of strange and beautiful things... ... So.... irgendwie wird aber die If-Bedingung nie erfüllt. Die globale Variable, die als Marker dienen soll, ist als volatile gekennzeichnet. Der Interrupt wird auch erreicht, d.h. der INT ist richtig enabled etc., Taste löst ihn auch aus, der ändert in der ISR den TEST_OUT_PIN, kann man sehr gut verfolgen. Die ISR müsste also die Variable auf 1 setzen und dann zurückkehren. Sehr simpel eigentlich. Es gibt keinerlei andere Teile im Programm, die auf die diceButtonPressed Variable zugreifen, weder lesend noch schreibend. Direkt hinter der if-bedingung hab ich auch schon die Ausgabe auf den Testpin vorgenommen, einfach um auszuschliessen, das da irgendwas nicht klappt, nix passiert. Der Teil hinter dem if wird einfach nie erreicht und ich kapiere nicht, warum nicht. Wäre prima, wenn mir da jemand weiterhelfen könnte...
Interrupt einschalten: sei(). Was soll das reti() sein? Macht der Compiler selber und richtiger. Aber: Taster als Quelle von Interrupt sorgt für Freude, weil er prellt.
:
Bearbeitet durch User
Interrupt ist an. Wie geschrieben kommt er in die ISR. Prellen ist in diesem Stadium noch egal und hat auf das Problem keine Auswirkungen.
Martin Luerssen schrieb: > PINB |= (1<<TEST_OUT_PIN); // Test-LED Interrupt erreicht PINB wird Dir nicht wirklich etwas anzeigen. Um ein Bit an einem Port zu setzen verwendet man PORT(X), in deinem Fall PORTB. Dazu muss auch das DDRB Register richtig gesetzt sein. PIN(X) wird zum einlesen verwendet. Das mal als Hinweis. Setzt Du die Variable diceButtonPressed in der main irgendwann auf 0? Zeig mal den ganzen Code, sonst kann man Dir nicht wirklich helfen. Und den reti() im ISR, schmeiß bitte raus.
Danke erstmal, Reti rausschmeissen versuche ich mal. Natuerlich ist der Testpin auf Ausgang geschaltet und den mit 1 zu beschreiben invertiert den Zustand des Portausgangs. Ist die einfachste Art einen Portpin blinken zu lassen und so aucb in den Datasheets beschrieben. Die diceButtonpressed Variable "würde" am ende des iif teils auf 0 gesetzt. Wird aber ja nie erreicht. VG OldMan schrieb: > Martin Luerssen schrieb: > PINB |= (1<<TEST_OUT_PIN); // Test-LED Interrupt erreicht > > PINB wird Dir nicht wirklich etwas anzeigen. > Um ein Bit an einem Port zu setzen verwendet man PORT(X), in deinem Fall > PORTB. Dazu muss auch das DDRB Register richtig gesetzt sein. > PIN(X) wird zum einlesen verwendet. > Das mal als Hinweis. > > Setzt Du die Variable diceButtonPressed in der main irgendwann auf 0? > Zeig mal den ganzen Code, sonst kann man Dir nicht wirklich helfen. > > Und den reti() im ISR, schmeiß bitt
Zum Pin B nochmal: Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn.
Immer die alte Leier, aber vielleicht unbekannt, da erst seit vorgestern dabei: das Programm auf das nötige Minimum reduzieren und dann im Original hier vorstellen.
Martin Luerssen schrieb: > ISR(EXT_INT0_vect) { > > diceButtonPressed = 1; > PINB |= (1<<TEST_OUT_PIN); // Test-LED Interrupt erreicht > reti(); > } Dein Programm hat keine ISR für INT0. Deswegen springt der Controller beim Auslösen des Interrupts auf 0 und fängt wieder von vorne an. Der Vektor heisst 'INT0_vect'. 'EXT_INT0_vect' kennt der Compiler nicht. Dafür hast du auch eine Warnung bekommen. Warnungen sind nicht zum ignorieren da! Also:
1 | ISR(INT0_vect) |
Und das reti() gehört nicht in die ISR, das wurde ja schon gesagt. mfg.
:
Bearbeitet durch User
Thomas Eckmann schrieb: > Der Vektor heisst 'INT0_vect'. 'EXT_INT0_vect' kennt der Compiler nicht. Doch, beim Tiny24 heißt der genau so.
Stefan Ernst schrieb: > Doch, beim Tiny24 heißt der genau so.
1 | /* Interrupt vectors */
|
2 | /* Vector 0 is the reset vector */
|
3 | #define EXT_INT0_vect_num 1
|
4 | #define EXT_INT0_vect _VECTOR(1) /* External Interrupt Request 0 */ |
Welcher Knallkopp hat das denn verzapft? Damit ist mein Post nicht mehr gültig. mfg.
:
Bearbeitet durch User
Thomas Eckmann schrieb: > Welcher Knallkopp hat das denn verzapft? Das Problem sich gelegentlich von Produkt zu Produkt ändernder Handler-Namen für die gleiche Sache durchzieht die gesamte Produktpalette.
Martin Luerssen schrieb: > Relevante Code-Teile Hast Du ggf. noch weitere (und möglicherweise unbehandelte) Interrupts aktiviert?
Ob TIM0_OVF_vect oder TIMER0_OVF_vect der richtige ist, kann man mit einem #ifdef leicht rausfinden (und so portablen Code, im AVR Umfeld, schreiben). Die Makros ISR() und SIGNAL() setzen für die definierten Funktionen die Attribute "interrupt" oder "signal", die das AVR-Backend veranlaßt, ALLE benutzten Register zu sichern, nicht zu erwarten, daß in R1 kein einziges Bit gesetzt ist und zuguterletzt mit RETI statt RET zu enden. Das Makro reti() wird nur für "nacked" Interrupt-Funktionen gebraucht, denn dann macht der Compiler weder Rgistersichern/restore noch RET/RETI. Da darf der Prograbmmierer alles selber machen. Per asm(). Und er weiß hoffentlich was er tut. Sinnvoll wenn z.B. nur ein Bit in GPIORn gesetzt werden soll, dann wird die ISR deutlich kompakter. Und Leute mit Takt-Phobie hoffentlich ruhiger :-)
A. K. schrieb: > Das Problem sich gelegentlich von Produkt zu Produkt ändernder > Handler-Namen für die gleiche Sache durchzieht die gesamte > Produktpalette. Nee, das ist in der 'iotn24a.h' so definiert. Im Datenblatt, sowohl bei 24 als auch beim 24a, ist es wie gewohnt INT0. Dieser Vektor ist auch der einzige, der mit EXT_ versehen wurde. TIM0 und TIMER0 und ... gibt es auch noch. Die stammen allerdings aus dem Datenblatt. mfg.
Ich hätte hier noch eine Geschichte von Paul Watzlawick, vielleicht kennt sie der eine oder andere ja noch nicht: Ein Betrunkener kriecht um Mitternacht auf allen Vieren unter einer Straßenlaterne herum. Kommt ein Polizist vorbei: "Sie, was machen Sie denn da?" "Ich suche meinen Hausschlüssel." Jetzt suchen beide. Nach einer Viertelstunde fragt der Polizist: "Sagen Sie mal, sind Sie sicher, dass Sie den Schlüssel hier verloren haben?" Kommt die Antwort: "Nein, nicht hier, sondern dort drüben. Aber dort ist es viel zu dunkel zum Suchen."
A. K. schrieb: > Und das reti()? Das zerdrischt Dir den Epilog des Handlers. Maximal wäre ein return; erlaubt.
Peter Dannegger schrieb: > A. K. schrieb: >> Und das reti()? > > Das zerdrischt Dir den Epilog des Handlers. > Maximal wäre ein return; erlaubt. Ich dachte, darum hätte er sich schon vor drei Stunden gekümmert: Martin Luerssen schrieb: > Danke erstmal, Reti rausschmeissen versuche ich mal.
Hallo allerseits, vielen Dank erstmal. Eben nach Hause gekommen und geändert, das reti() war es tatsächlich, Rest war Ok und funktioniert wie gedacht. Keine Ahnung mehr, wie ich da drauf gekommen bin, evtl. vom Assembler her in meinem Hirn hängengeblieben das reti. Thread kann dann zu, nochmal danke an alle.
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.