Atmega48 UART sendet bei TX Abschaltung ein ungültiges Zeichen

Gast #3699144
Hallo,

ich bin dabei mich auf dem ATMega48 mit der UART Schnittstelle zu 
befassen (in Assembler).

Das funktioniert soweit wie erwartet und ich kann Zeichen an das 
Terminalprogramm auf dem PC senden.
Mir fällt jedoch auf, dass das Deaktivieren und erneute Aktivieren des 
UART nicht transparent für ein permanent lauschendes Terminalprogramm 
von statten geht.

Das Problem, das auftritt, ist dass nach Aus- und wieder Einschalten des 
TX ein zusätzliches Zeichen vom Terminalprogramm empfangen wird. In den 
angehängten Screenshots ist das gut zu sehen. Da ist der Pegel auf der 
TX Leitung zu sehen und der Text der am Terminal empfangen wird.

Hier mal der funktionierende Fall und der Problemfall als Pseudocode:

Das folgende funktioniert einwandfrei:

    Initialisierung UART
Begin:
    Warte auf Tastendruck
    Aktiviere TX
    SendByte "H"
    SendByte "A"
    SendByte "L"
    SendByte "L"
    SendByte "O"
    Jmp Begin

Der folgende Code sendet nach der TX-Aus-/Einschaltsequenz vor dem 
ersten regulären Zeichen ein "_" an das Terminalprogramm.

    Initialisierung UART
Begin:
    Warte auf Tastendruck
    Aktiviere TX
    SendByte "H"
    SendByte "A"
    SendByte "L"
    SendByte "L"
    SendByte "O"
    Deaktiviere TX
    Jmp Begin

Ist es normal, dass der UART beim Aus-/Einschalten kurzfristig 
undefinierte Pegel am RX anliegen hat?

Hier noch die drei echten Codeschnippsel der UART-Routinen (auf das 
wichtigste reduziert und mit aufgelösten Konstanten):

AktiviereTX:
    lds  r17, UCSR0B                 ; TX und TXCIE aktivieren
    or   r17, 0b01001000             ; or: [ ]RXCIEn [x]TXCIEn [ ]UDRIEn 
[ ]RXENn [x]TXENn [ ]UCSZn2 [ ]RXB8n [ ]TXB8n
    sts  UCSR0B, r17

DeaktiviereTX:
    lds  r17, UCSR0A                 ; Wartet auf USART Data Register 
Empty
    sbrs r17, UDRE0
    rjmp DeaktiviereTX

    lds  r17, UCSR0B                 ; TX und TXCIE deaktivieren
    and  r17, 0b10110111             ; and: [x]RXCIEn [ ]TXCIEn 
[x]UDRIEn [x]RXENn [ ]TXENn [x]UCSZn2 [x]RXB8n [x]TXB8n
    sts  UCSR0B, r17

SendByte:
Wait:
    lds  r17, UCSR0A                 ; Wartet auf USART Data Register 
Empty...
    sbrs r17, UDRE0
    rjmp Wait
    ldi  r16, 'H'
    sts  UDR0, r16


Daher nochmal meine Frage: Ist das Verhalten normal oder ist das eher 
ein Programmfehler?

Gruß Markus
Angehängte Dateien:
Gast
Hallo Detlef,

ich versuche das mal aus den verschiedenen Includes zusammenzuschreiben:

.equ FCPU          = 20000000        ; CPU Taktfrequenz

.equ UH_BAUDRATE   = 9600            ; Baudrate (das Frameformat beträgt 
fest 8N1)

.equ UH_UBRR_VAL   = ((FCPU + UH_BAUDRATE * 8) / (UH_BAUDRATE * 16) - 1)
.equ UH_BAUD_REAL  = (FCPU / (16 * (UH_UBRR_VAL + 1)))            ; 
Reale Baudrate
.equ UH_BAUD_ERR   = ((UH_BAUD_REAL * 1000) / UH_BAUDRATE - 1000) ; 
Fehler in Promille

