Forum: Mikrocontroller und Digitale Elektronik brauche Hilfe bei Erweiterungen von Fifo-Funktionalitäten


von Anfänger (Gast)


Lesenswert?

Hi,

ich bin hier auf einen megacoolen Fifo gestossen:

Quelle: 
http://www.mikrocontroller.net/articles/FIFO#FIFO_mit_C-Pr.C3.A4prozessor
1
#define BUFFER_SIZE 16 // muss 2^n betragen (8, 16, 32, 64 ...)
2
#define BUFFER_MASK (BUFFER_SIZE-1) // Klammern auf keinen Fall vergessen
3
 
4
struct Buffer {
5
  uint8_t data[BUFFER_SIZE];
6
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
7
  uint8_t write; // zeigt immer auf leeres Feld
8
} buffer = {{}, 0, 0};
9
 
10
uint8_t BufferIn(uint8_t byte)
11
{
12
  uint8_t next = ((buffer.write + 1) & BUFFER_MASK);
13
  if (buffer.read == next)
14
    return FAIL;
15
  buffer.data[buffer.write] = byte;
16
  // buffer.data[buffer.write & BUFFER_MASK] = byte; // absolut Sicher
17
  buffer.write = next;
18
  return SUCCESS;
19
}
20
 
21
uint8_t BufferOut(uint8_t *pByte)
22
{
23
  if (buffer.read == buffer.write)
24
    return FAIL;
25
  *pByte = buffer.data[buffer.read];
26
  buffer.read = (buffer.read+1) & BUFFER_MASK;
27
  return SUCCESS;
28
}

Ich möchte gerne noch zwei Funktionalitäten dazu haben - Fifo leeren und 
Anzahl Elemente im Fifo ausrechnen.

Dazu habe ich mir folgendes ausgedacht:
1
void BufferClear()
2
{
3
    buffer.read = buffer.write = 0;
4
}
5
6
uint8_t BufferAnzahl()
7
{
8
    int16_t hilf;
9
    hilf = buffer.write-buffer.read;
10
    
11
    // keine Werte vorhanden:
12
    if (hilf=0) {
13
        return (0);
14
     }
15
    
16
    // hilf > 0
17
    if (hilf>0) {
18
       return (hilf);
19
    }
20
    
21
    if (hilf<0) {
22
        return (BUFFER_SIZE-hilf);
23
    }
24
}

Bei der clear-Funktion braucht man glaub ich nicht weiter diskutieren - 
so ist sie auf alle Fälle leer. Aber bei der Ermittlung der Anzahl der 
Elemente in dem Fifo bin ich mir unsicher. Ist die Lösung so brauchbar 
mit den drei if-Abfragen - oder gibt es eine einfachere Variante? Ich 
habe die Hilfsvariable extra als int-Variable genommen, die doppelt so 
groß ist, wie die uint8_t-Variable, damit beim Subtrahieren auch ein 
negativer Wert funktioniert. Meint ihr, das das so funktioniert, was ich 
mir ausgedacht hab?

von gonso (Gast)


Lesenswert?

Das sieht schon mal brauchbar aus. Aber die Kommentare wie // hilf > 0 
sind total überflüssig.

Nach jedem return fehlt noch ein break, damit die Funktion vorzeitig 
beendet wird.

von Max H. (hartl192)


Lesenswert?

Anfänger schrieb:
> oder gibt es eine einfachere Variante?
1
uint8_t BufferAnzahl()
2
{
3
  return (buffer.write - buffer.read) & (BUFFER_SIZE - 1);
4
}
BUFFER_SIZE muss eine Zweierpotenz mit ganzzahlige Exponenten sein.

gonso schrieb:
> Nach jedem return fehlt noch ein break, damit die Funktion vorzeitig
> beendet wird.
Die Funktion wird durch das return beendet.

von chris (Gast)


Lesenswert?

Anfänger schrieb:
> if (hilf=0)

das geht schief.
1
if (hilf == 0)

gonso schrieb:
> Nach jedem return fehlt noch ein break, damit die Funktion vorzeitig
> beendet wird.

Und das ist Käse. 'return' beendet die Funktion

von Anfänger (Gast)


Lesenswert?

Ich finds total lieb von Euch, dass Ihr Euch meinen Quellcodeentwurf 
angeschaut und verbessert habt.

Vielen Dank :-)

von Max H. (hartl192)


Lesenswert?

Anfänger schrieb:
> if (hilf<0) {
>         return (BUFFER_SIZE-hilf);
>     }
Das get auch schief: Wenn hilf negativ ist, dann ist BUFFER_SIZE-hilf 
größer als BUFFER_SIZE, z.B. 128 - -6 = 134.

BTW: return ist keine Funktion, die Klammen sind also nicht notwendig.

von Anfänger (Gast)


Lesenswert?

Max H. schrieb:
> Das get auch schief: Wenn hilf negativ ist, dann ist BUFFER_SIZE-hilf
> größer als BUFFER_SIZE, z.B. 128 - -6 = 134.

uupps :-), naja, darum bin ich ja noch ein Anfänger und kein 
Fortgeschrittener bzw. Profi, so wie Du. Mir wäre das wahrscheinlich nie 
aufgefallen und ich hätte mich gewundert, warum ich Blödsinn rausbekomme 
:-)

von Anfänger (Gast)


Lesenswert?

Guten Morgen!

Aus dem Quellcode würde ich gerne noch die letzte Zeile hier aus dem 
Abschnitt verstehen:
1
struct Buffer {
2
  uint8_t data[BUFFER_SIZE];
3
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
4
  uint8_t write; // zeigt immer auf leeres Feld
5
} buffer = {{}, 0, 0};

