www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR USART will nicht wie ich will


Autor: Andreas H. (heilinger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

möchte mit dem USART eine RS232-Schnittstelle betreiben. Dazu wollte ich 
jetzt zu Testzwecken einfach mal definierte Zeichen über den TxD meines 
ATmega48 versenden.

Ich schau mir das mit dem Scope an. Ich möchte 7 Zeichen verschicken, 
aber er schickt nur 6.
Hier mal die relevanten Teile meines Codes:
#define MYUBRR 64         //für Baudrate 19.2k

void USART_init(unsigned int ubrr)
{
  UBRR0H = (unsigned char) (ubrr>>8);   //Set baud rate
  UBRR0L = (unsigned char) ubrr;
  
  UCSR0C = (3<<UCSZ00);     //Set frame format
  UCSR0B = (1<<RXCIE0) | (1<<UDRIE0) |(1<<RXEN0)|(1<<TXEN0); //Enable receiver & transmitter and receiver & buffer empty interrupt
}

void send_Startdaten()
{
  uc_Send_TX_data[0] = (0x9B);    //"}"
  uc_Send_TX_data[1] = (0xD6);    //"Ö"
  uc_Send_TX_data[2] = (0x54);    //"T"
  uc_Send_TX_data[3] = (0xC8);    //"È"
  uc_Send_TX_data[4] = (0x0B);    //"K"
  uc_Send_TX_data[5] = (0x70);    //"p"
  uc_Send_TX_data[6] = (0x0D);    //<CR>
}

ISR(USART_UDRE_vect)
{
 while (!( UCSR0A & (1<<UDRE0)));           //transmit buffer empty?
 UDR0 = uc_Send_TX_data[uc_TX_zaehler_data];//Put data in buffer sends data
 uc_TX_zaehler_data++; 
  
 if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?
 {
  uc_TX_zaehler_data = 0;      //Protokoll zu Ende
  uint_Flag1 |= (1<<BIT14);    //Flag: Transmitter interrupt aus
 }
}
int main(void)
{
  USART_init(MYUBRR);     //USART0 konfigurieren
  send_Startdaten();      //Startsignal für RS232
  sei();                  //global ISR aktivieren  
  USART_Transmit(uc_Send_TX_data); //Startsignal anfangen zu senden

while(1)  
{
  if (uint_Flag1 & (0x4000))
  UCSR0B &= ~(1<<UDRIE0);   //RS232-Transmitter-Interrupt ausschalten   
  
}
return 0;
}

Und zwar wird das letzte Bit nicht gesendet (<CR>). Wenn ich den 
Transmitter-Interrupt anlassen, dann schickt er die ersten 6 Zeichen 
durchgehend, aber nie das 7. Zeichen.

Autor: LordZiu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du auf Byte 6 bist, inkrementierst du auf Byte 7 ohne es zu senden. 
Sondern schaltest dann gleich aus.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier
 UDR0 = uc_Send_TX_data[uc_TX_zaehler_data];//Put data in buffer sends data
 uc_TX_zaehler_data++; 
  
 if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?

überprüfst du bereits das nächste Byte, ob es 0x0D ist. Wenn ja stoppst 
du die Übertragung. Bei einem Byte gefolgt von einem 0x0D wird daher das 
0x0D nie übertragen.

Du inkementierst uc_TX_zaehler_data zu früh.

Autor: Andreas H. (heilinger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
habe das Inkrementieren nun hinter die Abfrage geschrieben.

Jetzt habe ich einen ganz komischen Effekt...

Er sendet das 5. Zeichen (0x0B) nicht?!?! Also wieder nur 6 Zeichen, 
aber jetzt fehlt ein Byte mitten drin °_o

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Code?

Autor: LordZiu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Code?

Plus initialisierung und Datentyp deines Sende-Daten-Arrays.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Heil schrieb:
> habe das Inkrementieren nun hinter die Abfrage geschrieben.

Keine gute Idee

Ich nehme an, das sieht jetzt so aus
ISR(USART_UDRE_vect)
{
 while (!( UCSR0A & (1<<UDRE0)));           //transmit buffer empty?
 UDR0 = uc_Send_TX_data[uc_TX_zaehler_data];//Put data in buffer sends data
  
 if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?
 {
  uc_TX_zaehler_data = 0;      //Protokoll zu Ende
  uint_Flag1 |= (1<<BIT14);    //Flag: Transmitter interrupt aus
 }

 uc_TX_zaehler_data++; 
}

Im if wird der zaehler auf 0 gesetzt, um gleich darauf inkrementiert zu 
werden.

Bitte: Auch bei vermeintlich kleinen Änderungen immer den neuen Code 
posten. Nicht beschreiben was du gemacht hast, sondern zeigen!

PS:
Die ISR wird aufgerufen, weil das UDR register empty ist. Genau so heißt 
ja auch die ISR. Die erste while Schleife ist daher sinnlos. Das UDR 
muss empty sein. Sonst wäre die ISR nicht aufgerufen worden!

Was mich ein wenig verblüfft: Im ISR Namen kommt die Nummer der UART gar 
nciht vor. Stimmt das tatsächlich?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Offtopic:

>  if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?

Wieso das "& (0x0D)"? Willst du nie z.B. ein 0x4D versenden?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan B. schrieb:
> Offtopic:
>
>>  if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?
>
> Wieso das "& (0x0D)"? Willst du nie z.B. ein 0x4D versenden?

Good catch.
Auch 0x0F könnte man so nicht versenden. 0x0B sollte aber durchgehen.

Autor: Andreas H. (heilinger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe das Problem gefunden. Erstmal auf jeden Fall vielen Dank 
bezüglich der Tipps mit der while-Schleife und der Abfrage des 
"Endzeichens 0x0D". Werde das ganze so umwandeln, dass ich nach einer 
bestimmten Anzahl gesendeter Bytes die Übertragung stoppe. Das 
Inkrementieren hatte ich übrigens ins else geschrieben, also wird nach 
dem Nullsetzen nicht nochmal inkrementiert. Warum die Nummer des USART 
im ISR-Namen nicht vorkommt: weil der ATmega48 nur einen hat ;)

Jetzt zu dem Problem:
Ich rufe die "USART_Transmit(uc_Send_TX_data)"-Funktion vor der while 
Schleife einmal auf. In dieser steht genau das gleiche, wie in der ISR. 
Es war ein Denkfehler von mir. Ich dachte die ISR wird nur dann 
aufgerufen, wenn ein Byte gesendet wurde und dann der Buffer leer ist. 
Aber die ISR wird ja direkt nach dem enablen durch sei() aufgerufen, 
also immer wenn der Buffer leer ist. Dadurch hat wohl die ISR den Zähler 
um einen nach oben  gezählt, während die Funktion von der main 
aufgerufen wurde.

Naja, blöder Denkfehler von mir. Aber Danke nochmals!

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.