mikrocontroller.net

Forum: Compiler & IDEs "Fehler" in UART-Kommunikation


Autor: Matze Klaus (phytomed)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

ich verwende die uart-library von Peter Fleury,
es funktioniert auch alles.
Allerdings habe ich folgende Modifikationen vorgenommen,
welche nicht so funktionieren wie sie sollen.
(Uart.c)

char uart_buffer_read[32];

SIGNAL(UART0_RECEIVE_INTERRUPT)
//------------------------------------------------------------------------
// Function: UART Receive Complete interrupt
// Purpose:  called when the UART has received a character


//....wie gehabt und zusaetzlich...

    if(data == '\r' && !newUartData){
      for(index = 0; index < 9; index++){
  uart_buffer_read[8-index] =  UART_RxBuf[tmphead];

  tmphead = ( UART_RxHead - 1 - index) & UART_RX_BUFFER_MASK;
      }
      //uart_buffer_read[9]=0;

      newUartData = 1;
      uartActive = 1;
    }
}


Die Idee ist dabei, dass nur wenn ein '\r' eingegangen ist,
die das Wort gelesen werden soll
(main.c)

...

extern char uart_buffer_read[32];

...

main(){

...

  for(;;){

...
      
      if(newUartData > 0){
  
  snprintf(uart_buffer_write,32,"received : %s\n",uart_buffer_read);      
  uart_puts(uart_buffer_write);
      
  if (!strncmp_P(uart_buffer_read, loadDATA,8)){
    // daten holen vom Ende zum Amfang
    // letzte Daten zuerst
    uart_puts("if loadDATA\n");


  } else if(!strncmp_P(uart_buffer_read, nextDATA,8)){
    // naechste Daten holen
    uart_puts("if nextDATA\n");
...

        }
  }

}



Es funktioniert auch ein paar mal (ich glaube immer 4 mal),
dann wird uart_buffer_read nicht mehr geändert?

Wo ist mein Denkfehler?!?
Falls das Design insgesamt unguenstig ist waeren
weitere Hilfen auch immmer willkommen.

Falls noch irgendetwas unklar ist, meldet euch bitte!

Tausend Dank
Matthias

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> for(index = 0; index < 9; index++)
> {
>   uart_buffer_read[8-index] =  UART_RxBuf[tmphead];
>   tmphead = ( UART_RxHead - 1 - index) & UART_RX_BUFFER_MASK;
> }

1/ Das kräuselt mir die Fußnägel. Was soll hier gemacht werden und kann 
man das nicht schöner machen? Solche Subtraktionen bei Arrayzugriffen 
haben immer was fischiges.

2/ Das Umkopieren vom Empfangspuffer in den Auswertepuffer könntest du 
ja auch in main() machen, wenn du '\r' erkannt hast und dein Flag 
newUartData gesetzt hast.

3/ Ich sehe keine Stelle, wo du UART_RxBuf[] entleerst. Kann es sein, 
dass der einfach irgendwann nur voll ist und neu empfangene Daten 
verworfen werden, oder ist UART_RxBuf[] ein Ringpuffer?


Autor: Matze Klaus (phytomed)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin Stefan,

zu 1/ ich möchte den Fischgeruch gerne loswerden,
      aber wie "kopiere" ich sonst mein Wort?!?

zu 2/ Du hast recht, man kann dass auch in main() machen,
      allerdings ist (nur) so ein "Abwarten" bis das letzte Wort
      in main() bearbeitet wurde.

zu 3/ ja UART_RxBuf[] ist ein Ringbuffer,
      was heißt eigentlich "entleeren" und wie wird das gemacht.
      Entschuldige bitte, sicherlich eine dumme Frage.


Noch einmal zu dem Problem, es funktioniert ein paar mal,
daher vermute ich ein Fehler beim Ringbuffer.

    // calculate buffer index 
    tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
    
    if ( tmphead == UART_RxTail ) {
      // error: receive buffer overflow 
      lastRxError = UART_BUFFER_OVERFLOW >> 8;
    }else{
      // store new index
      UART_RxHead = tmphead;
      // store received data in buffer
      UART_RxBuf[tmphead] = data;
    }
    UART_LastRxError = lastRxError;




ist von Peter Fleury auch eine Bufferoverflow Behandlung,
warum benötigt man so etwas, eigentlich kann ein Ringbuffer
doch nicht überlaufen, oder?

Schon mal vielen Dank
Matthias

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ringpuffer heisst, dass die Schreibposition (und die Leseposition) vom 
Pufferanfang zum Pufferende wandert. Wenn die Schreibposition das Ende 
erreicht hat, beginnt die Schreibposition wieder vorne am Ringpuffer, 
WENN die Leseposition auch weitergewandert ist und so Platz am 
Ringpufferanfang frei gemacht hat. D.h. erst wenn du als Anwender wieder 
Platz im Ringpuffer machst (durch Auslesen), kommen frische Daten rein.

In der Doku steht:

UART_BUFFER_OVERFLOW
Receive ringbuffer overflow. We are not reading the receive buffer fast 
enough, one or more received character have been dropped
http://homepage.hispeed.ch/peterfleury/group__pfle...

D.h. wenn wir nicht auslesen, wird der Ringpuffer voll. So wie es oben 
aussieht, hört die Library dann auf, neue Daten in den Ringpuffer zu 
schreiben. Und die Library kann dich als Anwender darüber informieren.

Wenn man so eine fertige Library nimmt, ändert man möglichst nicht die 
Libraryfunktionen, wenn es anders geht.

Ein Weg ohne Änderung der Library könnte z.B. so aussehen:
#define MEINPUFFERLAENGE 32
unsigned char uart_buffer_read[MEINPUFFERLAENGE];
unsigned char meinpufferindex = 0;

  // ...
  while(1)
  {
    unsigned int data = uart_getc(); // Ringpuffer auslesen

    if (!(data & 0xFF00))
    { 
      // Zeichen ohne Fehler empfangen
      unsigned char zeichen = data & 0x00FF;

      // Pufferüberlauf verhindern. Brutalmethode: Puffer resetten
      if (meinpufferindex >= MEINPUFFERLAENGE-1)
        meinpufferindex = 0;

      if (zeichen == '\r')
      {
        // Satzende? Auswerten!
        snprintf(uart_buffer_write, 32, "received : %s\n",
                 uart_buffer_read);      
        uart_puts(uart_buffer_write);
      
        if (!strncmp_P(uart_buffer_read, loadDATA, 8))
        {
          uart_puts("if loadDATA\n");
        } 
        else if(!strncmp_P(uart_buffer_read, nextDATA, 8))
        {
          uart_puts("if nextDATA\n");
        }

        // Puffer leeren für nächsten Satz
        meinpufferindex = 0;
      } 
      else
      {
        // sonstiges Zeichen in Puffer verschieben
        uart_buffer_read[meinpufferindex++] = zeichen;
      }

      // bisher empfangenes abschliessen
      uart_buffer_read[meinpufferindex] = 0;
    }
    else
    {
      switch(data >> 8)
      {
        case UART_NO_DATA:
          uart_puts("UART_NO_DATA\n");
          break;
        case UART_BUFFER_OVERFLOW:
          uart_puts("UART_BUFFER_OVERFLOW\n");
          break;
        case UART_OVERRUN_ERROR:
          uart_puts("UART_OVERRUN_ERROR\n");
          break;
        case UART_FRAME_ERROR:
          uart_puts("UART_FRAME_ERROR\n");
          break;
        default:
          uart_puts("UART_UNKNOWN_ERROR\n");
          break;
      }
    }
  }

  

Autor: Matze Klaus (phytomed)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tausend Dank Stefan,

wie Du sicher gemerkt hast bin ich kein guter Programmierer,
um deine Korrekturen / Anmerkungen zu verstehen und bewerten,
muss ich mir die "Ideen" etwas zu Gemüte führen.

Ich danke Dir herzlich
Matthias

Autor: Matze Klaus (phytomed)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin Stefan,

TAUSEND DANK, es hat (fast) alles funktioniert.

"Meine" Version sieht letztendlich folgendermaßen aus:
main(){

...

for(;;){

...

    }else if(uartActive > 0){

...

      // Ringpuffer auslesen 
      unsigned int data = uart_getc(); 

      if (!(data & 0xFF00)){
  
  // Zeichen ohne Fehler empfangen
  unsigned char token = data & 0x00FF;
  
  // Pufferüberlauf verhindern. Brutalmethode: Puffer resetten
  if (UartBufferIndex >= UartBufferLength-1){
    UartBufferIndex = 0;
  }

  if (token == '\r'){

    // bisher empfangenes abschliessen
    newUartData = 1;
    uart_buffer_read[UartBufferIndex] = 0;
    UartBufferIndex = 0;

  }else{

    // sonstiges Zeichen in Puffer verschieben
    uart_buffer_read[UartBufferIndex++] = token;
  }
  

      }else {
  switch(data >> 8)
    {
    case UART_NO_DATA:{
      uart_puts("UART_NO_DATA\n");
    };break;
      
    case UART_BUFFER_OVERFLOW:{
      uart_puts("UART_BUFFER_OVERFLOW\n");
    };break;

    case UART_OVERRUN_ERROR:{
      uart_puts("UART_OVERRUN_ERROR\n");
    };break;

    case UART_FRAME_ERROR:{
      uart_puts("UART_FRAME_ERROR\n");
    };break;

    default:{
      uart_puts("UART_UNKNOWN_ERROR\n");
    };break;

    }
      }


      if(newUartData > 0){
  
  snprintf(uart_buffer_write,32,"received : %s\n",uart_buffer_read);      
  uart_puts(uart_buffer_write);
      
  if (!strncmp_P(uart_buffer_read, loadDATA,8)){
    // daten holen vom Ende zum Amfang
    // letzte Daten zuerst
    uart_puts("if loadDATA\n");


  } else if(!strncmp_P(uart_buffer_read, nextDATA,8)){
    // naechste Daten holen
    uart_puts("if nextDATA\n");


  } else {
    // receive wrong string 
    // send something to the PC
    uart_puts("unknown Command\n");

  }
  
  newUartData = 0;
  uartActive = 0;

      }// end of newUartData

...

    }
...

}


UartActive wird in dem Empfangsinterrupt 1 gesetzt,
so dass nur wenn was empfangen wurde,
die "Schleife" durchlaufen werden muss.

Es werden nun alle Befehle in beliebiger Anzahl akzeptiert,
allerdings passieren "dazwischen" jeweils 3 UART_UNKNOWN_ERROR,
was mich aber nicht stört:

received : sdfgdssd
unknown Command
UART_UNKNOWN_ERROR
UART_UNKNOWN_ERROR
UART_UNKNOWN_ERROR
received : loadDATA
if loadDATA



Küss die Hand
Matthias

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.