Forum: Mikrocontroller und Digitale Elektronik Ringbuffer lesen/schreiben


von BerndS (Gast)


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.
1
#include "rbLIB.h"
2
3
4
extern void rbInit( struct STRUCT_RB_CTRL *prbCtrl, char *buffer, unsigned char size )
5
{
6
  prbCtrl->rbUsed = 0;
7
  prbCtrl->rbStart = buffer;
8
  //prbCrl->rbSize = SIZE;  //geht nicht, defined in rlib.h #define size 4
9
  //prbCtrl->rbStart = 0x0  //beginnt bei xdata
10
  //prbCtrl->rbLast = 0x4  //Anfangsadresse Xdata + 4  
11
}
12
13
extern char rbState( struct STRUCT_RB_CTRL *prbCtrl )
14
{
15
  return prbCtrl->rbUsed;
16
}
17
18
extern char rbRead(struct STRUCT_RB_CTRL *prbCtrl, char *value)
19
{
20
char rc = ERR_BUF_EMPTY 
21
22
  if (prbCtrl->rbUsed > 0)  //Daten im Puffer verfügbar
23
  {
24
    value = *prbCtrl->rbReadPos--;     //Lesezeiger dekr. von aktuellen Wert
25
    if (prbCtrl->rbReadPos < prbCtrl->rbStart)  //Untere Grenze des Puffers erreicht
26
    {
27
      prbCtrl->rbReadPos = prbCtrl->rbStart;
28
    }
29
    prbCtrl->rbUsed--;
30
    rc = OK;
31
  }
32
  return rc;
33
}
34
35
36
extern char rbWrite( struct STRUCT_RB_CTRL *prbCtrl, char *value )
37
{
38
char rc = ERR_BUF_FULL;
39
40
  if( prbCtrl->rbUsed < prbCtrl->rbSize )
41
  {
42
    *prbCtrl->rbWritePos++ = value;
43
    if( prbCtrl->rbWritePos > prbCtrl->rbLast )
44
    {
45
      prbCtrl->rbWritePos = prbCtrl->rbStart;
46
    }
47
  
48
    prbCtrl->rbUsed++;
49
    rc = OK;
50
  }
51
  return rc;
52
}
53
// EOF rbLIB.c

von Gast (Gast)


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.

von BerndS (Gast)


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?

von Daniel N. (Gast)


Lesenswert?

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

von anderer Gast (Gast)


Lesenswert?

> prbCrl->rbSize = SIZE;
> #define size 4

groß und KLEIN schreibung beachten!

von BerndS (Gast)


Lesenswert?

Quatsch,

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

von BerndS (Gast)


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.

von Daniel N. (Gast)


Lesenswert?

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

von BerndS (Gast)


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.

von Peter D. (peda)


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

von Simon K. (simon) Benutzerseite


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.

von BerndS (Gast)


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

von Peter D. (peda)


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

von BerndS (Gast)


Lesenswert?

OK, ich stell den kompletten Code heute abend mal hier ein.

von BerndS (Gast)


Angehängte Dateien:

Lesenswert?

OK, hier das komplette fehlerfreie Projekt.

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

von BerndS (Gast)


Angehängte Dateien:

Lesenswert?

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

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.