Forum: Mikrocontroller und Digitale Elektronik Problem mit AtMega8 Uart Receive


von Rainer Voigt (Gast)


Angehängte Dateien:

Lesenswert?

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...)

von Rainer Voigt (Gast)


Lesenswert?

achja: den Code hab ich hier irgendwo im Forum gefunden. Ich wollte nur
was einfaches zum Testen haben. Mein eigentliches Programm ist etwas
komplexer ;)

von Heinz (Gast)


Lesenswert?

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.

von Rainer Voigt (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

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.

von dave (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

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

von dave (Gast)


Lesenswert?

;) Ich kenn mit mit C nicht aus hehe.. mir reichts, wenn Assembler
funktioniert.

Dave

von Christian Zietz (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

:]

Naja, ich hab ja jetzt auch ein gleichwertiges Workaround...

Rainer

von Christian Zietz (Gast)


Lesenswert?

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.

von Rainer Voigt (Gast)


Lesenswert?

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.

von Rainer Voigt (Gast)


Lesenswert?

Haha... :) jetzt haben wir aber schoen gleichzeitig geschrieben :))

von Rainer Voigt (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Rainer Voigt (Gast)


Lesenswert?

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.

von Christian Zietz (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

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.

von Christian Zietz (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

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

von Christian Zietz (Gast)


Lesenswert?

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

von Rainer Voigt (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.