Hilfe bei Pointern und FIFO programmierung.

m0erk

Level-1
Beiträge
31
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich bin grade dabei einen FIFO Speicher zu Programmieren. Leider haben mir die Foreneinträge die ich hier gefunden habe nicht wirklich weiter geholfen.
Das ganze soll erstmal nur im Simulations Modus laufen, also Hardware ist vorerst Wurst. Ich möchte das ganze gerne folgendermaßen realisieren.

Ein ARRAY mit 20 Zellen vom Typ INT. Zwei Pointer, der eine zeigt auf den Aktuellen Wert (Startwert), der andere zeigt auf das Ende der Liste, bzw. auf die nächste auszulesende Zelle des Arrays. Den Startpointer möchte ich als Index für das Array benutzen, also z.B. ARRAY[START] soll auf Zelle 1,2,3,4,5... zeigen, je nach dem wo der nächste Wert zu schreiben ist.

Nach auslesen des ersten Wertes soll der Pointer der auf das Ende der Liste zeigt inkrementiert werden und so auf den nächsten Eintrag im ARRAY zeigen.


Ich habe vorallem meine Verständisprobleme mit den Pointern in CoDeSys, wenn ich jetzt einen pointer definiere.

pt:POINTER TO ARRAY[1..20] OF INT, klappt das dann, dass ich den inkrementieren kann und er dann auf die nächste Zelle im Array zeigt?
Und wie kann ich mir dann den Wert auf den der Pointer zeigt anzeigen lassen?

Mein nächstes Problem ist, dass ich das ganze gern in zwei Funktionen haben würde: eine zum Abspeichern der Daten und die andere zum Auslesen.
Wie stelle ich sowas am geschicktesten an?

An sich bräuchte ich mal irgend eine richtig vernünftige Erklärung, am besten mit einfachen Beispielen, zum Thema Pointer in CoDeSys. Evtl. hat ja jemand einen Link oder so?

Die SuFu habe ich schon bemüht, aber leider hauptsächlich auf STEP 7 Sachen gestossen.

PS: gibts evtl noch ne einfacherer lösung die dem nahe kommt unter codesys?! Ohne pointer mit anderen geschichten?
 
Zuletzt bearbeitet:
Ich glaube nicht, dass du in deinem Anwendungsfall unbedingt mit "echten" Pointern arbeiten mußt.
Du kannst dein Array definieren und dazu zwei Int, Zeiger_Ist, Zeiger_Soll z. Bsp.

Dann kannst du auf das Array zugreifen indem du schreibst,

Zeiger_Ist := 5;
MyArrayWert := MyArray[Zeiger_Ist];

Du mußt aber darauf achten, dass der Zeiger_Ist nicht auf Werte außerhalb deines Array gesetzt wird. Codesys hat dafür zwar eine Funktion, die kann man aktivieren und dann achtet Codesys selbst darauf (Name der Funktion fällt mir gerade nicht ein :confused:), aber die kostet rel. viel Performance und sollte nur während der Testzeit aktiviert werden.

Wozu soll der zweite Zeiger denn eigentlich gut sein?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also der erste Zeiger soll ja auf die nächste zu schreibende Zelle des Arrays zeigen. Der zweite Zeiger soll auf die nächste zu lesende Zelle des Arrays zeigen.
Das immer klar ist, wo als nächstes geschrieben werden kann und wo der nächste Wert der Liste zum lesen steht.

Habe jetzt folgendes Problem: Wie genau kann ich Schrittweise Werte ins Array schreiben? Wenn ich die Funktion im PLC_PRG aufrufe, wird sie nur einmal abgearbeitet habe ich das gefühl. Danach passiert nix mehr.

Hier mal meine Fkt.
Code:
(*Versuch FIFO Funktion in Strukturiertem Text.*)

LISTE[zeige_start]:=WERT;
zeige_start:=zeige_start+1;

IF zeige_start > 20 THEN
zeige_start:=1;
END_IF
RETURN;

Aufrufen tue ich das ganze mit:

Code:
WHILE START = TRUE DO
FIFO(WERT);
START:=FALSE;
END_WHILE

Es wird immer nur die erste Zelle von meinem Array geändert, der Index scheint sich nicht zu erhöhen.
Bin halt noch ziemlicher Anfänger in ST und CoDeSys allgemein. Manche zusammenhänge sind mir noch gar nicht klar.

Grüße,
m0erk.
 