.equ UH_UCSR0A_INIT     = 0b00000000 ; USART Control and Status Register 
n A
                                     ; [ ]RXCn [x]TXCn [ ]UDREn [ ]FEn [ 
]DORn [ ]UPEn [ ]U2Xn [ ]MPCMn
                                     ; U2Xn: Double the USART 
Transmission Speed (bei asynchron = 0)

.equ UH_UCSR0B_INIT     = 0b00000000 ; USART Control and Status Register 
n B
                                     ; [x]RXCIEn [x]TXCIEn [x]UDRIEn 
[x]RXENn [x]TXENn [ ]UCSZn2 [ ]RXB8n [ ]TXB8n
                                     ; RXENn:  Receiver Enable
                                     ; TXENn:  Transmitter Enable
                                     ; UDRIEn: Data Register Empty 
Interrupt Enable
                                     ; RXCIEn: RX Complete Interrupt 
Enable
                                     ; TXCIEn: TX Complete Interrupt 
Enable

.equ UH_UCSR0B_RXTX_ON  = 0b11011000 ; Parameter-Bitmasken für 
UH_De/Activate
.equ UH_UCSR0B_RX_ON    = 0b10010000
.equ UH_UCSR0B_TX_ON    = 0b01001000
.equ UH_UCSR0B_RXTX_OFF = 0b00100111
.equ UH_UCSR0B_RX_OFF   = 0b01101111
.equ UH_UCSR0B_TX_OFF   = 0b10110111

.equ UH_UCSR0B_UDRIE_ON  = 0b00100000
.equ UH_UCSR0B_UDRIE_OFF = 0b11011111

.equ UH_UCSR0C_INIT     = 0b00000110 ; USART Control and Status Register 
n C
                                     ; [ ]UMSELn1 [ ]UMSELn0 [ ]UPMn1 [ 
]UPMn0 [ ]USBSn [ ]UCSZn1 [ ]UCSZn0 [ ]UCPOLn
                                     ; UMSELn0/1:    0:0 = Asynchron 
Mode
                                     ; UPMn0/1:      0:0 = keine Parity
                                     ; USBSn:          0 = kein Stoppbit
                                     ; UCSZn0/1/2: 0:1:1 = 8 Datenbits
                                     ; UCPOLn:     Clock Polarity (bei 
asynchron = 0)


UART_INIT:
    push r16                         ; Arbeitsregister auf Stack sichern

    ldi  r16, HIGH(UH_UBRR_VAL)      ; Baudrate setzen
    sts  UBRR0H, r16
    ldi  r16, LOW(UH_UBRR_VAL)
    sts  UBRR0L, r16

    ldi  r16, UH_UCSR0A_INIT         ; Control und Status Register A, B 
und C setzen
    sts  UCSR0A, r16
    ldi  r16, UH_UCSR0B_INIT
    sts  UCSR0B, r16
    ldi  r16, UH_UCSR0C_INIT
    sts  UCSR0C, r16

    pop  r16                         ; Arbeitsregister restaurieren


Gruß Markus
Och Mann, das ist doch Grütze!
Zu das Zeug wo DDRD und PORTD beschrieben werden.

Uwe S. schrieb:
> Hallo Markus,
>
> hänge an Uart TXD und RXD je einen externen Pullup-Widerstand.
>
> so 1k-10kΩ sollten ausreichen.

Vielleicht geht das, aber nur wenn Port D1 ein Eingang ist.
Das ist aber eher unwarscheinlich beim TXD.
Gast
Hallo,

Deaktivieren von TxD muss den Pin TxD auf Hi-Pegel lassen. Lo ergibt 
irgendwelche Zeichen oder Break.

Was soll das Deaktivieren überhaupt? Ist nichts zu senden, bewegt sich 
an TxD auch nichts.

Georg
Gast
@Detlef:

