Forum: Projekte & Code Konzept für einen Ringpuffer


von Sebastian Koschmieder (Gast)


Angehängte Dateien:

Lesenswert?

Hey,
ich habe hier mal versucht einen Ringpuffer in C zu implementieren. Ist 
jedoch noch nicht auf ein µC angepasst, sondern zur Zeit läuft es noch 
normal im PC. Der eeprom wird durch ein Array simuliert. Der Vorteil 
hier ist, dass ich innerhalb der Speicherseiten mit Adressen arbeiten 
kann. Würde mich freuen, wenn ihr da mal kurz rüber gucken könntet um 
vlt Fehler in meiner Logik zu finden oder um Verbesserungsvorschläge zu 
machen.
Ich danke euch zumindest schon mal, für eure Mühe! ;)
mfg
Sebastian

von Sven P. (Gast)


Lesenswert?

Prima Idee, Kritik:

- Kommentare in C gehen /* .. */ und nicht //.. ('//' kommt in C99 dazu, 
das unterstützt nicht jeder).
- Auf einem AVR mit AVR-GCC/avr-libc gibt man dem Array die 
Speicherklasse 'eeprom' mit, muss dann aber mit eeprom_read_x und 
eeprom_write_x arbeiten, einfaches Zuweisen/Lesen funktioniert nicht.
- Es ist ratsam, statt 'short' und 'int' und 'char' die Typen aus 
<stdint.h> zu benutzen, die haben eine genaue Breite und ein eindeutiges 
Vorzeichen (ja, ein char ist nicht immer unsigned oder signed, und ja, 
ein int ist nicht immer 32 Bit breit und ein short muss nicht 
zwangsläufig kleiner als ein int sein).
- Rückgabewert für 'Erfolgreich' ist in der Libc meistens '0', im 
Fehlerfall ein Wert größer 0, daran solltest du dich auch halten.
- '%' und '/' ist richtig schön lahm, wenns sich irgendwie umgehen 
ließe... :-)
- Je nach Compiler würde ich 'tmp >> 7' (am Ende von EEPROM_writeBlock) 
durch ein if ersetzen, guck da mal ins ASM-Listing, inwieweit das schon 
optimiert ist.

von Benedikt K. (benedikt)


Lesenswert?

Sven P. wrote:

> - Kommentare in C gehen /* .. */ und nicht //.. ('//' kommt in C99 dazu,
> das unterstützt nicht jeder).

Naja. Wir haben das Jahr 2009, C99 ist schon 10 Jahre alt. Kein ernst 
zunehmender Compiler unterstützt die Kommentare mit // nicht.

> - '%' und '/' ist richtig schön lahm, wenns sich irgendwie umgehen
> ließe... :-)

Ein guter Compiler optimiert das automatisch zu entsprechenden UND 
Verknüpfungen, wenn es möglich ist. Wenn man das direkt mit & schreibt, 
ist man auf 2er Potenzen beschränkt.

von Norgan (Gast)


Lesenswert?

> - Kommentare in C gehen /* .. */ und nicht //.. ('//' kommt in C99 dazu,
> das unterstützt nicht jeder).
...
> - Es ist ratsam, statt 'short' und 'int' und 'char' die Typen aus
> <stdint.h> zu benutzen, die haben eine genaue Breite und ein eindeutiges
> Vorzeichen

Wer stdint.h nimmt, kann auch // als Kommentar nehmen. stdint.h ist 
nämlich ebenfalls ein C99-Feature.

> - Rückgabewert für 'Erfolgreich' ist in der Libc meistens '0', im
> Fehlerfall ein Wert größer 0, daran solltest du dich auch halten.

Oder bei den meisten Systemfunktionen ein Wert kleiner 0 im Fehlerfall 
(meist -1). Anders ausgedrückt, das geht bei C so durcheinander, dass es 
völlig egal ist was man selber nimmt. Bei mehreren möglichen 
Rückgabewerten empfiehlt es sich diese als Konstanten (#define oder 
enum) mit aussagekräftigen Namen zu definieren

> - '%' und '/' ist richtig schön lahm, wenns sich irgendwie umgehen
> ließe... :-)

Lässt sich umgehen wenn wenn der Divisor eine Zweierpotenz ist und man 
nur mit unsigned rechnet.

> - Je nach Compiler würde ich 'tmp >> 7' (am Ende von EEPROM_writeBlock)
> durch ein if ersetzen, guck da mal ins ASM-Listing, inwieweit das schon
> optimiert ist.

Mikrooptimierung, die in der praktischen Anwendung vermutlich kaum etwas 
bringt.

von Simon K. (simon) Benutzerseite


Lesenswert?

-Falsche Forumskategorie.

von sebastian@koschis-web.de (Gast)


Angehängte Dateien:

Lesenswert?

Hey, danke für die Tipps, ich werd sie umsetzen, sobald ich das kleine 
Prog auf dem µC umsetze...
ich hab nun nochmal ein paar kleine Fehler ausgemerzt... also, hier 
nochmal der neue Code...

von Stefan N. (nollsen)


Lesenswert?

hi,

