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


von Matze K. (phytomed)


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.
1
(Uart.c)
2
3
char uart_buffer_read[32];
4
5
SIGNAL(UART0_RECEIVE_INTERRUPT)
6
//------------------------------------------------------------------------
7
// Function: UART Receive Complete interrupt
8
// Purpose:  called when the UART has received a character
9
10
11
//....wie gehabt und zusaetzlich...
12
13
    if(data == '\r' && !newUartData){
14
      for(index = 0; index < 9; index++){
15
  uart_buffer_read[8-index] =  UART_RxBuf[tmphead];
16
17
  tmphead = ( UART_RxHead - 1 - index) & UART_RX_BUFFER_MASK;
18
      }
19
      //uart_buffer_read[9]=0;
20
21
      newUartData = 1;
22
      uartActive = 1;
23
    }
24
}

Die Idee ist dabei, dass nur wenn ein '\r' eingegangen ist,
die das Wort gelesen werden soll
1
(main.c)
2
3
...
4
5
extern char uart_buffer_read[32];
6
7
...
8
9
main(){
10
11
...
12
13
  for(;;){
14
15
...
16
      
17
      if(newUartData > 0){
18
  
19
  snprintf(uart_buffer_write,32,"received : %s\n",uart_buffer_read);      
20
  uart_puts(uart_buffer_write);
21
      
22
  if (!strncmp_P(uart_buffer_read, loadDATA,8)){
23
    // daten holen vom Ende zum Amfang
24
    // letzte Daten zuerst
25
    uart_puts("if loadDATA\n");
26
27
28
  } else if(!strncmp_P(uart_buffer_read, nextDATA,8)){
29
    // naechste Daten holen
30
    uart_puts("if nextDATA\n");
31
...
32
33
        }
34
  }
35
36
}



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

von Stefan (Gast)


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?


von Matze K. (phytomed)


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.
1
    // calculate buffer index 
2
    tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
3
    
4
    if ( tmphead == UART_RxTail ) {
5
      // error: receive buffer overflow 
6
      lastRxError = UART_BUFFER_OVERFLOW >> 8;
7
    }else{
8
      // store new index
9
      UART_RxHead = tmphead;
10
      // store received data in buffer
11
      UART_RxBuf[tmphead] = data;
12
    }
13
    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

von Stefan (Gast)


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__pfleury__uart.html#ga1

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:
1
#define MEINPUFFERLAENGE 32
2
unsigned char uart_buffer_read[MEINPUFFERLAENGE];
3
unsigned char meinpufferindex = 0;
4
5
  // ...
6
  while(1)
7
  {
8
    unsigned int data = uart_getc(); // Ringpuffer auslesen
9
10
    if (!(data & 0xFF00))
11
    { 
12
      // Zeichen ohne Fehler empfangen
13
      unsigned char zeichen = data & 0x00FF;
14
15
      // Pufferüberlauf verhindern. Brutalmethode: Puffer resetten
16
      if (meinpufferindex >= MEINPUFFERLAENGE-1)
17
        meinpufferindex = 0;
18
19
      if (zeichen == '\r')
20
      {
21
        // Satzende? Auswerten!
22
        snprintf(uart_buffer_write, 32, "received : %s\n",
23
                 uart_buffer_read);      
24
        uart_puts(uart_buffer_write);
25
      
26
        if (!strncmp_P(uart_buffer_read, loadDATA, 8))
27
        {
28
          uart_puts("if loadDATA\n");
29
        } 
30
        else if(!strncmp_P(uart_buffer_read, nextDATA, 8))
31
        {
32
          uart_puts("if nextDATA\n");
33
        }
34
35
        // Puffer leeren für nächsten Satz
36
        meinpufferindex = 0;
37
      } 
38
      else
39
      {
40
        // sonstiges Zeichen in Puffer verschieben
41
        uart_buffer_read[meinpufferindex++] = zeichen;
42
      }
43
44
      // bisher empfangenes abschliessen
45
      uart_buffer_read[meinpufferindex] = 0;
46
    }
47
    else
48
    {
49
      switch(data >> 8)
50
      {
51
        case UART_NO_DATA:
52
          uart_puts("UART_NO_DATA\n");
53
          break;
54
        case UART_BUFFER_OVERFLOW:
55
          uart_puts("UART_BUFFER_OVERFLOW\n");
56
          break;
57
        case UART_OVERRUN_ERROR:
58
          uart_puts("UART_OVERRUN_ERROR\n");
59
          break;
60
        case UART_FRAME_ERROR:
61
          uart_puts("UART_FRAME_ERROR\n");
62
          break;
63
        default:
64
          uart_puts("UART_UNKNOWN_ERROR\n");
65
          break;
66
      }
67
    }
68
  }

  

von Matze K. (phytomed)


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

von Matze K. (phytomed)


Lesenswert?

Moin Stefan,

TAUSEND DANK, es hat (fast) alles funktioniert.

"Meine" Version sieht letztendlich folgendermaßen aus:
1
main(){
2
3
...
4
5
for(;;){
6
7
...
8
9
    }else if(uartActive > 0){
10
11
...
12
13
      // Ringpuffer auslesen 
14
      unsigned int data = uart_getc(); 
15
16
      if (!(data & 0xFF00)){
17
  
18
  // Zeichen ohne Fehler empfangen
19
  unsigned char token = data & 0x00FF;
20
  
21
  // Pufferüberlauf verhindern. Brutalmethode: Puffer resetten
22
  if (UartBufferIndex >= UartBufferLength-1){
23
    UartBufferIndex = 0;
24
  }
25
26
  if (token == '\r'){
27
28
    // bisher empfangenes abschliessen
29
    newUartData = 1;
30
    uart_buffer_read[UartBufferIndex] = 0;
31
    UartBufferIndex = 0;
32
33
  }else{
34
35
    // sonstiges Zeichen in Puffer verschieben
36
    uart_buffer_read[UartBufferIndex++] = token;
37
  }
38
  
39
40
      }else {
41
  switch(data >> 8)
42
    {
43
    case UART_NO_DATA:{
44
      uart_puts("UART_NO_DATA\n");
45
    };break;
46
      
47
    case UART_BUFFER_OVERFLOW:{
48
      uart_puts("UART_BUFFER_OVERFLOW\n");
49
    };break;
50
51
    case UART_OVERRUN_ERROR:{
52
      uart_puts("UART_OVERRUN_ERROR\n");
53
    };break;
54
55
    case UART_FRAME_ERROR:{
56
      uart_puts("UART_FRAME_ERROR\n");
57
    };break;
58
59
    default:{
60
      uart_puts("UART_UNKNOWN_ERROR\n");
61
    };break;
62
63
    }
64
      }
65
66
67
      if(newUartData > 0){
68
  
69
  snprintf(uart_buffer_write,32,"received : %s\n",uart_buffer_read);      
70
  uart_puts(uart_buffer_write);
71
      
72
  if (!strncmp_P(uart_buffer_read, loadDATA,8)){
73
    // daten holen vom Ende zum Amfang
74
    // letzte Daten zuerst
75
    uart_puts("if loadDATA\n");
76
77
78
  } else if(!strncmp_P(uart_buffer_read, nextDATA,8)){
79
    // naechste Daten holen
80
    uart_puts("if nextDATA\n");
81
82
83
  } else {
84
    // receive wrong string 
85
    // send something to the PC
86
    uart_puts("unknown Command\n");
87
88
  }
89
  
90
  newUartData = 0;
91
  uartActive = 0;
92
93
      }// end of newUartData
94
95
...
96
97
    }
98
...
99
100
}

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

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.