Forum: Compiler & IDEs Welche Bedingung um UART RXC zurückzusetzen ?


von Andi (Gast)


Lesenswert?

Hallo,
ich habe folgendes Problem. Ich emfpange per UART etwas und möchte die 
empfangenen Daten in ein Array speichern (siehe Code). jedoch hänge ich 
immer in der WHILE Schleife fest, in der geprüft wird ob der 
Empfang(RXC1 Flag) erfolgreich abgeschlossen ist.

Was ist die Bedingung dafür um das RXC1 Flag zurück zu setzen ?

Im Datenblatt steht folgendes:
the RXCn flag can be used to check that there are no unread data in the 
receive buffer.

Aber ich lese die Daten doch mit der FOR-Schleife aus, also sind die 
Daten nicht ungelesen?!
1
uint8_t diag_data[7];
2
3
uint8_t Receive_Byte()
4
{
5
  while (!(UCSR1A & (1 << RXC1)))
6
  ;
7
  return UDR1; //Zeichen aus UDR zurueckgeben
8
}
9
10
for(int u=0 ; u<7 ; u++)
11
{
12
   diag_data[u] = Receive_Byte(); //nächstes Byte empfangen
13
}

von hdd (Gast)


Lesenswert?

Das RXC-Flag wird gesetzt, wenn die Daten vollständig in UDR stehen und 
wieder gelöscht wenn du diese Daten gelesen hast. Allerdings wartest du 
in der While-Schleife darauf, dass das Flag gelöscht ist und das 
Auslesen der Daten würde ja erst passieren, wenn du die Schleife 
verlässt.
Du solltest lieber warten, solange es nicht gesetzt ist und wenn es dann 
gesetzt wurde, auslesen.

von Andi (Gast)


Lesenswert?

Karl heinz Buchegger schrieb im Beitrag #1883497:
> Es gibt ein perfektes Bit, welches anzeigt ob im UART ein Zeichen
> empfangen wurde oder nicht und welches durch Auslesen aus UDR gelöscht
> wird.

Aha und wie heißt dieses, mir noch unbekannte, Zauberbit ? :-)

Hab keine Zeit mich jetzt komplett durch die UART Seiten durchzuwühlen!

von Karl H. (kbuchegg)


Lesenswert?

Ich hab den Post zurückgezogen.
Man sollte nicht unter Zeitdruck antworten.
Du hast schon das richtige Bit.

Zeig mal mehr Code, insbesondere die Initialisierung der UART

von Andi (Gast)


Lesenswert?

Hi Karl,

habe mich auch schon gewundert, da ich mir die UART Teile schon ziemlich 
gut angeschaut habe ;)

Hier noch die UART_Init.
Also der Empfang mit UART ISR geht, Senden tu ich NICHT mit ISR.

Nachdem ich über UART eine Anfrage versende, erwarte ich die Nachrichten 
die ich bis jetzt noch nicht mit der ISR verarbeiten kann. Als Antwort 
kommen zwischen 1-3 Nachrichten zurück mit je 8Byte größe. Jede dieser 
1-3 Nachrichten landet in der FOR-Schleife.... kann das Problem damit 
zusammen hängen ?

1
void USART_Init()
2
{
3
  BAUD_Init(NORMB);  // Baudrate setzen
4
5
  // Receiver und Transmitter einschalten UND Receive Interrupts einschalten
6
  UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
7
8
  //Frameformat setzen: Asynchron 8 Daten, Keine Parität 1 Stop bit (8N1)
9
  UCSR1C = (1 << UCSZ11) | (1 << UCSZ10);
10
}

von Karl H. (kbuchegg)


Lesenswert?

UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
                                       *************

Wenn du keinen Interrupt Handler hast, darfst du ihn auch nicht 
freigeben! Wenn du aber einen Interrupt Handler hast, dann musst du den 
kompletten Empfang über Interrupts abwickeln. Pollen des RXC Flags ist 
dann nicht mehr

(Ich wusste doch, das ich im Eröffnungsposting irgendwas von Interrupt 
gelesen hatte)

Zeig mal alles!

von Andi (Gast)


Lesenswert?

Warum habe ich keinen ISR Handler ?
Also hier mal die ISR_RX...
Das Erste Datenbyte kann ich auswerten (0x5D) was mit "Byte = 
Receive_Byte();" ausgelesen wird... aber an den weiteren Bytes scheiter 
ich.
1
uint8_t Receive_Byte()
2
{
3
  while (!(UCSR1A & (1 << RXC1)))
4
  // warten bis Zeichen verfuegbar
5
    ;
6
  return UDR1; //Zeichen aus UDR zurueckgeben
7
}
8
9
10
ISR(USART1_RX_vect)
11
{  
12
  uint8_t diag_data[7];
13
  Byte = Receive_Byte();
14
15
  if(Byte == 0x5D)  //1. Datenbyte
16
  {    
17
    for(int u=0 ; u<7 ; u++)
18
    {
19
      diag_data[u] = Receive_Byte(); //nächsten 7 Datenbytes empfangen
20
    }
21
  }
22
  else
23
    .....
24
}

