Wie implementier ich einen FIFO Buffer in C? Hat jemand ein Beispiel dazu? Thx
Du legst ein Array vom Typ der zu speichernden Daten an. Du definierst zwei Zeiger. Einen für die Stelle, an die du Daten schreibst, einen für die Stelle, wo du die Daten wieder ausliest. Nach jeder Schreib- oder Leseoperation erhöhst du den jeweiligen Zeiger. Wenn ein Zeiger über das Ende des Arrays hinausgeht, setzt du ihn wieder auf Null. Soweit das mal ganz grob umrissen.
Klaus wrote: > Wie implementier ich einen FIFO Buffer in C? Hat jemand ein Beispiel > dazu? Ja. Beitrag "LCD über nur einen IO-Pin ansteuern" Anhang im 12. Beitrag. Peter
Source Schnippsel: //////////////////////////////////// #define CON_OUT_BUF_SIZE 64 /* Buffer masks */ #define CON_OUT_MASK (CON_OUT_BUF_SIZE-1ul) /* Buffer read / write macros */ #define CON_BUF_RESET(Fifo) (Fifo->rd_idx = Fifo->wr_idx = 0) #define CON_BUF_WR(Fifo, dataIn) (Fifo->data[CON_OUT_MASK & Fifo->wr_idx++] = (dataIn)) #define CON_BUF_RD(Fifo) (Fifo->data[CON_OUT_MASK & Fifo->rd_idx++]) #define CON_BUF_EMPTY(Fifo) ((CON_OUT_MASK & Fifo->rd_idx) == (CON_OUT_MASK & Fifo->wr_idx)) #define CON_BUF_FULL(Fifo) ((CON_OUT_MASK & Fifo->rd_idx) == (CON_OUT_MASK & Fifo->wr_idx+1)) #define CON_BUF_COUNT(Fifo) ((CON_OUT_MASK & Fifo.wr_idx) - (CON_OUT_MASK & Fifo.rd_idx)) // Serial output buffer typedef struct { unsigned char data[CON_OUT_BUF_SIZE]; unsigned int wr_idx; unsigned int rd_idx; } CON_Fifo_t;
Vielleicht sollte man noch dazu schreiben, dass CON_OUT_BUF_SIZE zwingend eine Zweierpotenz sein muss. > #define CON_BUF_COUNT(Fifo) ((CON_OUT_MASK & Fifo.wr_idx) - > (CON_OUT_MASK & Fifo.rd_idx)) Und wenn wr_idx < rd_idx ist?
Klaus wrote:
> Wo werden denn hier die Pointer definiert? Welches ist der Pointer?
Wozu brauchst du einen Pointer?
Andread arbeitet auf einem ganz normalen Array und nimmt
Inidizes um in das Array zuzugreifen.
Ist doch völlig ausreichend.
Stefan Ernst wrote: > Vielleicht sollte man noch dazu schreiben, dass CON_OUT_BUF_SIZE > zwingend eine Zweierpotenz sein muss. Ja.
1 | #if((CON_OUT_BUF_SIZE|CON_OUT_MASK) != (CON_OUT_BUF_SIZE+CON_OUT_MASK))
|
2 | #error bad CON_OUT_BUF_SIZE !!!
|
3 | #endif
|
Peter
Hi >Du legst ein Array vom Typ der zu speichernden Daten an. >Du definierst zwei Zeiger. Einen für die Stelle, an die du >Daten schreibst, einen für die Stelle, wo du die Daten wieder ausliest. >Nach jeder Schreib- oder Leseoperation erhöhst du den jeweiligen... Das ist ein Ringpuffer und kein FIFO. Da reicht ein Zeiger, der nach dem Schreiben um 1 erhöht und vor dem Lesen um 1 erniedrigt wird. MfG Spess
> Das ist ein Ringpuffer und kein FIFO. Da reicht ein Zeiger, der nach dem > Schreiben um 1 erhöht und vor dem Lesen um 1 erniedrigt wird. Ein Ringpuffer ist ein FIFO. Deins ist ein Stack, oder auch LIFO.
Ich hab das mal mit Maske probiert, spart tatsächlich einige Bytes Code. Blöd ist nur, daß auch der SRAM in 2-er Potenzen organisiert ist. Wenn ich also nen Puffer beim ATtiny45 einrichte und 18 Byte für Stack und Variablen reserviere, kann ich nur 64 Byte Puffer einrichten. Ich bleibe daher beim Vergleichen und 0 setzen, dann kann ich sogar 110 Byte Puffer nehmen, also fast das doppelte! Peter
> #define CON_BUF_COUNT(Fifo) ((CON_OUT_MASK & Fifo.wr_idx) - > (CON_OUT_MASK & Fifo.rd_idx)) So funktioniert es auch wenn wr_idx < rd_idx ist: #define CON_BUF_COUNT(Fifo) ((Fifo.wr_idx - Fifo.rd_idx) & CON_OUT_MASK)
seit Jahren verwende ich immer das hier: http://www.roboternetz.de/wissen/index.php/FIFO_mit_avr-gcc
Man könnte ja anstatt CON_OUT_MASK & Fifo->wr_idx++ auch (Fifo->wr_idx++) % CON_OUT_BUF_SIZE verwenden und hätte damit das Problem der auf Zweierpotenzen eingeschränkten Puffergröße umgangen. Sollte auch nicht mehr Platz im .text Segment brauchen und auch nicht langsamer sein. Viele Grüße, Martin L.
^ Ich denke schon das eine 16Bit Division sowohl größer als auch langsamer ist als ein 'logical and'.
Ist ja nur ein 8-Bit Modulo notwendig. Aber stimmt - der Atmel hat keinen "mod"-Befehl. (Übrigens brauchen bessere Prozessoren bei 16 oder 32bit Berechnungen deren höherwertigen Bits null sind nicht länger als mit entsprechend kleineren Registern.) Viele Grüße, Martin L.
Nur wenige Controller haben einen div- oder mod Befehl. Mir fällt da nur der Cortex M3 ein. Das traurige am C Standard ist das solche Berechnungen immer mit mindestens 16Bit durchgeführt werden. Vielleicht optimiert der AVR-GCC das in diesem Fall und rechnet tatsächlich nur mit 8 Bits. Bei einer Multiplikation macht er das jedenfalls nicht. Da werden 8Bit Operanden auf 16Bit aufgebohrt und das Ergebnis wieder auf 8Bit zurückgestutzt. >(Übrigens brauchen bessere Prozessoren bei 16 oder >32bit Berechnungen deren höherwertigen Bits null sind nicht länger als >mit entsprechend kleineren Registern.) Ich nehme an du meinst 16/32 Bit Prozessoren? Interessanterweise dauert es auf solchen Prozessoren mitunter sogar länger wenn mit kleinen Datentypen gerechnet werden soll. Da werden nämlich Ergebnisse die ja in z.B. 32Bit Registern stehen erst mit Masken verknüpft um die oberen Bits auszublenden. Deshalb gibt es in der <stdint.h> die 'fast' Typen. Also z.B. uint_fast8_t der bei einem ARM7 als 'unsigned long' definiert ist. Ergo: Die kleinsten Datentypen sind nicht immer die Besten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.