Zuletzt bearbeitet:
pt:POINTER TO ARRAY[1..20] OF INT, klappt das dann, dass ich den inkrementieren kann und er dann auf die nächste Zelle im Array zeigt? Und wie kann ich mir dann den Wert auf den der Pointer zeigt anzeigen lassen?
Wie Ralle schon schreibt, brauchst Du gar keine Pointer. Deine Schreib- und Lesezeiger sind keine Zeiger im Sinne von Speicheradressen, sondern INT-Array-Indizes.
Mein nächstes Problem ist, dass ich das ganze gern in zwei Funktionen haben würde: eine zum Abspeichern der Daten und die andere zum Auslesen. Wie stelle ich sowas am geschicktesten an?
Ich würde einen FB schreiben, der keinen Hauptcode, sondern nur zwei Aktionen zum Lesen und Schreiben hat. In der unflexibleren Variante würde der FB auch das Datenarray enthalten, den zu schreibenden Wert als VAR_INPUT und den auszulesenden Wert als VAR_OUTPUT.
Flexibler wäre der FB, wenn er nur Schreib- und Leseindex als VAR_OUTPUT verwalten und die Arraygrösse als VAR_INPUT erhalten würde. Das Datenarray würde dann im aufrufenden Programm deklariert und könnte von beliebiger Grösse und beliebigem Feldtyp sein.
 
Hallo,
- also erstmal hat dir Ralle das relevante doch schon genannt : nicht mit einem Pointer arbeiten, sondern einen Lese-Index und einen Schreib-Index bilden. Das wären dann 2 unterschiedliche Variablen.
- dann : so signifikant sind die Unterschiede hierfür zwischen ST und Siemens-SCL nicht. Wenn es also SCL-Beispiele gibt (und da bin ich mir fast sicher) dann kannst du die sehr wahrscheinlich genauso verwenden.

Zur Funktion :
- Zu irgendeinem Zeitpunkt mußt du den Baustein mal initialisieren. Nun würde ich den Schreib-Index auf 1 setzen (da kommt der nächste Wert hin) und den Lese-Index auf 0 (es gibt keinen Wert zum Auslesen).
- Nun schreibst du Daten in dein Array. Das tust du an Position Array_Element[Schreib_index]. Steht der Lese-Index nun auf 0 so kannst du ihn dann auf 1 setzen. Auf jeden Fall aber erhöhst du nach jedem Schreiben den Schreib-Index um 1. Hier mußt du dir nun schon Gedanken machen, was passieren soll, wenn dein Schreib-Index die max.Größe der Array-Dimensionierung überschreitet ... eventuell keine neuen Daten mehr annehmen ... oder oder ...
- Jetzt willst du einen Datensatz auslesen. Du holst dir bei (Lese-Index <> 0) oder bei (Lese-Index < Schreib-Index) das Array_Element[Lese_index] und erhöhst dann den Lese-Index um 1.

Das wars. Kannst du das nun ggf. selber programmieren ...?

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich probier jetzt erstmal ein bisschen. Theoretisch weiss ich schon ziemlich genau, was ich zu tun habe. Leider reichen meine Programmierkenntnisse bei weitem nicht aus, um das ganze zu fassen.
Ich habe extreme probleme diese Funktion oder den FB dann vernünftig aufzurufen bzw. ist mir nicht klar, wie ich jetzt werte nach und nach in das array schreibe: Ich will ja bei jedem Button Drücken in der Visu einen Eintrag ins nächste Feld meines Arrays schreiben. Da haperts eigentlich am meisten. Wie genau realisiere ich den aufruf mit einem Button im Hauptprogramm aus der Visu heraus?
Die reine Logik des Arrays und wie ich mit den Zeigern auf die Zellen arbeite habt ihr mir sehr gut nah gebracht!!

Danke für die viele Mühe!


PS: Grüße nach Detmold :) Die Ostwestfalen sind doch immer hilfsbereit!
PPS: Die Thüringer auch... :)


Update: Kann jetzt ins Array schreiben, das Problem war die Lokale Veriable zeiger_start:INT:=1; die bei jedem funktionsaufruf wieder mit 1 initialisiert wurde... das meine ich mit "zusammenhänge nicht klar".. ich brauch ewig um solche einfachen fehler zu finden und zu eleminieren :P
 
Zuletzt bearbeitet:
PS: Grüße nach Detmold :) Die Ostwestfalen sind doch immer hilfsbereit!

Das ist mein 2. Nickname ... ;)

