UART: Endlosschleife: Lese-Buffer leeren?

OP #2243898
Lesenswert?

Hallo zusammen,

ich weiß nicht genau wieso, aber meine Sende-Routine endet immer wieder 
in einer Endlosschleife.

Ich initialisiere den UART so:
1
  UCA0CTL1 = UCSWRST + UC7BIT + UCSSEL_1;  
2
  UCA0CTL0 = UCPEN + UCPAR;   // Parity enabled, Even Parity
3
  
4
  // BRCLK Baudrate
5
  //---------------
6
  UCA0BR0 = 0x03;                           // 32k/2400 - 13.65
7
  UCA0BR1 = 0x00;                           //
8
  UCA0MCTL = 0x06;                          // Modulation
9
  
10
  UCA0CTL1 &=~ UCSWRST;                     // Initialize USART state machine
11
  IE2 |= UCA0RXIE;                          // Enable USART1 TX interrupt --> ISR bei Empfang

Die Sende und Empfangsroutine sieht dann so aus:
1
#pragma vector = USCIAB0RX_VECTOR
2
__interrupt void USCIAB0RX_ISR(void)
3
{
4
    if (UCA0RXBUF == ('1'))
5
    {
6
      Uart_SendText("End");
7
      IE2 &= ~UCA0RXIE;
8
      UCA0TXBUF = 0;
9
      LeaveNode();
10
      m_Uart = FALSE;
11
    }
12
    else
13
    {
14
      // Echo received char
15
      while(!(IFG2&UCA0TXIFG));  
16
      UCA0TXBUF = UCA0RXBUF;
17
      IFG2 = 0;
18
    }
19
}

Auf gut Deutsch: Wenn eine "1" empfangen wird, wird der Empfang 
eingestellt. Andernfalls soll das empfangene Zeichen einfach nur 
zurückgegeben werden.

Das Resultat ist nun leider, dass der uC endlos lang sendet und ich 
damit nicht wirklich was anfangen kann.

Meine Vermutung ist, dass UCA0RXBUF nicht geleert wird. Muss ich das 
selber machen?

Gibt es andere schöne Routinen, die nicht in einer Endlosschleife enden?
Moderator (Firma: Titel) Persönliche Seite #2243908
Lesenswert?

Roland M. schrieb:
> Meine Vermutung ist, dass UCA0RXBUF nicht geleert wird.
Du kannst den nicht LEEREN. Da steht immer irgendwas drin...  :-/

> Muss ich das selber machen?
Ob ein Zeichen über die serielle Schnitte angekommen ist, siehst du an 
einem Empfangsflag in einem Statusregister.

Wenn du sagen würdest, um welchen uC sich das da handelt, könnte dir 
sicher noch jemand den Namen des Registers sagen...

BTW: warum nimmst du nicht einfach eine fertige Empfangsreoutine? Jeder 
Hersteller hat da ein paar Beispielprogramme z.B. in einer App-Note zur 
Verfügung...
OP #2243922
Lesenswert?

Es handelt sich um einen MSP430FG4618.

Ich habe bisher keine fertige Empfangsroutine gefunden, werde aber mal 
die Application Notes durchwühlen...


EDIT:

So funktioniert die ROutine noch und liefert mir wunderbar ein Echo...
1
#pragma vector = USCIAB0RX_VECTOR
2
__interrupt void USCIAB0RX_ISR(void)
3
{
4
    while (!(IFG2 & UCA0TXIFG))
5
    {  }                                        // USART1 TX buffer ready?
6
    UCA0TXBUF = UCA0RXBUF;
7
}

Wenn ich sie nur leicht abändere, sodass ich eine 2 kriegen will, wenn 
ich eine 1 sende, dann kriege ich schon wieder nur Datenmüll raus OBWOHL 
ich doch noch nichtmals die 1 gesendet habe...
1
#pragma vector = USCIAB0RX_VECTOR
2
__interrupt void USCIAB0RX_ISR(void)
3
{
4
    while (!(IFG2 & UCA0TXIFG))
5
    {  }                                        // USART1 TX buffer ready?
6
    char byte = UCA0RXBUF;
7
    byte += 1;
8
    UCA0TXBUF = byte;
9
}

Wirklich, ich blicke da nicht durch...
Moderator (Firma: Titel) Persönliche Seite #2244476
Lesenswert?

Roland M. schrieb:
> Wenn ich sie nur leicht abändere, sodass ich eine 2 kriegen will, wenn
> ich eine 1 sende, dann kriege ich schon wieder nur Datenmüll raus OBWOHL
> ich doch noch nichtmals die 1 gesendet habe...
Von wo aus sendest du? Vom PC aus? Drückst du zwischendurch auf Enter?

> __interrupt void USCIAB0RX_ISR(void)
> {
>     while (!(IFG2 & UCA0TXIFG))
>     {}
Man wartet nicht in einem Interupt. Auf gar nichts!
Du kannst im Interrupt die Daten auslesen, zwischenspeichern und ein 
Flag setzen. Und dann in der Main-Loop das Flag überprüfen, und wenn es 
gesetzt ist, die Daten zurückschicken.
OP #2244501
Lesenswert?

Gut, dann werde ich das morgen früh mal abändern und aus dem Interrupt 
eine Funktion aufrufen, die dann das empfangene Byte bearbeitet.

Aber ändert das überhaupt etwas?

Wenn ich aus dem Interrupt eine Funktion aufrufe und diese dann wartet?

Also hab ich dich richtig verstanden, wenn ich keine Funktion aufrufen 
soll, sondern in der MainLoop das "Ereignis" abarbeiten soll, ja?
#2244506
Lesenswert?

Roland M. schrieb:
> Wenn ich sie nur leicht abändere, sodass ich eine 2 kriegen will, wenn
> ich eine 1 sende, dann kriege ich schon wieder nur Datenmüll raus OBWOHL
> ich doch noch nichtmals die 1 gesendet habe...
> #pragma vector = USCIAB0RX_VECTOR
> __interrupt void USCIAB0RX_ISR(void)
> {
>     while (!(IFG2 & UCA0TXIFG))
>     {  }                                        // USART1 TX buffer ready?
>     char byte = UCA0RXBUF;
>     byte += 1;
>     UCA0TXBUF = byte;
> }

Versuch mal den Empfangsbuffer als erstes zu leeren. Wie Lothar schon 
sagte: In ner Interruptroutine wartet man auf nichts, dafür gibts main() 
und co ;) .
Problem ist schonmal, dass du erst wartest, dass der Sendebuffer leer 
ist bevor du den Empfangsbuffer, der den Interrupt ausgelöst hat, 
sicherst. Das ist aber eigentlich das Erste, das man hier sichert (und 
das sollte so schnell wie möglich passieren, deshalb die erste Aktion im 
Interrupt eigentlich). Wenn du zu lange nämlich damit wartest kanns 
passieren, dass dir nachfolgende Zeichen den Empfangsbuffer versaun.

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