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:
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 | }
|
@ 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
1 | typedef unsigned char uchar; |
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.
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.
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.