Forum: Mikrocontroller und Digitale Elektronik AVR Sendepuffer prüfen


von Mathias G. (rodiboki)


Lesenswert?

Hallo,

Ich wollte gerne den Sendepuffer abfragen, ob der schon leer ist (d.h. 
ob alle Zeichen raus sind)
Benutze AVR Studio 7 und ATMEGA 8

Gruß Mathias

p.s.: Sorry nicht gesehen, das ich in Bearbeiten war und damit mein 
ersten Post ausversehen verwuselt....

: Bearbeitet durch User
von Mike R. (thesealion)


Lesenswert?

Direkt aus dem Datenblatt
1
void USART_Transmit( unsigned char data )
2
{
3
    /* Wait for empty transmit buffer */
4
    while ( !( UCSRA & (1<<UDRE)) );
5
    /* Put data into buffer, sends the data */
6
    UDR = data;
7
}

Bits aus einem Register abfragen/testen ist elementarstes C.

von Adam P. (adamap)


Lesenswert?

Mathias G. schrieb:
> ob die Zeichen raus sind

Ist es nicht so, dass das UDRE nur sagt, dass das Byte aus dem UDR ins 
Shift Register übertragen wurde.
Dann folgt das Heraustakten und erst dann meldet TXC den Transmit 
Complete?

von M. K. (sylaina)


Lesenswert?

Adam P. schrieb:
> Dann folgt das Heraustakten und erst dann meldet TXC den Transmit
> Complete?

Bei der Fragestellung aus dem Eingangspost hätte ich jetzt auch geprüft 
ob Transmit Complete vorliegt und würde nicht über das UDRE gehen aber 
wer kann schon sagen, was der TE überhaupt machen will. Möglicherweise 
ist auch das Prüfung von UDRE das, was der TE sucht ;)

von Mathias G. (rodiboki)


Lesenswert?

Hallo,

an das Abfragen des Bits direkt habe ich schon gedacht wie:
Mike R. schrieb:
> while ( !( UCSRA & (1<<UDRE)) );

Aber da ich Zeichen mit uart_putc einzeln Sende, funktioniert das nicht 
so mit der Abfrage. Werde das mal als kompletten String mit uart_puts 
senden.

Gruß Mathias

von Adam P. (adamap)


Lesenswert?

Mathias G. schrieb:
> Aber da ich Zeichen mit uart_putc einzeln Sende, funktioniert das nicht
> so mit der Abfrage.

Warum nicht?

Mathias G. schrieb:
> Werde das mal als kompletten String mit uart_puts
> senden.

uart_puts() ist doch auch nur eine Übergelagerte Funktion die uart_putc 
verwendet. (In den meisten Implementierungen zumindest um doppelten Code 
zu vermeiden).

Code von oben erweitert:
1
void USART_Transmit( unsigned char data )
2
{
3
    /* Wait for empty transmit buffer */
4
    while ( !( UCSRA & (1<<UDRE)) );
5
    /* Put data into buffer, sends the data */
6
    UDR = data;
7
}
8
9
void USART_Send_Blocked(const unsigned char *str)
10
{
11
  while (*str)
12
  {
13
    USART_Transmit(*str++);
14
  }
15
}

: Bearbeitet durch User
von Mathias G. (rodiboki)


Lesenswert?

Adam P. schrieb:
> Warum nicht?
>
> uart_puts() ist doch auch nur eine Übergelagerte Funktion die uart_putc
> verwendet. (In den meisten Implementierungen zumindest um doppelten Code
> zu vermeiden).

Er führt meinen Code weiter aus, obwohl die Zeichen noch nicht 
vollständig gesendet sind.
Das Auswerten des TXC müsste in diesem Fall besser funktionieren.

Hintergrund:
Ich muss vor dem Senden über einen Pin ein Signal setzen, was nach dem 
vollständigen senden wieder zurückgesetzt wird. Dieses Signal geht zu 
einer Umschaltlogik, das von einem anderen uart Sender zu meinem ATMega 
umschaltet.

: Bearbeitet durch User
von Adam P. (adamap)


Lesenswert?

Mathias G. schrieb:
> Er führt meinen Code weiter aus, obwohl die Zeichen noch nicht
> vollständig gesendet sind.

Würde für TXE als Lösung sprechen.

Oder bastel dir doch ein FIFO, schreib deine Daten da rein und wenn du 
dann dein Sende-Trigger aktivierst, dann setzt du dein PIN, aktivierst 
die Interrupts, lässt die ganze Arbeit vom Interrupt erledigen und wenn 
TXE sich meldet und dein FIFO auch "empty" ist, dann bist du fertig.

So als Spontane Idee :-)


Mathias G. schrieb:
> Er führt meinen Code weiter aus

Das wirkt wohl nur so, denn die while() in der Transmit Funktion sagt 
was anderes.

Oder meinst du eher, dass das UDRE Flag sich meldet aber noch Bits vom 
letzten Byte getaktet werden?

von Pandur S. (jetztnicht)


Lesenswert?

Blockierend zu arbeiten ist doch viel schwieriger wie mit Interrupt. 
Zumal der PC, ein PC, sowieso ein schlechtes Verhalten hat. Mit einem PC 
arbeitet man am effizientesten mit moeglichst grossen Bloecken falls man 
etwas wie Performance haben will. USB-2-Serial hat ein unpassendes 
Timing verhalten. Da sollte man nicht zuviel erwarten.

Und genau diese Performance ist auf Controller Seite weg wenn man 
blockierend arbeitet, wie auf ein Bit zu warten.

Aber wir wissen ja nich was der poster effektiv moechte

von Theor (Gast)


Lesenswert?

Hm. Vielleicht zeigst Du mal Deinen eigenen Code.

An sollte die Übertragung mit der der while-Schleife vor dem erneuten 
setzen von UDR so gehen. Was funktioniert daran nicht?

Allerdings musst Du tatsächlich, auch das TXC-Flag verwenden, falls Du 
erkennen willst, das der Transfer des letzten Bytes abgeschlossen ist.

Als Hinweis noch ein Satz aus dem Datenblatt:

"The TXC Flag can be used to check that the Transmitter has completed 
all transfers, and the RXC Flag can be used to check that there are no 
unread data in the receive buffer. Note that the TXC Flag must be 
cleared before each transmission (before UDR is written) if it is used 
for this purpose."

D.h., spätestens vor der Übertragung des letzten Bytes, musst Du das 
TXC-Flag löschen.

von M. K. (sylaina)


Lesenswert?

Mathias G. schrieb:
> Er führt meinen Code weiter aus, obwohl die Zeichen noch nicht
> vollständig gesendet sind.

Wäre ja auch so richtig. Das while wartet ja nur drauf, dass das UDR 
wieder leer ist, das bedeutet eben nicht, dass bereits alles gesendet 
wurde. Ist das für dich wichtig dann solltest du in der Tat nach TXC 
schauen. ;)

von Mathias G. (rodiboki)


Lesenswert?

M. K. schrieb:
> Wäre ja auch so richtig. Das while wartet ja nur drauf, dass das UDR
> wieder leer ist, das bedeutet eben nicht, dass bereits alles gesendet
> wurde. Ist das für dich wichtig dann solltest du in der Tat nach TXC
> schauen. ;)

Ich habe jetzt den TXC genommen

while (!(UCSRA & 1<<TXC));

… und mit dem Hinweis:
Theor schrieb:
> D.h., spätestens vor der Übertragung des letzten Bytes, musst Du das
> TXC-Flag löschen.

UCSRA = UCSRA & (0xff - 1<<TXC);

… scheint es zu funktionieren.

Danke

Gruß
Mathias

von Theor (Gast)


Lesenswert?

@ Mathias

Na Prima.

Und schön, dass Du eine Rückmeldung gibst.

von Mathias G. (rodiboki)


Lesenswert?

Theor schrieb:
> @ Mathias
>
> Na Prima.
>
> Und schön, dass Du eine Rückmeldung gibst.
Irgendwie habe ich noch Schwierigkeiten, habe im AVR-GCC-Tutorial/Der 
UART den Hinweis gefunden:
Um das Bit zu löschen muss eine 1 an die entsprechende Position 
geschrieben werden!

