www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART TX mit Interrupt?


Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe nun meine ersten Zeichen erfolgreich zum PC übertragen.
Das ganze mit einer einfachen Warte Abfrage auf das UCSRA Register und
das UDRE Bit.

Da ich aber lange Texte (bis zu 82 Zeichen...) übertragen möchte und
das leider nur in 4800 Baud würde das ja wohl bedeuten wenn man es mit
der Schleifen MEthode macht das ich mir mein Hauptprogramm abbremse.
;-(

Nun habe ich gelesen das es auch für die TX Seite Interrupt Vektoren
gibt nur steige ich noch nicht ganz dahinter wie es funktionieren
soll.

Ich habe meinen String den ich sende möchte im SRAM abgelegt.
Wie ist denn nun der Ablauf wenn man es mit Hilfe der Interrupts senden
möchte?

RX macht mir keine Probleme das habe ich begriffen... :-)

Für jeden Tip danbar... AVRli...

Autor: Marcus M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo AVRLi,

wenn ich das jetzt richtig im Kopf habe, dann mußt Du nur den
Sendebuffer füllen und auf den dazu passenden Interrupt warten.
Der Code sollte irgendwie so aussehen.
Allerdings weiß ich jetzt nicht welchen AVR Du benutzt, somit ist der
Code jetzt etwas allgemeiner gefaßt.

Gruß Marcus

char tx_buffer[82];
char tx_send = 0;
char tx_end = 0;

void init_UART(void)  {

  //Parameter entsprechend Datenblatt einstellen!

}

void init_transmission(void) {

  tx_send = 0; //Die Position, die gesendet werden soll, zum
//start erstmal auf Null stellen
  tx_end = strlen(tx_buffer); // Länge des Buffers ermitteln
  sei();       //interrupts aktivieren

}

SIGNAL (SIG_UART_TRANS) {

   if (tx_send < tx_end) //tx_send ist innerhalb des Datenstrings
    UCSRA = tx_buffer[tx_send++];
   else
      cli();  //andernfalls Interrupt deaktivieren, denn es gibt nix
mehr für die serielle Schnittstelle zu senden
}

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Marcus,

danke für den Tip!
Leider habe ich es mal wieder verpennt zu schreiben was meine
"Spielsachen" sind.

ATmega8 und in Assembler...

Mir ist nicht ganz klar wozu die beiden Interrupts da sind.
Und wie man die eigendlich Übertragung dann anschubst...

Gruß AVRli...

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi AVRli

der "transmittierende" Teil des USART am Mega 8 hat zwei mögliche
Interrupts. Der eine wird ausgelöst, wenn ein neues Zeichen ins
Datenregister gepackt werden kann (UDRE). Der zweite, wenn die
Übertragung komplett ist (TXC).

In deinem Fall kannst du in der ISR zum UDRE beispielsweise immer ein
neues Zeichen aus deinem String im Datenregister ablegen. Dieses wird
dann automagisch übertragen.


Viele Grüße

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

danke... ist es dann so das man wenn ich im SRAM meine Daten abgelegt
habe dann im UCSRB das BIT UDRIE setze um die Übertragung zu starten
und wenn alle Zeichen übertragen sind das BIT wieder lösche?

Im Moment springt es ja nun immer wierde in den Vector rein...
Ist das korekt?

Gruß AVRli...

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi.

du musst erstmal TXEN und RXEN setzen, aber das musstest du für die
Interruptlose Kommunikation ja auch. Dann setzt du noch UDRIE, was
bewirkt, dass immer wenn ein Byte fort ist (d. h. aus dem UDR Register
raus) dieser Interrupt ausgelöst wird. Wenn alle Zeichen übertragen
wurden, wird das UDRIE wieder gelöscht, sonst wird die ISR immer wieder
aufgerufen...


Grüße

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi AVRli,

Du solltest Dir erstmal überlegen, woran Du das Ende Deiner
Zeichenfolge erkennen willst. Es gibt 2 Möglichkeiten:

1. Counter
2. Null am Ende des Strings

In Deiner Sende-IR-Routine sendest Du also einfach solange Zeichen, bis
die Ende-Bedingung erfüllt ist. Dann schaltest Du den TXD-IR ab mit:
    UCSRB &= ~_BV(UDRIE);  // disable the transmitter-IR

Wenn Du einen String senden willst, schreibst Du den Ptr auf den String
in die IR-Ptr-Variable und gibst den TXD-IR frei:
    UCSRB |= _BV(UDRIE);  // enable the transmitter-IR