generell würde ich sagen ist etwas viel code für nen ringpuffer.

du solltest versuchen das ganze etwas mikrocontroller optimiert zu 
schreiben.

% und * gehen eigentlich gar nicht.
das * 8 kann der compiler sicher noch durch ein linksshiften ersetzen. 
für das modulo allerdings bastelt dir dein compiler extrafunktionen.. 
...


hier ist mal etwas code für nen einfachen ringpuffer, der ohne 
irgendwleche modulos auskommt:
1
struct DataBuffer
2
{
3
  uchar Data[256];
4
  uchar WritePos;
5
  uchar ReadPos;
6
7
} ;
8
9
struct DataBuffer UART_Send;
10
struct DataBuffer UART_Recieve;
11
12
13
void Buffer_AddChars(struct DataBuffer* pDataBuffer, char* data, uchar len)
14
{
15
  while(len--)
16
  {
17
    pDataBuffer->Data[pDataBuffer->WritePos] = *data++;;
18
    pDataBuffer->WritePos++; 
19
    if(pDataBuffer->ReadPos == pDataBuffer->WritePos) 
20
      pDataBuffer->Data[pDataBuffer->WritePos] = '.';
21
  }
22
}
23
24
uchar Buffer_ReadChars(struct DataBuffer* pDataBuffer, uchar* data, uchar len)
25
{
26
  uchar c=0;
27
  while(len--)
28
  {
29
    if(pDataBuffer->ReadPos == pDataBuffer->WritePos) return c;
30
    *data++ = pDataBuffer->Data[pDataBuffer->ReadPos];
31
    c++;
32
    pDataBuffer->ReadPos++; 
33
  }
34
  return c;
35
}

von Simon K. (simon) Benutzerseite


Lesenswert?

Modulo 2^N ergibt ein einfaches logisches AND 2^N-1.

von hans dampf (Gast)


Lesenswert?

@ nollsen:

kannst du mir mal bissl was zu deinem code erklären?

1.: was ist ein uchar?
2.: pDataBuffer->Data[pDataBuffer->WritePos] = *data++;; ??????
2.1: der operator: "->"
2.2: das dingen am ende: *data++;;

würd mir glaub ich schon massiv weiterhelfen das zu verstehn.

gruß hans

von zzz (Gast)


Lesenswert?

Der Ringpuffer von Stefan Noll funktioniert nicht.
Wo wird pDataBuffer->WritePos auf 0 zurückgesetzt?!?
Wo wird pDataBuffer->ReadPos auf 0 zurückgesetzt?!?

Was passiert, wenn pDataBuffer->WritePos=254 ist und noch zwei Zeichen
in den Puffer geschrieben werden?!?

Ich sehe keine Ring-Implementierung, nur irgendwas, das abstürzt,
nachdem 256 Zeichen reingeschrieben wurden - zzz.

von Karl H. (kbuchegg)


Lesenswert?

zzz schrieb:
> Ich sehe keine Ring-Implementierung, nur irgendwas, das abstürzt,

Ich sehe einen Poster der C lernen sollte, ehe er anderer Leute Code 
zerpflückt.

Mit dem Code ist alles in Ordnung, wenn man eine übliche und auch 
naheliegende Definition zu Grunde legt
1
typedef unsigned char uchar;

von Karl H. (kbuchegg)


Lesenswert?

hans dampf schrieb:
> @ nollsen:
>
> kannst du mir mal bissl was zu deinem code erklären?
>
> 1.: was ist ein uchar?
1
typedef unsigned char uchar;

> 2.: pDataBuffer->Data[pDataBuffer->WritePos] = *data++;; ??????
> 2.1: der operator: "->"
> 2.2: das dingen am ende: *data++;;
>
> würd mir glaub ich schon massiv weiterhelfen das zu verstehn.

Massiv weiterhelfen würde dir ein C-Buch.
Das sind alles Grundlagen, in jedem C-Buch auf mindestens 40 Seiten 
durchgekaut.

von Stefan N. (nollsen)


Lesenswert?

lustig dass der beitrag immer noch aktiv ist :)

als erstes mal bitte die beschreibung durchlesen:

"hier ist mal etwas code für nen einfachen ringpuffer, der ohne
irgendwleche modulos auskommt:"

das zurücksetzen auf 0 ist einfach nicht notwendig, weil die 
adressvariable einfach überläuft und von 0 startet.

die anderen fragen -> einfach mal ein C buch lesen und das kapitel 
"pointer" aufschlagen.

der ringpuffer ist übrigens darauf hin optimiert, dass das 
hineinschreiben in den puffer immer möglich ist. wenn der puffer 
überläuft, werden . - zeichen hineingeschrieben um den überlauf zu 
zeigen. das kann je nach anwendung dann angepasst werden, aber passt auf 
deinen uart puffer recht gut. eine interrupt routine kann nicht warten, 
bis der puffer wieder leergelesen wurde.

von zzz (Gast)


Lesenswert?

@Karl heinz Buchegger

>Mit dem Code ist alles in Ordnung, wenn [...]
ja wenn... und wenn nicht? Portierbarkeit? Wartbarkeit?
Ich sehe einen Poster der irgendwo in den 90ern beim Bitfrickeln 
stehengeblieben ist.

