Forum: Mikrocontroller und Digitale Elektronik Eigenbau-Ringbuffer: Holy oder Crap?


von Stephan (Gast)


Lesenswert?

Hallo!

Nebenstehend mein UART-Ringbuffer, mit dem ich zu verhindern versuche, 
dass bei rascher Folge zweier Stringzeilen die eine während der 
Bearbeitung der vorherigen verlorengeht.
-die ISR schreibt stets das neu angekommene Zeichen hinter das letzte 
Zeichen des UART-Strings
-die Ausleseschleife nimmt immer wieder das erste Zeichen des 
UART-Strings, kopiert es in den neuen Nutzstring und verschiebt den 
gesamten UART-String um eine Stelle nach vorn, solange, bis ein \r das 
Ende einer Stringzeile anzeigt.
1
char nutzstring[100];
2
3
void ausleseschleife(void)
4
{
5
int i;
6
int stelle;
7
8
while (uart1_str_count != 0 && stringfertig == 0)
9
{      
10
  nutzstring[stelle] = uart1_string[0]; 
11
    
12
  for ( i=0;i<=100;i++)
13
  {
14
    uart1_string[i] = uart1_string[i+1];
15
  }
16
  if (nutzstring[stelle] == '\r')
17
  {
18
    nutzstring[stelle] = '\0';
19
    stringfertig = 1;
20
  }
21
  uart1_str_count--;
22
  stelle++;
23
}  
24
25
}
26
27
ISR (USART1_RX_vect)    
28
{
29
unsigned char nextChar;
30
nextChar = UDR0;
31
  if (nextChar != '\n')
32
  {
33
    uart1_string[uart1_str_count] = nextChar;  
34
    uart1_str_count++;
35
  }
36
}
Es klappt wunderbar- nur übersehe ich vllt irgendwas?

von Eddy C. (chrisi)


Lesenswert?

>Es klappt wunderbar-

So what?

>nur übersehe ich vllt irgendwas?

Was würdest Du denn gerne übersehen?

Heidernei, einen Ringpuffer baut man nicht, indem man die Daten im Kreis 
kopiert, sondern einen Lese- und einen Schreibzeiger implementiert, 
welche am Pufferende auf Pufferanfang zurück gestellt werden. So ist es 
definitiv Crap :-) Sieht irgendwie nach einer Mischung aus Stack und 
FIFO aus, gewürzt mit memcpy...

von Simon K. (simon) Benutzerseite


Lesenswert?

Das was du gepostet hast, ist "crap". Das lässt sich nicht mal 
kompilieren.

Auf die Schnelle sehe ich aber auch nicht, wo da jetzt der Ringbuffer 
ist.

Eine entsprechende Abstraktion des Puffers fehlt auch. Schon mal 
vorhandene Ringbuffer-Implementierungen angeschaut, wie es dort gemacht 
wird?

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

Übelster Crap. Meine Augen schmerzen immer noch...

von Uwe (de0508)


Lesenswert?

Hallo,

ich sehe da keinen UART-Ringbuffer !

Man hat immer einen Schreib- und einen Lesezeiger.

In einer einfachen Abbildung des Ringbuffer ist dieser leer, wenn 
(Schreibzeiger == Lesezeiger) ist.

Dem Zufolge ist der Ringbuffer voll, wenn (UEBERLAUF(Schreibzeiger, 
RINGBUFFER_SIZE) == Lesezeiger) ist.

Hier noch die Definition des Macros:
1
#define UEBERLAUF( x, max )  x = ++x >= max ? 0 : x

Man benötigt also drei Funktionen:
a) ist ein Zeichen im Ringpuffer ? (Hauptprogramm)
b) Lese ein Zeichen aus dem Ringpuffer. (Hauptprogramm)
c) Schreibe ein Zeichen in den Ringpuffer, das macht dann die ISR.

---

Dein Code ist nicht vollständig, da
1
uart1_string[]
 nirgendwo definiert ist!

Ich würde ihn als
1
#define RINGBUFFER_SIZE 32
2
volatile char uart1_string[RINGBUFFER_SIZE];
anlegen.

Stephan schrieb:
> ISR (USART1_RX_vect)
> {
> unsigned char nextChar;
> nextChar = UDR0;
>   if (nextChar != '\n')
>   {
>     uart1_string[uart1_str_count] = nextChar;
>     uart1_str_count++;
>   }
> }