Zu deinem Problem :
Ich denke, dass du alles immer ausführst. Dann ist dann schon mal nicht so sinnig.
Zu deiner Tasten-Funktion aus der Visu würde ich mir eine Flanke bilden und damit die Aktion (egal welche davon) nur einmal pro Tastendruck ausführen.
Alles, was du da machst, solltest du erstmal nicht mit TEMP-Variablen machen. Die haben das Problem, dass sie von Aufruf zu Aufruf wieder "vergessen" werden. Wenn du dir aber etwas "merken" möchtest, so ist der STAT-Bereich hier dein Freund ...
Wenn du sonst Fragen hast, dann wäre es schön, wenn du einmal ein bißchen Code postest und deine Fragen dazu stellst - da kann man dann einfacher konkret werden ...

Gruß
Larry
 
Das Ganze ist einfacher, wenn man das Array mit dem Index 0 beginnen lässt, also ARRAY[0..19] of INT. Lese- und Schreibzeiger beim Start auf 0 setzen. "Lesezeiger=Schreibzeiger" ist dann auch im Folgenden die Erkennung für "FIFO leer". Nach jedem Schreiben den Schreibzeiger um 1 erhöhen bzw. von 20 auf 0 setzen, geht einfach mit "Schreibzeiger:=(Schreibzeiger+1) MOD 20". Schreiben darf man natürlich nur, solange der Puffer nicht voll ist. Das wäre daran zu erkennen, dass der Schreibzeiger auf den Lesezeiger laufen würde, also "((Schreibzeiger+1) MOD 20)=Lesezeiger". Nach jedem Lesen den Lesezeiger um 1 auf die selbe Weise erhöhen wie den Schreibzeiger. Anstelle der Vergleiche für "FIFO leer/FIFO voll" könnte man auch eine eigene Füllstandsvariable spendieren, die man beim Schreiben/Lesen entsprechend inkrementiert/dekrementiert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Alles, was du da machst, solltest du erstmal nicht mit TEMP-Variablen machen. Die haben das Problem, dass sie von Aufruf zu Aufruf wieder "vergessen" werden. Wenn du dir aber etwas "merken" möchtest, so ist der STAT-Bereich hier dein Freund ...
Auf jeden Fall, aber die Begriffe "TEMP" und "STAT" gibt es ja bei CoDeSys gar nicht. Lokale Variablen von Funktionen sind immer temporär, solche von Funktionsbausteinen dagegen immer statisch. Der FIFO muss also ein FB sein.
 
Ja das mit dem "alles Ausführen" habe ich jetzt auch mit einer While schleife unterbunden, die jewails auf eine bestimmte boolsche variable einmal die funktion aufruft und die variable wieder false setzt. Weiss nicht ob das so sauber ist, aber es funtzt. Die Variablen habe ich jetzt auch so weit im Griff denke ich, habe die Zeiger und das Array einfach Global deklariert und den rest eben entweder als IN oder als TEMP, bei denen es geht. Habe jetzt das lesen hinbekommen und auch das schreiben. Nach dem lesen wird der wert des array wieder auf 0 gesetzt um die bearbeitung anzuzeigen. Jetzt muss ich dieses "Versuchs" Projekt nur noch in mein eigentliches Projekt implementieren (ich denke ich werds darin einfach nochmal neu schreiben und anpassen) und dann bin ich mit dem FIFO so weit durch.

Danke an alle die mir geholfen haben, ohne euch hätte ich das nicht so schnell hinbekommen.

Hier nochmal mein Code:

PLC_PRG


Code:
PROGRAM PLC_PRG
VAR
    FIFO_RD1:FIFO_RD;
    WERT: INT;
    WERT_RD:INT;
    START_WR:BOOL:=FALSE;
    START_RD: BOOL:=FALSE;
    A1: BOOL:=FALSE;
    A2: BOOL:=FALSE;
    A3: BOOL:=FALSE;
END_VAR

(*Speichern der Werte im Array*)
WHILE START_WR = TRUE DO

    FIFO(WERT);

    START_WR:=FALSE;
END_WHILE;

(*Lesen des akt. Wertes aus dem Array*)
WHILE START_RD = TRUE DO

    FIFO_RD1();
    WERT_RD:=FIFO_RD1.WERT;

(*Auf den Wert des Arrays reagieren.*)
    CASE WERT_RD OF
    1:A1:=TRUE;
        A2:=FALSE;
    2:A2:=TRUE;
        A1:=FALSE;
    ELSE
    A3:=TRUE;
    A1:=FALSE;
    A2:=FALSE;
    END_CASE;

    START_RD:=FALSE;
END_WHILE;

Funktion SCHREIBEN

Code:
FUNCTION FIFO : BOOL
VAR_INPUT
    WERT:INT;
END_VAR
VAR

(*FIFO Funktion zum Schreiben der Werte.*)

LISTE[zeige_start]:=WERT;