von Karl H. (kbuchegg)


Lesenswert?

zzz schrieb:
> @Karl heinz Buchegger
>
>>Mit dem Code ist alles in Ordnung, wenn [...]
> ja wenn... und wenn nicht?

Dann fragt man nach was er sich für einen uchar so vorgestellt hat, wenn 
man schon nicht in der Lage ist, das aus der Verwendung der Variablen zu 
ersehen und ballert da nicht ungerechtferigte Vorwürfe durch den Raum.

> Portierbarkeit?

Voll portierbar

> Wartbarkeit?

Voll wartbar, da nicht notwendig. Der Ringbuffer ist auf 256 Zeichen 
ausgelegt und dafür ist der Code geschrieben.
Im Übrigen war von Wartbarkeit überhaupt nicht die Rede. Deine 
Ankündigung war, dass der Code, wie gepostet, abstürzt.

> Ich sehe einen Poster der irgendwo in den 90ern beim Bitfrickeln
> stehengeblieben ist.

Ich sehe einen Poster der vollmundig einen Fehler gemacht hat und zu 
feig ist den auch zuzugeben. Statt dessen schaltet er jetzt in den 
Politkermodus und versucht sich rauszureden. Und von Bitfrickeln kann 
schon überhaupt keine Rede sein. Lerne C und was es dir für das 
Verhalten von bestimmten Datentypen für Zusagen macht.

von zzz (Gast)


Lesenswert?

@Karl heinz Buchegger
Ist das wartbar, wenn ich den Ringpuffer auf 1024 Zeichen erhöhen möchte
und dafür die Zählvariablen im ganzen Algorithmus umtypen muss???

manchmal frag ich mich echt...

von Karl H. (kbuchegg)


Lesenswert?

zzz schrieb:
> @Karl heinz Buchegger
> Ist das wartbar, wenn ich den Ringpuffer auf 1024 Zeichen erhöhen möchte
> und dafür die Zählvariablen im ganzen Algorithmus umtypen muss???
>
> manchmal frag ich mich echt...

Davon ist in dem ganzen Code nicht die Rede.
Dieser Ringbuffer ist für 256 Zeichen ausgelegt. Unter anderem auch 
daran erkennbar, dass es kein #define für die Arraygröße gibt und die 
Größe der Indexvariablen nur 1 Byte ist (was zb auf einem AVR durchaus 
gute Gründe haben kann)

Und im übrigen war das nicht die Aussage, wegen der ich dich angegangen 
bin. Wechsle nicht das Thema.
Deine Aussage war:
> Ich sehe keine Ring-Implementierung, nur irgendwas, das abstürzt,
> nachdem 256 Zeichen reingeschrieben wurden - zzz.
Und das ist definitiv nicht der Fall. Der gepostete Code funktioniert 
wunderbar, so wie er gepostet wurde.

Kein einziger der Punkte, die du als Kritikpunkte in deiner Erwiederung
"Der Ringpuffer von Stefan Noll funktioniert nicht." vorbringst, ist 
stichhaltig.

Manchmal frag ICH mich echt ...

von nollsen (Gast)


Lesenswert?

hi,

ich habe schon ziemlich jede möglichkeit durchprobiert, in 
mikrocontrollern ringpuffer zu implementieren.

klar, am einfachsten macht man ein ringpuffer mit RingBuffer* pBuffer = 
new RingBuffer(2434); , aber auf einem Mikrocontroller mit 8 kbyte passt 
das einfach nicht drauf. ja es ist bitgefrickel, aber bei 1 kb speicher 
muss das eben sein.
große ringpuffer implementiert man eh mit pointern, da pointer schneller 
hochzuzählen sind als 16 bit variablen. wenn die größe noch in 8 bit 
reinpasst, ist eine direkte adressierung tatsächlich schneller.

und ja, der code ist nicht universell einsetzbar wie das .net 
MemoryStream objekt, aber da stoßen C compiler einfach an ihre grenzen, 
die ganzen constraints optimal umzusetzen.

von Bernd M. (bernd_m)


Lesenswert?

Lohnt es sich noch Popcorn zu holen?
m)

Bernd

von Camel C. (camelcoder)


Lesenswert?

übrigens:
ptr_to_t->y entspricht (*ptr_to_t).y und das entspricht t.y, wenn z.B. 
struct s *ptr_to_t = &t; definiert wurde

da wär jetzt von euch auch keinem ein zacken aus der krone gefallen, das 
einfach mal kurz zu erklären... :)

von Uhu U. (uhu)


Lesenswert?

Camel Coder schrieb:
> übrigens:
> ptr_to_t->y entspricht (*ptr_to_t).y und das entspricht t.y, wenn z.B.
> struct s *ptr_to_t = &t; definiert wurde
>
> da wär jetzt von euch auch keinem ein zacken aus der krone gefallen, das
> einfach mal kurz zu erklären... :)

Für solche Grundbegriffe genügt wirklich ein Verweis auf ein beliebiges 
C-Buch - den hat Karl heinz Buchegger gegeben.

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.