Bevor das alles so einfach funktioniert, musst Du den UART
initialisieren. Und da geht das Henne-Ei-Problem los: Das Flag UDRE ist
nach dem Reset Null und kann auch nicht manuell gesetzt werden. Die
einzige Möglichkeit, die ich kenne: ein erstes Byte manuell (ohne IR)
in das TXD-Register schreiben.

@Marcus:
Mit cli und sei beeinflusst Du alle IRs gleichzeitig. Wenn Du also auch
andere IR benutzen willst, solltest Du unbedingt das spezifische
IR-Enable-Register der entsprechenden Hardware (in diesem Fall UDRIE)
benutzen.

Stefan

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Stefan,

"Das Flag UDRE ist nach dem Reset Null und kann auch nicht manuell
gesetzt werden. Die einzige Möglichkeit, die ich kenne: ein erstes Byte
manuell (ohne IR) in das TXD-Register schreiben."

Da das so nicht im Datenblatt steht, habe ich das grad' auch noch mal
ausprobiert ;->
Und es ist wirklich so, dass der UDRE - data register empty interrupt -
sofort ausgelöst wird, sobald UDRIE und natürlich das globale
Interruptflag gesetzt sind. Man muss also das erste Byte nicht selbst
schreiben...

Viele Grüße

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Thomas,

danke für den Tip.
Ich verwende bei meinem eigenen Code nicht das UDRIE-Flag, sondern das
TXCIE-Flag. Bei dem läuft es so wie ich beschrieben habe, und ich habe
das dem UDRIE-Flag ohne zu testen auch unterstellt.

Normalerweise ist die Verwendung des UDRIE besser. Weil ich bei meiner
Appl. aber XON/XOFF-Handshake benutze, verwende ich das TXCIE. Dadurch
ist der Ausgangspuffer des UART beim Senden immer leer (doppelte
Pufferung). Der Recieve-IR kann also XOFF-Bytes direkt in den
Transmitter schreiben, ohne eine laufende Ausgabe zu stören.

Stefan

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Stefan,

die Verwendung des UDRIE hat halt den einen Vorteil, dass man schon ein
neues Byte zum Transfer abgeben kann, während das andere noch durch die
serielle Übertragung geschoben wird. Aber das war's doch auch schon?!
:)

Viele Grüße

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Thomas,

bei manchen Sachen sind die beiden unterschiedlichen Flags schon ganz
hilfreich, z.B. bei RS485: der letzte macht das Licht aus ;-)

Viele Grüße, Stefan

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

also ich habe es mit dem UDRE Interrupt gelöst.
Alles super so! ;-)

Also meine Daten liegen im SRAM und enden mit der 0.
Wenn die Daten im SRAM gespeichert sind wird das
UDRIE Bit gesetzt.

In dem Interrupt wird nun immer das nächste Zeichen geleaden und
ausgesendet. Ist er bei der 0 angekommen dann wird das
UDRIE Bit wieder gelöscht.

Funktioniert wirklich gut.

Ich danke für die Infos.
Es macht es schon leichter wenn man sich austauscht.

Gruß AVRli...

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

nun bin ich dabei die Anwndersoft auf dem PC zu schreiben und da
ist mir aufgefallen das ich was in der Software vom ATMEL (ATmega8,
Assembler) was übersehen haben muss.

Ich schicke meine Abfragen zyklisch zum AVR... kurze Antworten von 3
Zeichen kommen richtig an zum PC.
Längere die dazwischen sind werden nach halber aussendung von der
Antwort der nächsten Anfrage überschrieben.

Mit einer Pause zwischen den Befehlen kann ich nicht leben...
Also Sende 1 Sek warten sende ...

Wie würdet ihr sowas lösen?

Die Möglichkeiten die mir einfallen sind wohl nicht ideal.
1. Doch nicht im Interrupt aussenden und das ganze AVR Programm
abbremsen
2. keine Zeichen annehemen solange nicht die komplette Antwort raus
ist. (hier gehen dann Zeichen verloren oder)

Gruß AVRli...

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi AVRli,

kannst du mir das nochmal anders erklären :->
irgendwie stehe ich aufm Schlauch und kapier nicht so recht, was du
meinst.

Wenn deine Abfragen nicht schneller kommen, als die Übertragung des
Strings anhand seiner Länge und Baudrate dauert, leuchtet mir nicht
ein, warum nur ein Teil übertragen werden sollte... Mir wird nicht
klar, warum dies ein Problem der Übertragung mittels Interrupt sein
soll.

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi AVRli,

das macht es etwas komplizierter. Du brauchst einen Ausgangs-Puffer,
analog zum Eingangspuffer des RXD-Teils. Zum Verschicken reicht es dann
nicht mehr, einfach den Pointer des Strings zu kopieren, sondern Du
musst alle Zeichen aus dem String in den Puffer kopieren. Nicht
vergessen: Beim Kopieren in den Puffer und auch beim Auslesen die obere
Puffergrenze und den Puffer-Füllstand kontrollieren.