buffer = {{}, 0, 0}

Ich bin mir über die Verwendung der geschweiften Klammern noch im 
Unklaren. Die beiden Nullen dort sind sicherlich als Initialwerte für 
read und write zu verstehen. Mit {} - ist damit gemeint, dass das Array 
data[BUFFER_SIZE] leer sein soll?

Warum kann ich dort überhaupt geschweifte Klammern benutzen? Sorry, wenn 
meine Frage vielleicht trivial ist - aber ich habe in meinem 
C-Anfängerbuch nachgeschaut und noch nicht herausgefunden, warum man 
sagen kann buffer={...}. Ich hab bisher immer gedacht, dass die 
geschweiften Klammern dazu da sind, Funktionsblöcke einzugrenzen.

von Max H. (hartl192)


Lesenswert?

Anfänger schrieb:
> Mit {} - ist damit gemeint, dass das Array
> data[BUFFER_SIZE] leer sein soll?
Es wird mit 0 initialisiert.

> warum man sagen kann buffer={...}.
Das ist laut C-Standard einfach so.
> Ich hab bisher immer gedacht, dass die geschweiften Klammern
> dazu da sind, Funktionsblöcke einzugrenzen.
Wie du gesehen hast nicht ausschließlich.

von Peter D. (peda)


Lesenswert?

Nicht zu alte Compiler kennen auch eine namentliche Initialisierung:
1
struct Buffer buffer = { .read = 0, .write = 0 };

von Anfänger (Gast)


Lesenswert?

cool, danke für Eure Hilfe.

Ich hab jetzt mal versucht, das C-Programm in eine Klassenstruktur 
umzuwandeln (Headerdatei und cpp-Datei sind jetzt hier in dem 
Codeschnippsel zusammen):

1
// Headerdatei
2
3
class Buffer {
4
 public:
5
    uint8_t BufferIn  (uint16_t element);
6
    uint8_t BufferOut (* element);
7
    void BufferClear ();
8
    uint32_t BufferAnzahl ();
9
 
10
 private:
11
    uint16_t data[];
12
    uint16_t read;
13
    uint16_t write;
14
};
15
16
// cpp-Datei
17
18
uint8_t Buffer::Buffer(uint16_t size) {
19
    if (size%2 != 0) { 
20
         return ERROR;
21
    }
22
    else {
23
         read = 0;
24
         write = 0;
25
         data = date[size];
26
         return !ERROR;
27
    }
28
}
29
 
30
uint8_t Buffer::BufferIn(uint8_t byte) {
31
  uint8_t next = ((buffer.write + 1) & BUFFER_MASK);
32
  if (buffer.read == next)
33
    return FAIL;
34
  buffer.data[buffer.write] = byte;
35
  // buffer.data[buffer.write & BUFFER_MASK] = byte; // absolut Sicher
36
  buffer.write = next;
37
  return SUCCESS;
38
  int a= ERROR;
39
}
40
 
41
uint8_t Buffer::BufferOut(uint8_t *pByte) {
42
  if (buffer.read == buffer.write)
43
    return FAIL;
44
  *pByte = buffer.data[buffer.read];
45
  buffer.read = (buffer.read+1) & BUFFER_MASK;
46
  return SUCCESS;
47
}
48
49
void Buffer::BufferClear()
50
{
51
    buffer.read = buffer.write = 0;
52
}
53
54
uint8_t Buffer::BufferAnzahl()
55
{
56
    return (buffer.write - buffer.read) & (BUFFER_SIZE - 1);
57
}

Später würde ich in meinem Programm das so aufrufen:
1
 if ( (Buffer meinbuffer(1024)) != SUCCESS) 
2
    { ... Fehler beim Initialisieren des Buffers ...}
Ich bin mir aber nicht sicher, ob im Konstruktor die Zuweisung der 
Arraygröße funktioniert:
1
 data = date[size];

Könnt ihr mir da vielleicht nochmal ein paar Tipps geben? Kann ich 
überhaupt im Konstruktor eine return-Anweisung machen?

von Anfänger (Gast)


Lesenswert?

Könnte ich eigentlich auch mit dem Präprozessor abfangen, dass der 
Initialwert ein Vielfaches von 2 ist?

Das wäre grad meine Idee:
1
void Buffer::Buffer(uint16_t size) {
2
#if ((size%2) != 0)
3
#error BUFFER-SIZE kein Vielfaches von 2
4
#endif
5
         read = 0;
6
         write = 0;
7
         data = date[size];
8
9
}

von Max H. (hartl192)


Lesenswert?

Nein, die Präprozessor Anweisungen funktionieren nur mit Konstanten. 
Dann müsstest du 'size' mit einem #define machen.

von Anfänger (Gast)


Lesenswert?

Max H. schrieb:
> Nein, die Präprozessor Anweisungen funktionieren nur mit Konstanten.
> Dann müsstest du 'size' mit einem #define machen

ok, danke. Ich brauche in meinem Programm zwei Buffers mit 
unterschiedlichen Größen und wollte gerne die Größe variabel erzeugen 
können - auch für später mal, wenn ich wieder mal nen Buffer brauche.

Aber das hier würde gehen?
1
uint8_t Buffer::Buffer(uint16_t size) {
2
    if (size%2 != 0) { 
3
         return ERROR;
4
    }
5
    else {
6
         read = 0;
7
         write = 0;
8
         data = date[size];
9
         return !ERROR;
10
    }
11
}

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.