von Karl H. (kbuchegg)


Lesenswert?

Andi schrieb:
> Warum habe ich keinen ISR Handler ?

Weil du ihn noch nicht hergezeigt hast?


> [c]
> uint8_t Receive_Byte()
> {
>   while (!(UCSR1A & (1 << RXC1)))
>   // warten bis Zeichen verfuegbar
>     ;
>   return UDR1; //Zeichen aus UDR zurueckgeben
> }
>
>
> ISR(USART1_RX_vect)
> {
>   uint8_t diag_data[7];
>   Byte = Receive_Byte();

Das ist Unsinn.
Du bist in der ISR weil ein Byte empfangen wurde. Du brauchst hier 
nicht mehr abfragen, ob ein Byte empfangen wurde bzw. darauf warten. Wir 
wissen, das eines empfangen wurde, sonst wäre die ISR nicht aufgerufen 
worden.

>
>   if(Byte == 0x5D)  //1. Datenbyte
>   {
>     for(int u=0 ; u<7 ; u++)
>     {
>       diag_data[u] = Receive_Byte(); //nächsten 7 Datenbytes empfangen
>     }

das geht nicht.
Du bist in der ISR

In der ISR holst du dir das empfangene Zeichen und speicherst es weg. 
Danach gehts wieder raus aus der ISR. Sobald das nächste Zeichen 
empfangen wird, wird die ISR erneut aufgerufen.

Du musst weg vom Denken in Schleifen und hin zum Denken in Ereignissen: 
Jetzt ist das Ereignis 'Zeichen empfangen' eingetreten. Was mach ich mit 
dem Zeichen?
Und warten in einer ISR geht gar nicht.

von Andi (Gast)


Lesenswert?

Jetzt kommt auch bei mir das Licht an :-)
Bin erst seit paar Wochen in der Thematik... daher diese Fragen!

Ok, werde es mal kurz umschreiben und das Erg. posten !

THX schonmal im vorus !!

von Andi (Gast)


Lesenswert?

Ich glaub ich steh grad etwas auf dem Schlauch.... also in UDR wird 
immer nur EIN Byte von meiner 8Byte großen Nachricht gespeichert.
Das muss ich jetzt Zwischenspeichern und sobald das nächste Byte kommt, 
wird die ISR erneut aufgerufen in der ich das Byte zwischenspeichern 
muss...u.s.w.
.... Ich bekomm grad nix mehr hin!

von Karl H. (kbuchegg)


Lesenswert?

Andi schrieb:
> Ich glaub ich steh grad etwas auf dem Schlauch.... also in UDR wird
> immer nur EIN Byte von meiner 8Byte großen Nachricht gespeichert.
> Das muss ich jetzt Zwischenspeichern und sobald das nächste Byte kommt,
> wird die ISR erneut aufgerufen in der ich das Byte zwischenspeichern
> muss...u.s.w.

Ganz genau


1
volatile uint8_t bytesReceived;
2
volatile uint8_t diag_data[7];
3
4
ISR(USART1_RX_vect)
5
{  
6
  uint8_t nextByte = UDR1;
7
8
  if( bytesReceived == 0 ) {    // warten wir auf das Startbyte?
9
    if( nextByte == 0x5D )
10
      bytesReceived = 1;        // die restlichen Bytes sind Daten
11
  }
12
13
  else {
14
    if( bytesReceived <= 7 ) {
15
      diag_data[ bytesReceived - 1 ] = nextByte;
16
      bytesReceived++;
17
    }
18
  }
19
}

Wenn bytesReceived den Wert 8 erreicht hat, sind alle Bytes da. In der 
Hauptschleife die Daten auswerten und bytesReceived zum Schluss wieder 
auf 0 setzen.
1
....
2
3
4
int main()
5
{
6
  ....
7
8
  while( 1 ) {
9
10
    ...
11
    if( bytesReceived == 8 ) {
12
      // mach was mit diag_data
13
      bytesReceived = 0;
14
    }
15
16
    ...
17
  }
18
}

von Andi (Gast)


Lesenswert?

Danke Karl,

habe es im Detail so übernommen und es läuft... muss jetzt das drumherum 
noch bisschen anpassen, da ich nicht nur Nachrichten bekomme die mit 
0x5D anfangen!

Top Sache, hast mir echt geholfen !!

Gruß & Danke
Andi

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.