Du brauchst also:
* den Puffer selbst, Größe je nach Anforderung
* einen Puffer-Index für die Füll-Routine
* einen Puffer-Index für den TXD-IR

Viele Grüße, Stefan

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

@Thomas
Ja das Problem ist folgendes...
Ein Befehl PC>AVR sieht bei mir so aus das er mit einem CR endet.
Also so...

SET1

wenn alle Zeichen im AVR sind dann schreibt der in den SRAM
die Zeichen rein die er aussenden soll.
Soweit ok...

Sendet man nun aber

SET1
SET2
SET3

hintereinander zum AVR dann bekommt man nur die Antwort vom letztem
Befehl richtig zum PC gesendet.
Grund dafür dürfte sein das die Antwort auf den letzten Befehl noch
nicht fertig ist und dann die neue einfach begonnen wird. :-(

Ok?

@Stefan

Danke für den Tip... werde erstmal darüber schlafen.... :-D

Gruß AVRli...

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du brauchst einfach einen eingangspuffer von was weiss ich wievielen
befehlen den dein programm dann der reihe nach abarbeitet

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi AVRli

also gut, dann wirds wohl ein Eingangspuffer im AVR tun oder noch
einfacher: dafür sorgen, dass der PC keine Kommandos schickt, solange
die Abarbeitung eines anderen Befehls noch läuft.

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

> also gut, dann wirds wohl ein Eingangspuffer im AVR tun
Ja habe ich hinbekommen so eine Art "Ringbuffer"...
Die Antwort vom AVR wird nun temporär im SRAM abgelegt diese
darf max. 82 Zeichen haben.
Anschließend werden die neuen Zeichen in den Ringbuffer (255 Zeichen)
geladen.
Nun wird der TX int. aktiviert.
Und er sendet fleißig los.
Kommt nun einen neue Anfrage dann wird diese im Ringbuffer angehangen.
Das ganze funktioniert so lange einwandfrei bis man ein Dauerfeuer an
Kommandos gibt.
Der Ringbuffer ist hier nun 255 Byte groß.
Da knallt es wenn man also 4 mal eine Antwort mit 80 Zeichen bekommen
will... aber das ist total nebensächlich !!!! ;-)
Das kommt in der Praxis nie vor !!!
In der Praxis werden alle 500ms eine Antwort von ca. 50 Zeichen
erwartet.

> oder noch einfacher: dafür sorgen, dass der PC keine Kommandos
> schickt, solange die Abarbeitung eines anderen Befehls noch läuft.

Ja die Lösung hatte ich auch in Betracht gezogen da man ja einen neuen
Befehl hätte blöcken können solange nicht die ganze Antwort da ist...
;-I
Aber geschickt ist das nicht... hahahahaha
Kostet unnötig Resourcen...

Ich freue mich riesig das ich es, dank eurer Hilfe, auf die Reihe
bekommen habe.

Gruß AVRli...

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

>> oder noch einfacher: dafür sorgen, dass der PC keine Kommandos
>> schickt, solange die Abarbeitung eines anderen Befehls noch läuft.

>Aber geschickt ist das nicht... hahahahaha
>Kostet unnötig Resourcen...

Wie jetzt, was ist daran ungeschickt :-P
Und was kostet das für Resourcen? Du sollst da ja an dem Steuerrechner
kein "Busy-Wait" draus machen :)

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Thomas,

ja na ungeschickt in der Form das man auf der PC Seite damit
beschäftigt ist ständig zu schauen ob die Schaltung fertig ist mit der
Abarbeitung.

Nun kann ich ganz sorglos meine Befehle an einem Stück absenden und tu
dies nun alle 500ms der Atmel hingt zwar etwas hinter her aber das
stört nicht weiter.

Die Befehle hat er locker nach 500ms beantwortet. ;-)
Ohne nur eine Antwort zu zerstückeln.

Finde es eleganter und das wird es leichter machen
wenn Software anderer Entwickler mit meiner Schaltung "spielen"
wollen.

Gruß AVRli...

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

der PC hat ja auch sowas wie Interrupts :) muss man also nicht
ununterbrochen pollen, um rauszufinden, was der µC tut.
Aber es ist schon richtig, ein Puffer im µC schadet nicht. Nur muss man
sich der Grenzen trotzdem bewusst sein... irgendwann ist der nämlich
auch voll.

Grüße

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
übrigens:
Baudrate hochsetzen verringert solche Probleme oft extrem. Bei 115kbaud
brauchen 80 Zeichen keine 8ms mehr.

Happy praogramming, Stefan

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.