mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ringbuffer lesen/schreiben


Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen, wir haben die Aufgabe bekommen ein Programm (auf dem8051) von 
Assembler in C zu übersetzen. Es geht dabei ums aus- und einlesen von 
Daten aus einem Ringbuffer. Insbesondere ist mir nicht klar, wie ich die 
Variablen initilisieren soll (siehe Funktion rbInit). Es wäre gut, wenn 
ihr da mal drüberschauen konntet. Danke im Voraus.
#include "rbLIB.h"


extern void rbInit( struct STRUCT_RB_CTRL *prbCtrl, char *buffer, unsigned char size )
{
  prbCtrl->rbUsed = 0;
  prbCtrl->rbStart = buffer;
  //prbCrl->rbSize = SIZE;  //geht nicht, defined in rlib.h #define size 4
  //prbCtrl->rbStart = 0x0  //beginnt bei xdata
  //prbCtrl->rbLast = 0x4  //Anfangsadresse Xdata + 4  
}

extern char rbState( struct STRUCT_RB_CTRL *prbCtrl )
{
  return prbCtrl->rbUsed;
}

extern char rbRead(struct STRUCT_RB_CTRL *prbCtrl, char *value)
{
char rc = ERR_BUF_EMPTY 

  if (prbCtrl->rbUsed > 0)  //Daten im Puffer verfügbar
  {
    value = *prbCtrl->rbReadPos--;     //Lesezeiger dekr. von aktuellen Wert
    if (prbCtrl->rbReadPos < prbCtrl->rbStart)  //Untere Grenze des Puffers erreicht
    {
      prbCtrl->rbReadPos = prbCtrl->rbStart;
    }
    prbCtrl->rbUsed--;
    rc = OK;
  }
  return rc;
}


extern char rbWrite( struct STRUCT_RB_CTRL *prbCtrl, char *value )
{
char rc = ERR_BUF_FULL;

  if( prbCtrl->rbUsed < prbCtrl->rbSize )
  {
    *prbCtrl->rbWritePos++ = value;
    if( prbCtrl->rbWritePos > prbCtrl->rbLast )
    {
      prbCtrl->rbWritePos = prbCtrl->rbStart;
    }
  
    prbCtrl->rbUsed++;
    rc = OK;
  }
  return rc;
}
// EOF rbLIB.c

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde ja gerne das Assemblerprogramm sehen, das der Verwendung von 
'struct' zu Grunde liegt.

Was funktioniert denn nicht?
Variablen initialisiert man vorzugsweise mit 0.

Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde die Variablen so initializieren wie oben in der Funktion 
angegeben.

"SIZE" habe ich wie gesagt in der Header-Datei dekl.:

#define size 4


"rbstart" ist die Startadresses des Puffers und liegt an der 
Anfangsadresse von Speicherbereich XDATA. Meine Frage ist nun wie ich 
das deklariere. Wie unterscheide ich in C zwischen diesen 
Speicherbereichen?

Autor: Daniel N. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C ist case-sensitive!
Du hast also nicht "SIZE" definiert, sondern "size".
#define SIZE 4

Autor: anderer Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> prbCrl->rbSize = SIZE;
> #define size 4

groß und KLEIN schreibung beachten!

Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Quatsch,

so müsste es sein.
extern void rbInit( struct STRUCT_RB_CTRL *prbCtrl, char *buffer, unsigned char size )
{
  prbCtrl->rbUsed = 0;
  prbCtrl->rbStart = buffer;
  //prbCrl->rbSize = SIZE;  //geht nicht, defined in rlib.h #define size 4
  //prbCtrl->rbLast = buffer + 4  //Anfangsadresse Xdata + 4  
}


Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, "size" habe ich jetzt klein geschrieben Schreibefehler. Das habe ich 
nicht beachtet, weil ich vorher mit VHDL rumgemacht habe und der Prof 
schreibt Schlüsselworter und Konstneten immer groß. Ich versuche immer 
alles klein zu schreiben.

Autor: Daniel N. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso nimmst du eigentlich nicht einfach das "size", dass du sowieso der 
init funktion übergibst?

Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, machen wir es besser so

prbCrl->rbSize = SIZE;  //geht nicht, defined in rlib.h #define SIZE 4

Konstanten groß schreiben. Das Funzt jetzt so.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BerndS wrote:
> Morgen, wir haben die Aufgabe bekommen ein Programm (auf dem8051) von
> Assembler in C zu übersetzen.

Dann wirst Du hierfür wohl eine glatte "6" bekommen.

Du hast einfach ohne Nachzudenken von irgendwoher eine Lösung kopiert, 
die für wesentlich größere Systeme ausgelegt sind, als für nen kleinen 
8051.
Der MC wird sich erstmal schon dumm und dußlich ackern, ehe er überhaupt 
die ganzen Indirektionen aufgelöst hat.
Und zu allem Übel wird er das mit generic Pointern machen müssen, d.h. 
für jeden einzelnen Bytezugriff nen Funktionsaufruf. Es sind ja keine 
Memory-Specifier angegeben.


Ich kann mir nicht vorstellen, daß der Assemblercode auch nur entfernt 
ähnlich komplex ist.
Er wird wohl ganz einfach sein, ohne Strukturpointer, sondern mit 
direktem Memoryzugriff für genau eine FIFO im IDATA-Bereich.


