Hallo! ich hab irgendwie ein dickes Problem mit dem AtMega8, und ich forsche schon ne kleine Ewigkeit nach der Loesung... vielleicht koennt Ihr mir ja helfen: Ich moechte einfach nur was uebers Uart empfangen koennen... Ich hab das Teil an meine RS232 am PC angeschlossen, usw... die Signale kommen auch richtig an Pin2 (RXD) an, das hab ich schon am Oszi gesehn, der Interrupt ist wohl auch enabled, aber es passiert nichts! Ich hab am PortC, wo sich eigentlich was tun sollte, LEDs mit Vorwiderstaenden dran, und die bleiben brav dunkel :( Kann mir jemand sagen was das los ist? Oder hab ich den Atmel vielleicht irgendwie per Elektrostatik zerschossen? (So langsam faellt mir naemlich keine Erklaerung mehr ein...)
achja: den Code hab ich hier irgendwo im Forum gefunden. Ich wollte nur was einfaches zum Testen haben. Mein eigentliches Programm ist etwas komplexer ;)
Ich hab mit dem Mega8 in verbindung mit RS232 mal viel Spass gehabt, bis ich herausgefunden habe, das der interne Quarz wohl doch SEHR Temperaturabhängig arbeitet! Da in deinem Quellcode aber was von 16 Mhz steht, gehe ich davon aus das du den extern taktest ? Vielleicht solltest du noch ein paar Angaben zur Hardware machen.
Also: Ich hab einen AtMega8(-16PI), getaktet mit 16Mhz ueber einen Quarz-Oszillator (so ein silberner Vierbeiner mit Vcc, GND und einem Ausgang mit Rechteck-Signal) an XTAL1; dann ist da noch der Max202, der seinen Dienst (laut Oszi) scheinbar gut verrichtet; naja 5V aus einem Linear-Regler, ein paar 100nF Entstoer-Kondensatoren, weil da eigentlich noch einige andere Bauteile mit drauf sind... (ausserdem noch eine schicke kleine Sinus-Schwingung auf der Versorgung, aber nur plus-minus 0.05V, das sollte der Atmel verkraften). Hardwareseitig sollte das eigentlich in Ordnung sein, denk ich. Viele Gruesse, Rainer
So, jetzt hab ich so was aehnliches wie eine Loesung: Eigentlich programmiere ich ja kein assembler, das war nur, um einen low-level Test durchzufuehren. Das hat ja, wie beschrieben auch keinen Erfolg beschert. Ich benutze sonst immer AVR-GCC, und hier ist etwas seeeeehr komisch: benutzt man SIGNAL, um den Uart-Receive Handler zu schreiben, funktioniert alles! Verwendet man hingegen INTERRUPT, so wird der Code nie ausgefuehrt! Die ist eine sehr komische Angelegenheit, kann mir das jemand erklaeren? Viele Gruesse, Rainer.
Wie man hier bei uns immer an der Schule sagt: Abschreiben bringt nichts... und Abschreiben sollte gelernt sein. "achja: den Code hab ich hier irgendwo im Forum gefunden. Ich wollte nur was einfaches zum Testen haben. Mein eigentliches Programm ist etwas komplexer ;)" Am besten schauste jetzt nochmal in den Thread, da wirste wohl mitbekommen, dass der Herr K E I N E N Mega8 verwendet. Der Mega8 hat einen Timer2 mit IRQ... nur wo sind die in deinem Code? Folge daraus: Du versucht den Timer0 Overflow IRQ auszuführen... Pech ghabt. ==> Füge 2 RETIs ein (über T1) und beachte, dass du 2 Stobbits eingestellt hast. Dave
Dass abschreiben nix bringt ist mir eigentlich auch klar :) Ich hab nur nach ner schnellen Problemloesung gesucht... (War wohl der falsche Weg, dass ist wahr!) Dennosch erklaert das nicht, warum der C-Compiler beim Keyword 'INTERRUPT' Mist macht, und das ganze mit 'SIGNAL' und einem folgenden 'sei ();' ganz einwandfrei funktioniert... (?) Gruss, Rainer
;) Ich kenn mit mit C nicht aus hehe.. mir reichts, wenn Assembler funktioniert. Dave
Ich denke mal, es passiert folgendes: Also: Wenn Daten im Puffer sind, wird das RXC-Flag gesetzt. Es bleibt gesetzt, bis die Daten gelesen wurden (s. Datenblatt). Wenn der entsprechenden Interrupt aktiv ist, löst das Flag ihn aus. Definierst Du den Handler beim GCC als INTERRUPT, so sind in der Interrupt-Routine Interrupts aktiv, können diese also unterbrechen (bei SIGNAL ist das nicht der Fall, genauso in Deinem ASM-Quelltext). Da das RXC-Flag ja gesetzt ist, wird also sogleich ein neuer Interrupt ausgelöst, der wiederum einen Interrupt auslöst. Du hängst also fest. Das erklärt aber nicht, warum der ASM-Source nicht läuft. Christian
:] Naja, ich hab ja jetzt auch ein gleichwertiges Workaround... Rainer
Rainer, ich hatte Dein letztes Posting noch nicht gelesen, als ich meins verfasst habe. Dass es trotz sei() mit SIGNAL geht, ist schon seltsam. Schau Dir mal die Listfiles (.lst) an, um Unterschiede festzustellen.
Hmmm... Also Du meinst, ich muesste das Flag gleich clearen? Aber da ja die als erstes gerufene Interrupt-Routine nicht unterbrochen werden kann, muesste ja, wenn ich darin das empfangene Zeichen zurueck schicke, dieses zumindest wieder ankommen, oder? Die evtl. wiederholt ausgeloesten Interrupts, muessten erst danach abgearbeitet werden, oder? Rainer.
Haha... :) jetzt haben wir aber schoen gleichzeitig geschrieben :))
Ich hab mal die beiden *.lst Files angehaengt, hatte aber grade wenig Motivation, das auseinander zu nehmen... Was ich aber festgestellt habe ist Folgendes: wenn man SIGNAL verwendet, 'sei ();' zuerst ruft und danach den Inhalt von UDR holt, dann wird der Interrupt-Code doppelt ausgefuehrt, weil dann einen Takt lang, das RXC Flag noch gesetzt ist; wenn man erst UDR sichert, wird das Flag sofort gecleart; dann kommt er nur einmal bei der Routine vorbei. (Ist also doch irgendwie so wie Du sagtest). Was dann bei 'INTERRUPT' passiert, weiss ich grade nicht. Da wird ja 'sei' sofort gerufen, und das Flag bliebe ja bis zum ersten Auslesen von UDR noch gesetzt... Also der richtige Weg ist wohl so: SIGNAL verwenden, Daten aus UDR retten und dann, falls noetig, 'sei ();' aufrufen. Viele Gruesse, Rainer.
Achso, eine ganz andre Frage hab ich noch: kann ich nicht, wenn an XTAL1 ein Rechtecksignal als Clock anliegt, XTAL2 noch als Output benutzen? Irgendwie geht das grade auch nicht... Ist da was mit den Fuses falsch? Rainer.
Laut Datenblatt wird nach einem SEI noch eine weitere Instruktion verarbeitet, bevor evtl. anstehende Interrupts aufgerufen werden. Steht das SEI also direkt vor dem Auslesen von UDR, passiert vermutlich Folgendes: 1.) SEI: Das globale Interrupt-Flag wird gesetzt. Die nächste Instruktion wird trotzdem erst ausgeführt. 2.) IN Rxx, UDR: UDR wird gelesen. Der AVR braucht dann aber noch etwas Zeit, bis daraufhin das RXC-Flg gelöscht wird. 3.) Da das RXC-Flag noch nicht gelöscht ist, wird noch ein Interrupt ausgelöst. 4.) Im Hintergrund wird das RXC-Flag gelöscht. 5.) Die zweite Interrupt-Routine wird ausgeführt. Da RXC mittlerweile gelöscht ist, löst SEI keinen dritten Interrupt aus. 6.) RETI: Zurück in die erste Interrupt-Routine 7.) Die erste Routine wird bis zum RETI ausgeführt. Ist der Handler als INTERRUPT definiert, so steht das SEI ganz am Anfang. Folglich wird das RXC-Flag nie gelöscht, denn es werden immer weitere Interrupt-Routinen aufgerufen, die gar nicht bis zum Auslesen von UDR kommen. Der uC hängt fest. Warum brauchst Du in einer Interrupt-Routine eigentlich noch weitere Interrupts? Christian
Naja, mein Atmel hat viele Aufgaben, da gibts noch Timer-Interrupts, weil zwei Stepper gesteuert werden, ein i2c-Interface sollst auch noch geben... (Da bin ich mir schon nicht mehr sicher, ob er das auch alles packt, aber eigentlich hat er immer nur wenig zu tun, aber eben viele verschiedene Sachen) Ich baue naemlich ein Roboter-Control-Modul. Man soll ueber RS232 die Stepper ansteuern koennen, die Schritte ruecklesen koennen, die Rotation des Roboters von einem elektr. Kompass am i2c auslesen koennen, dann kommt noch ein Servo mit Ultraschall-Abstandssensor dran, den soll man eben auch darueber auslesen oder evtl. sogar drehen koennen... Am Ende kommt ein PocketPC auf den Robbi drauf, der dann die Orientierung uebernimmt. Das was ich jetzt hab, ist nur erstmal ein richtig schickes, geprintetes gruenes Board mit zwei Stepperdriver-ICs, dem MAX202 und dem Atmel drauf :) Rainer.
Zu den Interrupts: Mein Vorgehen wäre anders: Die Interrupt-Routinen so kurz wie möglich halten, dafür auf verschachtelte Interrupts (d.h. Interrupt-Handler mit SEI) verzichten. So ein Timer-Interrupt geht ja auch nicht verloren. Es wird das Flag gesetzt und sobald Du aus der aktuellen Interrupt-Routine draußen bist, wird dann diejenige des Timers ausgeführt. Zu XTAL2: Im Datenblatt ist dieser Pin bei Verwendung eines externen Oszillators als NC (nicht anschließen) bezeichnet. Nur bei Verwendung des internen Oszillators steht explizit drin, dass man XTAL2 (und auch 1) als reguläre I/Os nutzen kann. Christian
Also meine Interrupt-Routinen sind eigentlich fast alles Dreizeiler, oder so in dieser Region... . Also wenn ich 'sei' nicht rufe, kommen die zwischenzeitlich aufgetretenen Interrupts einfach danach, anstatt zwischendurch? Na denn... mehr wollte ich eigentlich gar nicht :) Ich hab dann irgendwas im AVR-GCC Tutorial ein bisschen falsch interpretiert. Ich dachte die gehen dann verloren, und das rufen von 'sei' bewirkt, dass sie danach aufgefuehrt wuerden... Hmm... Das mit XTAL2 ist ja doof... rein theoretisch waere das ja schon moeglich... nagut, dann eben nicht. Aber danke fuer die Hilfe! Viele Gruesse, Rainer
Die aufgelaufenen Interrupts kommen dann halt nach dem Ende des aktuellen Interrupt-Handlers. Das Datenblatt sagt: Similarly, if one or more interrupt conditions occur while the global interrupt enable bit is cleared [Anm.: genau das ist in einem Interrupt-Handler standardmäßig der Fall], the corresponding Interrupt Flag(s) will be set and remembered until the global interrupt enable bit is set [Anm.: das passiert nach dem RETI], and will then be executed by order of priority. Evtl. auch wichtig: When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served. Christian
Wow! Man muss, wie so oft, nur genau lesen.(Nur bei den knapp 300 Seiten faellt das stellenweise schwer :)). Dass er erst noch eine Instruction im Hauptprogramm ausfuehrt, ist auch interessant... Danke vielmals! Rainer.
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.