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


von Andreas H. (heilinger)


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:
1
#define MYUBRR 64         //für Baudrate 19.2k
2
3
void USART_init(unsigned int ubrr)
4
{
5
  UBRR0H = (unsigned char) (ubrr>>8);   //Set baud rate
6
  UBRR0L = (unsigned char) ubrr;
7
  
8
  UCSR0C = (3<<UCSZ00);     //Set frame format
9
  UCSR0B = (1<<RXCIE0) | (1<<UDRIE0) |(1<<RXEN0)|(1<<TXEN0); //Enable receiver & transmitter and receiver & buffer empty interrupt
10
}
11
12
void send_Startdaten()
13
{
14
  uc_Send_TX_data[0] = (0x9B);    //"}"
15
  uc_Send_TX_data[1] = (0xD6);    //"Ö"
16
  uc_Send_TX_data[2] = (0x54);    //"T"
17
  uc_Send_TX_data[3] = (0xC8);    //"È"
18
  uc_Send_TX_data[4] = (0x0B);    //"K"
19
  uc_Send_TX_data[5] = (0x70);    //"p"
20
  uc_Send_TX_data[6] = (0x0D);    //<CR>
21
}
22
23
ISR(USART_UDRE_vect)
24
{
25
 while (!( UCSR0A & (1<<UDRE0)));           //transmit buffer empty?
26
 UDR0 = uc_Send_TX_data[uc_TX_zaehler_data];//Put data in buffer sends data
27
 uc_TX_zaehler_data++; 
28
  
29
 if ((uc_Send_TX_data[uc_TX_zaehler_data] & (0x0D)) == (0x0D))  //<CR>?
30
 {
31
  uc_TX_zaehler_data = 0;      //Protokoll zu Ende
32
  uint_Flag1 |= (1<<BIT14);    //Flag: Transmitter interrupt aus
33
 }
34
}
35
int main(void)
36
{
37
  USART_init(MYUBRR);     //USART0 konfigurieren
38
  send_Startdaten();      //Startsignal für RS232
39
  sei();                  //global ISR aktivieren  
40
  USART_Transmit(uc_Send_TX_data); //Startsignal anfangen zu senden
41
42
while(1)  
43
{
44
  if (uint_Flag1 & (0x4000))
45
  UCSR0B &= ~(1<<UDRIE0);   //RS232-Transmitter-Interrupt ausschalten   
46
  
47
}
48
return 0;
49
}

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.

von LordZiu (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Hier
1
 UDR0 = uc_Send_TX_data[uc_TX_zaehler_data];//Put data in buffer sends data
2
 uc_TX_zaehler_data++; 
3
  
4
 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.

von Andreas H. (heilinger)


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

von Karl H. (kbuchegg)


Lesenswert?

Code?

von LordZiu (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Code?

Plus initialisierung und Datentyp deines Sende-Daten-Arrays.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Heil schrieb:
> habe das Inkrementieren nun hinter die Abfrage geschrieben.

Keine gute Idee

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

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?

von Stefan B. (stefan) Benutzerseite


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?

von Karl H. (kbuchegg)


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.

von Andreas H. (heilinger)


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!

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.