Zeig dochmal den Assemblercode, damit man weiß, was Du wirklich machen 
sollst.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BerndS wrote:
> OK, "size" habe ich jetzt klein geschrieben Schreibefehler. Das habe ich
> nicht beachtet, weil ich vorher mit VHDL rumgemacht habe und der Prof
> schreibt Schlüsselworter und Konstneten immer groß. Ich versuche immer
> alles klein zu schreiben.

Damit mans schlechter lesen kann? Nene die Konstanten-"Regel" gilt bei 
ziemlich vielen Programmiersprachen. Ist kein schlechter Stil das 
beizubehalten.

Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter,  es ist eine Praktikumsaufgabe und die Funktionsrümpfe wurden 
vorgegeben. Der Algorithmus für das Lesen und Schreiben eines Bytes 
(generisch) wurde als Ablaufdiagramm (mit Variablen) im Heft für 
Assemblerprogrammierung vorgegeben. Dort ist auch ein einfaches Beispiel 
für die Programmierung eines Ringpuffers, was ich hier ja mal einstellen 
kann.

Diese Lösung ist nicht optimal (weil generisch). Daher sollen wir uns ja 
im nächsten Schritt überlegen, wie wir das Programm optimieren können. 
Eine Lösung ist die generischen Zeiger durch spezifische Zeiger zu 
ersetzen. Mir ist nur noch nicht klar wie...

#include "rbLIB.h"


extern void rbInit( struct STRUCT_RB_CTRL *prbCtrl, char *buffer, 
unsigned char size )
{
  prbCtrl->rbUsed = 0;
  prbCtrl->rbStart = buffer;
  prbCrl->rbSize = size;
  prbCtrl->rbLast = size + buffer -1
}

extern char rbState( struct STRUCT_RB_CTRL *prbCtrl )
{
  return prbCtrl->rbUsed;
}

extern char rbRead(struct STRUCT_RB_CTRL *prbCtrl, char *value)
{
char rc = ERR_BUF_EMPTY;

  if (prbCtrl->rbUsed > 0)  //Daten im Puffer verfügbar
  {
    *value = *prbCtrl->rbReadPos++;     //Lesezeiger dekr. von aktuellen 
Wert
    if (prbCtrl->rbReadPos < prbCtrl->rbStart)  //Untere Grenze des 
Puffers erreicht
    if (prbCtrl->rbReadPos < prbCtrl->rbLast)   //Obere Grenze des 
Puffers erreicht
    {
      prbCtrl->rbReadPos = prbCtrl->rbStart;
    }
    prbCtrl->rbUsed--;
    rc = OK;
  }
  return rc;
}


extern char rbWrite( struct STRUCT_RB_CTRL *prbCtrl, char value )
{
char rc = ERR_BUF_FULL;

  if( prbCtrl->rbUsed < prbCtrl->rbSize )
  {
    *prbCtrl->rbWritePos++ = value;
    if( prbCtrl->rbWritePos > prbCtrl->rbLast )
    {
      prbCtrl->rbWritePos = prbCtrl->rbStart;
    }

    prbCtrl->rbUsed++;
    rc = OK;
  }
  return rc;
}
// EOF rbLIB.c

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BerndS wrote:
> Der Algorithmus für das Lesen und Schreiben eines Bytes
> (generisch) wurde als Ablaufdiagramm (mit Variablen) im Heft für
> Assemblerprogrammierung vorgegeben. Dort ist auch ein einfaches Beispiel
> für die Programmierung eines Ringpuffers, was ich hier ja mal einstellen
> kann.

Ja das wäre sinnvoll.


> Diese Lösung ist nicht optimal (weil generisch). Daher sollen wir uns ja
> im nächsten Schritt überlegen, wie wir das Programm optimieren können.

Der 8051 ist nicht sonderlich optimiert auf Operationen mit Zeigern auf 
Strukturen mit Zeigern (doppelte Indirektion).
Wenn der FIFO die gesamte Laufzeit gebraucht wird, ist es also 
sinnvoller seine Struktur direkt im Memory zu plazieren.
Vielleicht ab 10 FIFOs ist die Pointervariante wieder günstiger im 
Codeverbrauch.


> Eine Lösung ist die generischen Zeiger durch spezifische Zeiger zu
> ersetzen.

Das kann auch noch etwas bringen, ist aber bei Strukturen ziemlich 
haarig in der Syntax. Mal in der Keil Knowledgebase googlen.


> #include "rbLIB.h"

Wo ist denn die?
Wenn man Code postet, muß man auch alle darin verwendeten Definitionen 
mitposten.
Er muß compilierbar sein, sonst ist es sinnlos.


Peter

Autor: BerndS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, ich stell den kompletten Code heute abend mal hier ein.

Autor: BerndS (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
OK, hier das komplette fehlerfreie Projekt.

Optimieren kann ich das Programm noch, indem ich die Zeiger auf den 
Speicherbereich xdata Verweise, also
char xdata *rbReadPos 
char xdata *rbWritePos
...

Autor: BerndS (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Anbei das komplette Projekt mit spezifischen Pointern. Statt 900 habe 
ich jetzt nur noch eine Codegröße von knapp 300Byte.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.