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
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.
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.
> - 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.
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...
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:
@ 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
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.
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
hans dampf schrieb:> @ nollsen:>> kannst du mir mal bissl was zu deinem code erklären?>> 1.: was ist ein uchar?
1
typedefunsignedcharuchar;
> 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.
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.
@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.
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.
@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...
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 ...
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.
ü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... :)
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.