Ist das so richtig?

Das würde erklären, das beim ersten senden funktioniert. Wenn ich später 
in einer anderen Stelle nochmal was sende, funktioniert es nicht! ?
Gruß
Mathias

von Mathias G. (rodiboki)


Lesenswert?

Mathias G. schrieb:
> Um das Bit zu löschen muss eine 1 an die entsprechende Position
> geschrieben werden!
>
> Ist das so richtig?
Hallo,
habe gerade festgestellt, es ist tatsächlich so. Naja, war ja immer von 
löschen die Rede... :-)

Danke nochmal
Gruß
Mathias

von Theor (Gast)


Lesenswert?

Mathias G. schrieb:
> Theor schrieb:
>> @ Mathias
>>
>> Na Prima.
>>
>> Und schön, dass Du eine Rückmeldung gibst.
> Irgendwie habe ich noch Schwierigkeiten, habe im AVR-GCC-Tutorial/Der
> UART den Hinweis gefunden:
> Um das Bit zu löschen muss eine 1 an die entsprechende Position
> geschrieben werden!
>
> Ist das so richtig?
>
> Das würde erklären, das beim ersten senden funktioniert. Wenn ich später
> in einer anderen Stelle nochmal was sende, funktioniert es nicht! ?
> Gruß
> Mathias

Das ist richtig. Du musst eine 1 schreiben.

Steht im Datenblatt auf Seite 138
Zitat: "... or it can be cleared by writing a one to its bit location."

Das ist aber nicht grundsätzlich bei allen uC oder auch nur bei allen 
Peripherieeinheiten der AVRs so. Am besten immer ins Datenblatt schauen, 
wenn Du mir den Rat erlaubst.

von Mathias G. (rodiboki)


Lesenswert?

Theor schrieb:
> Das ist aber nicht grundsätzlich bei allen uC oder auch nur bei allen
> Peripherieeinheiten der AVRs so. Am besten immer ins Datenblatt schauen,
> wenn Du mir den Rat erlaubst.

Habe ich wohl übersehen... :-(
Gruß
Mathias

von Theor (Gast)


Lesenswert?

Mathias G. schrieb:
> Mathias G. schrieb:
>> Um das Bit zu löschen muss eine 1 an die entsprechende Position
>> geschrieben werden!
>>
>> Ist das so richtig?
> Hallo,
> habe gerade festgestellt, es ist tatsächlich so. Naja, war ja immer von
> löschen die Rede... :-)
>
> Danke nochmal
> Gruß
> Mathias

Darüber könnte ich und würde ich gerne eine längere 
Sprach-philosophische und -geschichtliche Vorlesung halten. Mache ich 
aber nicht. Glück gehabt. ;-)

Am besten Du merkst es Dir einfach, dass Eingangssignale einer Mimik 
nicht zwingend auch mit dem inneren Zustand dieser Mimik übereinstimmen 
müssen. Das ist nur eine menschliche Assoziation, keine Regel.

Schliesslich erscheint auf der Ampel auch kein, gedrückter metallener 
Knopf mit Pfeil, um Dir anzuzeigen, dass Du drauf gedrückt hast. Auch in 
der Ampelsteuerung selbst, gibt es das nicht.

von Jakob (Gast)


Lesenswert?

> Um das Bit zu löschen muss eine 1 an die entsprechende Position
> geschrieben werden!

> Ist das so richtig?

Mir fällt so schnell kein Flag-Bit ein, das nicht mit '1',
oder mit Ausführung des Interrupts gelöscht wird.

Im einfachsten Fall:
Flag-Register lesen, die interessanten Bits mit AND herausfiltern
und in's Flag-Register zurückschreiben.

Es ist häufig günstiger, zugehörige Flag-Bits zu löschen, bevor ein
Interrupt "enabled" wird. Sonst arbeitet die Interruptfunktion
gleich mal veraltete Ereignisse ab, womit die erhoffte Reaktion auf
folgende Ereignisse vermurkst wird...

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.