Da ich für Inputs (Taster) nur PROTC nutze, wird auch nur dieser von mir 
konfiguriert.

.equ PORTC_DDRC    = 0b00001001      ; DDRC (Richtungsregister, 
1=Output, 0=Input)
.equ PORTC_PORTC   = 0b00000000      ; Alle Bits an PORTC0 ausschalten

    ldi  Tmp, PORTC_DDRC             ; DDRC (Richtungsregister) setzen
    out  DDRC, Tmp

    ldi  Tmp, PORTC_PORTC            ; Bits und Pullup-Widerstände 
setzen
    out  PORTC, Tmp


@Alle anderen:

Hmm, nun wenn das Abschalten des TX nicht Usus ist, dann ist das ja in 
Ordnung. Ich kenne den genauen workflow dazu nicht.

Denkbar wäre aber, wenn eine Schaltung nur zeitweise über UART 
kommuniziert. Da würde ich von der logischen Überlegung her (und weil 
ich 'nen ordentlicher Mensch bin ;-) ) das TX Modul abschalten, wenn es 
nicht gebraucht wird. Mein Beispiel im ersten post ist ein 
Extrembeispiel das gebe ich zu, da nach einem Wort der TX sofort wieder 
dicht gemacht wird.

Das Verhalten mit dem "_" ist für mich aber auch kein Showstopper, ich 
wollte halt nur wissen, ob das normal ist oder ob ich etwas übersehen 
habe.

Manch einer ist ja auch schon mit dem TXC0-Bit auf die Nase gefallen, 
welches nur gelöscht wird, wenn die zugehörigen Interrupts aktiviert 
sind. Sendet man ohne aktivierte Interrupts, dann muss das Flag manuell 
gelöscht werden. Andernfalls funktioniert die Abfrage, ob das frame 
komplett übertragen wurde nicht korrekt. -> "This flag bit is set when 
the entire frame in the Transmit Shift Register has been shifted out and 
there are no new data currently present in the transmit buffer (UDRn). 
The TXCn Flag bit is automatically cleared when a transmit complete 
interrupt is executed, or it can be cleared by writing a one to its bit 
location."

Irgendeine ähnliche, fiese Kleinigkeit in diese Richtung hatte ich für 
meinen Fall in Verdacht.
Gast
Markus schrieb:
> Da würde ich von der logischen Überlegung her (und weil
> ich 'nen ordentlicher Mensch bin ;-) ) das TX Modul abschalten

Wenn es denn deine Nerven beruhigt, kannst du das ja machen, aber dann 
eben so, dass der Pin konstant Hi ist.

Georg
Gast
Das mit dem High-Pegel habe ich gerade umgesetzt.
Was soll ich sagen? Geht ab wie Sahne! :-)
Besten Dank.

Herr Ober, je ein Bier bitte an die beiden Herren dort drüben (Uwe und 
Detlef)
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite
Markus schrieb:
> Denkbar wäre aber, wenn eine Schaltung nur zeitweise über UART
> kommuniziert. Da würde ich von der logischen Überlegung her (und weil
> ich 'nen ordentlicher Mensch bin ;-) ) das TX Modul abschalten, wenn es
> nicht gebraucht wird.
Diese Vorgehensweise ist umständlich, wenn du den Pin zwischendurch 
nicht für was anderes brauchst. So ähnlich wie wenn du die Lötstation 
die du zu Weihnachten bekommen hast, nach und vor jeder Benutzung bis 
hin zum Geschenkband ein- und wieder auspackst...

Du kannst das TX Modul eines AVR gar nicht einzeln abschalten. Du 
schaltest nur den Pintreiber um.
Gast
Okay, ich denke anhand des Lötstationen-Beispiels habe ich verstanden, 
dass ich TX/RX nicht immer wieder abschalten brauche. :-) Wieder was 
gelernt.

Besten Dank nochmal an alle, das ging echt schnell.

Gruß Markus

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.