Forum: Mikrocontroller und Digitale Elektronik UART und ADC-Interrupt


von Olaf Fran (Gast)


Lesenswert?

Hi!

Habe folgendes Problem mit einem ATmega16:

In meinem Programm gibts einen Main-Loop, der den UART pollt. Dazu
läuft im Hintergund der ADC, der einen Interrupt auslöst, wenn er mit
der Conversion fertig ist. Die Interrupt-Routine setzt dann einen neuen
Channel und startet eine neue Conversion.

Das Problem ist, daß wenn ich diesen Interrupt aktiviert habe, ca.
jedes 6. byte vom UART nicht korrekt ausgelesen wird. Kommt dann nur
irgendwelcher Blödsinn raus, den auf der anderen Seite nie jemand
gesendet hat. Ist der Interrupt aus, läuft alles bestens. Fällt dazu
jemandem was ein? Kann doch wohl nicht so timingkritisch sein, die
UART-Geschichte, oder doch?

von Rahul (Gast)


Lesenswert?

Poste den Quellcode!
Olga hat gerade Urlaub!

von Olaf Fran (Gast)


Angehängte Dateien:

Lesenswert?

I'm sorry. Hatte ich meiner Verzweiflung auf eine "Ach ja, das ist ein
typischer Anfängerfehler"-Antwort gehofft. ;-)

Hier ist ein aufs Wesentliche reduzierter Source, mit dem sich der
Fehler nachvollziehen lässt. Kommentiert man die Zeilen zwischen den
"blah" Kommentaren aus, läuft alles bestens.

BTW, der Takt ist bei mir 3.69 MHz, die Baudrate demnach 57600.

von Michael (Gast)


Lesenswert?

Solche Probleme hat man immer, wenn man im Interrupt das Statusregister
nicht rettet und wiederherstellt. Glück hast Du noch, da sich der
Fehler gleich gezeigt hat :-)

von Peter D. (peda)


Lesenswert?

man sollte SREG zwar immer sichern, aber in diesem Fall ist es
ausnamsweise unschuldig, da im main garnicht benutzt.

Und richtiger sollte es wohl

sbr r16, 1<<adsc

heißen.


Das Problem dürfte vielmehr sein, daß ständig gesendet wird, d.h. auch
wenn nichts empfangen wurde.
Dadurch reichen schon kleinste Programmverzögerungen aus, um Bytes
doppelt zu senden, klar daß dann dafür andere Bytes geopfert werden
müssen.


Peter

von Olaf Fran (Gast)


Lesenswert?

Hmmm.

Wie ist das mit dem ständigen senden gemeint? Die Empfangsroutine
wartet doch, bis ein Zeichen da ist. Danach wird erst die Senderoutine
aufgerufen. Klappt ja auch, solange der Interrupt aus ist.

Ich schau mal in die Specs, was es mit dem SREG auf sich hat. Danke für
den Tip. ;-)

von Olaf Fran (Gast)


Lesenswert?

Hi.

Hab gerade mal versucht, in int_adc das sreg zu sichern ('in r20,
sreg' am anfang und 'out sreg, r20' vor dem reti), hat aber leider
auch nicht zum Erfolg geführt. Hat vielleicht noch jemand eine Idee?

von Sven (Gast)


Lesenswert?

hallo Olaf,

ich würde den adc interrupt abschalten, wenn ein Zeichen empfangen
wurde und erst nachdem alle Zeichen über den Uart empfangen worden sind
wieder den ADC interrupt akitivieren....
Hatte mal das selbe Problem und hab's nicht anders lösen können, wobei
ich jetzt nicht unbedingt der Profi Programmierer bin....

vielleicht klappt's ja

Gruß

Sven

von Peter D. (peda)


Lesenswert?

"Wie ist das mit dem ständigen senden gemeint?"

War ein Irrtum meinerseits.


Aber ganz ohne Empfangs-/Sendepuffer dürfte es normal sein, daß Zeichen
verloren gehen. Die Senderoutine frißt Dir dann die ganze Zeit auf.
Dein Quarz muß nur leicht langsamer sein als der der Gegenstelle und Du
empfängst schneller als Du senden kannst.

Jede kleine Mehrbelastung z.B. durch einen Timerinterrupt dürfte die
gleiche Wirkung haben.


Peter

von Olaf Fran (Gast)


Lesenswert?

Theoretisch schon. Bei dem Source, den ich reingestellt hab, reicht es
aber auch, in einem Terminalprogramm ab und an mal eine Taste zu
drücken, um den Fehler auszulösen. Müssen keine irrsinnigen Datenströme
sein.

Die fertige Anwendung würde auch so aussehen, daß erst ein Befehl
empfangen wird, der Controller antwortet und dann kommen erst die
nächsten Daten. Wäre also in Ordnung, wenn er da eine Weile in der
Senderoutine verbringt, weil währenddessen nichts kommen kann.

von Olaf Fran (Gast)


Lesenswert?

Sven,

Danke für den Tip, aber dann könnte ich den ADC auch gleich pollen.
Wäre dann in meiner Anwendung die sinnvollere Alternative. Aber da
Interrupts irgendwie lässiger sind, möcht ich die lieber ans laufen
bekommen. :-)

von Rahul (Gast)


Lesenswert?

wie wäre es denn beides über Interrupts auszuführen?
Dann würde der Controller 95% der Zeit nix tun, aber ziemlich sicher
auf alles reagieren, was da so anliegt.
Die Idee von Peter würde ich immer realisieren, sprich einen
Empfangspuffer per Interrupt füllen und dann in der Hauptschleife
auslesen.

von Peter D. (peda)


Lesenswert?

Wenns schon bei einem Byte auftritt, dann muß da was faul sein.

Stimmt denn der Interruptvektor ?
Warum nimmst Du nicht ".org Int-Name" zum Zuweisen des richtigen
Vektors ?

Auch solltest Du ruhig kommentieren und Konstanten verstehbar (Namen
benutzen) hinschreiben.


Peter

von Olaf Fran (Gast)


Lesenswert?

Hi.

Ich bin ab gleich für ein paar Tage ausser Landes, mal über andere
Sachen nachdenken. Vielleicht kommt mir da ja zufällig die rettende
Idee (oder jemand anders hat noch zufällig eine?). Ich probier später
noch mal, das Ding mit Buffer und Interrupt-gesteuertem Empfang ans
Laufen zu bekommen.

Der Vektor für den ADC-Int in meinem Code müsste stimmen.

Übrigens bitte nicht dieses aus dem Kontext gerissene Code-Snippet als
repräsentativ für meinen Stil betrachten. Das war nur ein Spielzeug. Im
echten Code sind schon Kommentare und Konstanten drin. Wenn ich auch
nicht einer von diesen Wahnsinnigen bin, die jedem Register ein Alias
ala Variablenname verpassen. ;-)

Danke für die Hilfe bisher.

MfG,
Olaf

von Uwe (Gast)


Lesenswert?

Hi!
Ich habe momentan blos das pdf vom Mega163, aber da hat ein Int-Vekt.
16 Bit! Ist das beim M16 nicht auch so?

MFG Uwe

von Thorsten Witt (Gast)


Lesenswert?

Hallo,
nimm den Tip von Peter an und schreib vor jedem IRQ-Vektor die Adresse
mittels ".org Int-Name". Ich verwende auch den Mega16 und hatte das
gleiche Problem. Nachdem ich vor jedem verwendetem IRQ-Vektor das
entsprechende ".org" geschrieben habe, funktioniert es.

Viel Erfolg

Thorsten

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.