AVR USART will nicht wie ich will

#1604061
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.
#1604080
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.
#1604110
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?
#1604187
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren