Hallo, ich habe bis jetzt meine serielle Schnittstelle (8051er) immer über Polling bedient. Jetzt wird es auch mal Zeit, mich mit Ringspeichern zu beschäftigen. Leider habe ich bis jetzt noch keinen (befriedigenden) eigenen Ansatz gefunden, der wirklich gut wäre. Kann mir jemand dabei helfen? Das ganze sollte so ausgelegt sein, dass ich die Ringspeicher-Routinen beliebig verwenden kann, also entkoppelt von den seriellen Routinen, weil diese auch mit Handshake usw. arbeiten. Sprache wäre Assembler oder C. Google-Suche oder Forums-Suche hat nicht geholfen. Wahrscheinlich die falschen Stichwörter verwendet ;-) Gruß Ralf
Nach dem englischen Begriff "FIFO" (first-in, first-out) suchen könnte helfen.
Oder die Forensuche, diese Fragestellung gab es schon öfters und natürlich auch qualifizierte Antworten. Der Informatikskript jeder beliebigen Uni sollte so etwas im Normalfall auch enthalten, genauso wie jedes gute C-Buch.
Ich habe zu diesem Thema eine kleine Sammlung von drei Upros in 8051-Assembler geschrieben: buf_init, buf_put, buf_get Sie verwalten einen 16-Bytes großen Ringspeicher. (Die Größe läßt sich in 2^n-Schritten leicht anpassen). Außerdem werden die Bit-Variablen buf_full und buf_empty zur Verfügung gestellt. Bei Interesse kann ich den Code heute abend hier posten. Gruß, Markus_8051
Danke für die Antworten. @Markus_8051: Ja, bitte poste mal. Wie ist das, ich muss aber (was mir erst hinterher auffiel) für jeden RingBuffer, den ich im Projekt verwende, eigene Zugriffsroutinen verwenden, richtig? Gruß Ralf
Hi nö. Du kannst jeder Funktion ja einen Pointer auf eine struct ringbuf { ... } mitgeben. Matthias
Hmmm, in C geht das wohl so, in Assembler wird das schwieriger. Da ich nur einen Ringbuffer verwende, habe ich mir da auch keine weiteren Gedanken zu gemacht. Nun ja, vielleicht kannst Du meinen Code ja noch verbessern. Wie gesagt, kommt heute abend!!! Markus_8051
@Matthias: Pointer auf eine Struktur... Nur um mich zu vergewissern, was du meinst: Ich lege also eine Struktur an, die dann jeweils den Ringbuffer und die Schreib-Lesepointer enthält? Hört sich gut an (wenn ich es wirklich so verstanden habe, wie du meinst ;-) Wie ist das, in einigen Codes, die ich gefunden habe, wird noch eine Variable verwendet, die aussagt, wieviele ungelesene Bytes sich im Ringbuffer befinden. Bringt die einen Vorteil, den ich nicht sehe? Denn die Angabe, wieviel ungelesenes noch drin ist, bekomme ich doch auch, indem ich die Differenz aus Schreib- und Lesepointer bilde, oder? Latürnich nur unter der Vorraussetzung, dass kein Überlauf stattgefunden hat. In dem Fall wäre aber der Buffer-Inhalt eh Gülle, also brauche ich die Variable nicht wirklich, oder? Gruß Ralf PS: Warst du nicht zusammen mit Stefan Schöndienst in der Berufsschule?
Hi so war das gedacht. Die zusätzliche Variable die die Menge der Zeichen im Buffer angiebt ist nicht wirklich nötig und bringt auch keine sonderlichen Performancegewinne wenn man nicht 10000mal pro empfangen Zeichen den Puffer prüft. PS: Jap. Sag ihm mal nen schönen Gruß von mir. Matthias
Hallo, ich hatte mal einen µkernel für einen 8051 geschrieben in den ich einen 256Byte großen ringpuffer für den empfang realisiert hatte in ASM, 256Byte weil es genügent groß ist und es sich wunderbar über movx a,@DPTR adressieren wenn der puffer an einer 256byte grenze anfäng wie z.b. 0x0400h oder so, da kann man einfach DPL durch einen VariablenPointer ersetzen. Man brauch drei variablen um diesen sinnvoll und effektiv zu erstellen. 1. ByteCounter, diese variable beinhalt die bytes die sich im ringpuffer befinden. 2. WritePointer, dieser zeigt auf die nächste Speicherzelle die geschrieben wird, beim schreiben wird WritePointer um 1 erhöht und ByteCounter auch 1. ReadPointer, dieser zeigt auf das nächste byte welches gelesen wird, beim lesen wird ReadPointer um 1 erhöht und ByteCounter um 1 verringert. Die drei variablen sind bytevariablen wobei Write und ReadPointer auch überlaufen dürfen, weil sie trotzden auf die richtige speicherzelle zeigt -> Ringbuffer. Wichtig ist nur das Bytecounter nicht überläuft, sonst ist der puffer voll. Wenn Bytecounter auf 255 steht kann man einfach neue byte für den puffer ignorieren. Wenn Bytecounter auf null steht ist der puffer leer und man wartet aufs nächste byte. ich hoffe das hilft dir ein bischen. CA
@Matthias: Okay, hab mir das jetzt durchdacht. Was mir aufgefallen ist: 1. Wenn ich die Sache mit Strukturen mache, müsste ich mehrere Strukturen verwenden, wenn ich z.B. einen Ringbuffer mit 16 Bytes und einen mit 32 Bytes haben möchte, richtig? Also etwa so: typedef struct { uchar ucBuffer[16], uchar ucRead; uchar ucWrite; } stRingBuffer_TYP1; typedef struct { uchar ucBuffer[32], uchar ucRead; uchar ucWrite; } stRingBuffer_TYP2; 2. Soll ich den Zugriff auf das Array über den Index des Array-Feldes machen, oder lieber über einen Pointer? @Dirk: Danke, das ist auch hilfreich. Gruß Ralf
Nachtrag zum Beitrag von gerade eben: Kann ich mit einer Funktion auf beide Struct-Typen zugreifen? Und wie deklariere ich überhaupt einen Pointer auf eine Struktur?!? Gruß Ralf
Hi zu 1. Eigentlich ja. zu 2. Eigentlich egal. Du kannst dir aber mal im Detail ankucken was der Compiler daraus macht wenns wirklich hocheffizient sein soll. Der Zugriff mittels Array-Index ist zwar (programmiertechnisch) einfacher aber unter Umständen langsamer. >Kann ich mit einer Funktion auf beide Struct-Typen zugreifen? Eigentlich nicht. Mit einer gezielten Anordnung der Strukturvariablen geht das aber. Ist aber unsauber und AFAIK auch unportabel. Grundsätzlich und sauberer würde man sowas mit einem Pointer in der Struktur auf den gewünschten Datentyp undstatisch bzw. dynamisch (z.B. per malloc) allokiertem Speicher erledigen. In der Struktur muß dann zusätzlich noch die Länge verwaltet werden. Also etwa so: uchar ringBufMem1[16]; uchar ringBufMem2[32]; typedef struct { uchar * ucBuffer; uchar ucRead; uchar ucWrite; uint length; } stRingBuffer; stRingBuffer buf1; stRingBuffer buf2; void ringBufInit(void) { buf1.ucBuffer = ringBufMem1; buf1.length = sizeof(ringBufMem1)/sizeof(uchar); buf2.ucBuffer = ringBufMem2; buf2.length = sizeof(ringBufMem2)/sizeof(uchar); } Ob sowas auf einem kleinen µC nötig ist mußt du selbst entscheiden. >Und wie deklariere ich überhaupt einen Pointer auf eine Struktur?!? stRingBuffer * pTostRingBuffer; Matthias
Hi Matthias,
> Ob sowas auf einem kleinen µC nötig ist mußt du selbst entscheiden.
Der Gedanke war, falls ich mal in einem Projekt mit mehreren
Ringspeichern arbeite, dass ich die Ringspeicher trotz
unterschiedlicher Größe mit der gleichen Routine bearbeiten kann. Ich
habe es jetzt so gemacht, dass ich eben bis zu drei Ringspeicher
anlegen kann, und jeder Ringspeicher hat seine eigenen Routinen.
Aber mal sehen, dein Code-Beispiel hat glaube ich (nach meinem
Verständnis) das Potential für meine Anwendung.
Was tut man nicht alles, um C zu lernen grins
Ein Gedanke von mir war auch, "irgendwie" den Typ der im Pointer
übergebenen Struktur herauszufinden, vielleicht hätte sich damit was
machen lassen.
Aber so wie ich die Sache verstanden habe (dank deiner Hilfe mit der
Pointer-Deklaration), verwendet C für den Zugriff auf die Elemente der
Struktur feste Offsets, die zur Startadresse der Struktur hinzuaddiert
werden.
Gruß Ralf
Hallo, hat noch jemand Lust auf Assembler? Im upload findet Ihr ein paar Code-Fetzen zum gepufferten Lesen und Schreiben der RS232-Schnittstelle im 8051. Bitte beachtet folgende Anmerkungen: 1. Die Größe der beiden Puffer kann frei gewählt werden. Da bei jedoch beide im internen RAM liegen sollte man geizen. 2. Es erfolgt keine Überwachung des Überlaufs. 3. Ich verwende als Assembler AS von Alfred Arnold, der in einer selbstentwickelten IDE eingebettet ist. Dabei ersetzt die IDE alle Befehle, die mit Unterstrich „_“ beginnen in gültige Assembler-Statements. Die _if statements funktionieren so wie man meint, das sie funktionieren. Im folgenden Posting hängt die Quelle wie sie der Assembler sieht, d.h. mit ersetzten _if's cu
So, hier kommt mein inc-File für einen Ringbuffer für die serielle Schnittstelle. Ich habe ihn nur zum senden benutzt. Beachte bitte, daß die Prozedur send_char erwartet, daß es eine IRQ-basierte Senderoutine gibt, die den Buffer leert, wenn die RS232 frei ist. Sonst hängt sich der µC hier weg. Viel Erfolg damit, Markus_8051
Noch ne Frage wegen Pointer auf Strukturen: Kann ich anstatt einen Pointer auf die Struktur zu übergeben, auch den Pointer auf ein Element der Struktur übergeben? Gruß Ralf
@Markus_8051 & Edgar Renner: Danke für die Routinen, werd ich mir auch mal angucken. Gruß Ralf
Hi im Prinzip ja. Du kannst aber aus einem Pointer auf ein Element der Struktur eigentlich nicht mehr auf die Struktur selber zurückschließen wenn es portabel sein soll. Matthias
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.