IF zeige_start >= 20 THEN

    zeige_start:=1;

ELSE

    zeige_start:=zeige_start+1;

END_IF;

Funktionsblock LESEN (kann auch noch ne Funktion werden)

Code:
FUNCTION_BLOCK FIFO_RD
VAR_INPUT
END_VAR
VAR_OUTPUT
    WERT:INT;
END_VAR
VAR
END_VAR

(*FIFO FB zum Auslesen der Werte.*)

IF zeige_ende < zeige_start THEN
    WERT:=LISTE[zeige_ende];

        IF WERT > 0 THEN
        LISTE[zeige_ende]:=0;
        END_IF;

    zeige_ende:=zeige_ende+1;
END_IF;

IF zeige_ende >= 20 THEN
    zeige_ende:=0;
END_IF;

Und meine Liste der GLobalen Variablen

Code:
VAR_GLOBAL
    LISTE:ARRAY[0..20] OF INT;
    zeige_start:INT:=1;
    zeige_ende:INT:=0;
END_VAR



Könnte mir jemand noch Tipps zum verbessern geben, oder sagen, ob Grundsätzlich alles in Ordnung ist?
Das ganze ist nen eigenen Projekt, quasi "proof-of-concept", das jetzt in die eigentliche Aufgabe integriert werden soll.
Evtl. ein paar Tipps, wie ich sowas am Intelligentesten in ein bestehendes Projekt einfüge?

Grüße,
m0erk.
 
@StructuredTrash:
Ich hoffe du verzeihst mir, aber ich bin halt nun mal ein Siemens-Programmierer und leite dann Einiges nach SCL ab ... ;)

@m0erk:
Wenn du das Ganze wirklich verbessern willst dann solltest du dem Vorschlag von StructuredTrash aufgreifen und Alles in einen FB zusammenpacken (so würde ich es übrigens auch machen).
Der FB könnte nun das Array und deine Zeiger intern verwalten.
Über die Schnittstelle (IN) wählst du die gewünschte Funktion (Lesen oder Schreiben) aus und über einen INOUT liest du den Wert ein oder gibst ihn aus.
Der Vorteil hierbei ist, dass du alles Zusammengehörende auch zusammen hast - Kapselung.
Über die Schnittstelle (OUT) könntest du dann noch zusätzliche Info's wie z.B. "Daten im Puffer" oder "Daten eingelesen" oder "Daten ausgegeben" oder "Fehler" oder oder ... ausgeben.

Eine "While-Schleife" ist bei einer "Zyklischen Programmbearbeitung" immer so eine Sache. Da solltest du ggf. auch noch einmal drüber nachdenken. Es gibt ja auch noch IF ... THEN ...

Gruß
Larry
 
@StructuredTrash:
Ich hoffe du verzeihst mir, aber ich bin halt nun mal ein Siemens-Programmierer und leite dann Einiges nach SCL ab ... ;)
Aber sicher, war ja nicht böse gemeint. Wo kämen wir auch hin, wenn es bei Siemens so wäre wie im Rest der Welt. ;)Schliesslich ist der Rest in diesem Fall der eindeutig kleinere Teil.

@m0erk:
Ich würde alles, wie schon gesagt, in einen FB packen. Das macht es einfacher, den FIFO auch in anderen Projekten einzusetzen. Mit Deiner Lesefunktion wirst Du ein Problem bekommen, sobald der Schreibzeiger einmal die 20 überschritten hat, wenn z. B. der Lesezeiger noch bei 18, der Schreibzeiger aber schon wieder bei 2 ist. Und in der Schreibfunktion hast Du keine Absicherung gegen das Überschreiben noch nicht ausgelesener Daten.
 
Nochmals danke für eure Tipps! Ich werde das Ganze in nen FB packen und denke mir auch noch was wegen dem Problem, dass StructuredTrash geschrieben hat, dass ist mir beim testen natürlich auch aufgefallen :P Du hattest ja schon eine Lösung dazu geschrieben, ich versuche das mal einzubauen. Also als Eingang bei nem FB hätte man den Wert der rein soll und lesen und schreiben, wenn ich das richtig sehe und raus kommt der aktuell gelesene Wert und evtl. wertere Infos wie Fehler bzw. leer/voll Meldungen?

BTW: Super Forum hier! Es wird einem nicht einfach der Code vor die Nase gesetzt sondern mal wirklich geschaut, wo das Problem liegt und gezielt darauf geantwortet. Einfach klasse. :)

Grüße,

m0erk.

PS: Die oscat lib hab ich schon probiert aber ich wollte gerne selbst machen ;)
 
Zurück
Oben