Link

Hier findet man solch einen Ringpuffer:

[1] Beitrag "Software UART mit FIFO"

von Eddy C. (chrisi)


Lesenswert?

Also hier mal eine Version, die das macht das Du evtl. wolltest:

1
#define BUFSIZE  80
2
volatile int Put = 0;
3
volatile int Get = 0;
4
char Buffer[BUFSIZE];
5
6
ISR (USART1_RX_vect)    
7
{
8
    Buffer[Put++] = UDR0;
9
    if (Put == BUFSIZE)
10
        Put = 0;
11
}
12
13
char ReadChar(void)
14
{
15
    // Wait for a character
16
    while (Put == Get)
17
        ;
18
    // Read it from the holy buffer
19
    char Char = Buffer[Get++];
20
    if (Get == BUFSIZE)
21
        Get = 0;
22
}
23
24
void ReadString(char *String)
25
{
26
    while (1)
27
    {
28
        char Char = ReadChar();
29
        if (Char == '\n')
30
            break;
31
        *String++ = Char;
32
    }
33
    // Terminate string
34
    *String = 0;
35
}

von Simon K. (simon) Benutzerseite


Lesenswert?

@Eddy Current: Bei dir fehlt aber schon mal die Abfrage, ob der Puffer 
voll ist :-)

EDIT: Vergiss es, das ist ja gar kein Ringbuffer (hast du aber auch 
nicht behauptet).

EDIT2: Aber so richtig was sinnvolles scheint mir das auch nicht zu 
sein. Das Stückchen Code erzeugt eine gefährliche 
speichervollschreibende Endlosschleife, wenn kein '\n' im Buffer steht.

Baaad baad programming! Ganz ganz übel.

von Eddy C. (chrisi)


Lesenswert?

Simon: Das ist ein Ringpuffer. Ich wollte nicht das Funktionsprinzip 
durch Fehlerbehandlung oder schlaue Makros verbergen. Eine verbesserte 
Version von ReadString wäre:

1
void ReadString(char *String,int MaxLen)
2
{
3
    int Len = 0;
4
    while (1)
5
    {
6
        char Char = ReadChar();
7
        if (Char == '\n')
8
            break;
9
        if (Len < MaxLen)
10
            String[Len++] = Char;
11
    }
12
    // Terminate string
13
    String[Len] = 0;
14
}

von Stephan (Gast)


Lesenswert?

Okay, verstanden. Vielen dank! Bildlich gefiel mir meine Vorstellung 
eines Ringbuffers aber besser.
Und, wohlgemerkt, er funktioniert tadellos!
Werd trotzdem weiter in Richtung etabliertem Ringbuffer arbeiten.

von Stephan (Gast)


Lesenswert?

Hallo!
Ich versuche nun den den FIFO- Ringbuffer aus dem Artikel 
http://www.mikrocontroller.net/articles/FIFO
zu verwenden.

#define BUFFER_SIZE 16 // muss 2^n betragen (8, 16, 32, 64 ...)
#define BUFFER_MASK (BUFFER_SIZE-1) // Klammern auf keinen Fall 
vergessen

struct Buffer {
  uint8_t data[BUFFER_SIZE];
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
  uint8_t write; // zeigt immer auf leeres Feld
} buffer = {{}, 0, 0};

uint8_t BufferIn(uint8_t byte)
{
  uint8_t next = ((buffer.write + 1) & BUFFER_MASK);
  if (buffer.read == next)
    return FAIL;
  buffer.data[buffer.write] = byte;
  // buffer.data[buffer.write & BUFFER_MASK] = byte; // absolut Sicher
  buffer.write = next;
  return SUCCESS;
}

uint8_t BufferOut(uint8_t *pByte)
{
  if (buffer.read == buffer.write)
    return FAIL;
  *pByte = buffer.data[buffer.read];
  buffer.read = (buffer.read+1) & BUFFER_MASK;
  return SUCCESS;
}

Immerzu kommt die Fehlermeldung, er erwarte ,/;/oder attributes vor 
BufferOut oder BufferIn. Ich vermute nicht, dass der Fehler im Code 
liegt, wohl eher in einer meiner Header- Dateien- weiß wer Rat?

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.