# Codesys Pointer auf GLOBALE Variablen WAGO 750-830



## Babylonkiller (7 November 2012)

Servus miteinander,

Folgendes Problem habe ich. Ich übergbe ein  ARRAY[0..90]OF BOOL über einen POINTER an 90 Globale BOOL Variabele. Bis zum Register 64 passt die Übergabe der Werte. Ab Register 65 wird die 66igste Variable beschriben und nicht die 65igste. Warum wird das 65igste Bit immer übersprungen? Und was kann ich machen das es nicht übersprungen wird.

VAR_INPUT
    EreignisID            :WORD;
    ControllerID        :WORD;
    Minute                :WORD;
    Stunde                :WORD;
    Datum                :WORD;
END_VAR
VAR_OUTPUT
    Tag                    :INT;
    Monat                :INT;
    Jahr                :INT;
END_VAR
VAR_IN_OUT
    PT1: POINTER TO  ARRAY[0..90]OF BOOL; (*Meldelisten Pointer *)
    StartAdresse:BOOL;(*Adresse der ersten Globalen Variable *)
END_VAR
VAR
    Meldelsite:ARRAY[0..90]OF BOOL;
    Lauf:INT;
    Lauf1:INT;
    Index:INT;
    TmpDatum:INT;
    TmpDatum1:INT;
    TmpDatum2:INT;
END_VAR

FOR Lauf:=0 TO 90 DO
IF Lauf=EreignisID THEN
    Index:=Lauf;
EXIT;
END_IF;
END_FOR;

FOR Lauf1:=0 TO 90 DO
Meldelsite[Lauf1]:=FALSE;
END_FOR;

Meldelsite[Index]:=TRUE;

PT1:=ADR(StartAdresse);
PT1^:=Meldelsite;


----------



## Majestic_1987 (8 November 2012)

Also...wenn du einen Pointer als VAR_IN_OUT übergibst...dann wirst du außerhalb deines Bausteins ja wahrscheinlich dort ein ARRAY OF BOOL mittels ADR dranhängen, richtig?
Wieso weist du dann am Ende dem Pointer eine neue Adresse zu?

Du hast Anfangs in PT1 die Adresse deines Array drinstehen. Dann tust du irgendwas und an Ende weist du deinem Pointer die Adresse einer booleschen Variable zu. Damit ist dein Außen angelegter Pointer (weil VAR_IN_OUT) kein Zeiger mehr auf das Array sondern auf die Adresse des BOOL. Mit dem eigentlichen Array, auf das du zeigst, tust du...garnix..

Ich würde spontan sagen: Lösch alles und mach neu. Und bevor du Pointer verwendest solltest du (der Verständlichkeit und der Fehlersuche wegen) genau wissen, was du damit tust....weil das hier sieht mir gruselig aus. 

Nur so am Rande:

Die erste Schleife kannst du die sparen. Die bedeutet effektiv nämlich nur: Index := Lauf. Und damit kannste dir direkt auch Index sparen.
Die zweite Schleife ist schon okay. Damit löschst du alle Indizes außer "Index". Auch okay. Dann weist du der Index-ten Variable den Wert TRUE zu. Auch okay. Aber wozu sollte man alle Werte in einer Meldeliste löschen wollen bis auf einen? Ist mir rätselhaft.

Für mich sieht das aus wie:

VAR_INPUT
    iIndex: INT;
    pErsteVar: POINTER TO BOOL;
END_VAR
VAR
   pVar: POINTER TO BOOL;
END_VAR

pVar := pErsteVar+iIndex;
pVar^:=TRUE;

Korrigier mich, wenn ich das beim Überfliegen missverstehe....


----------



## Babylonkiller (8 November 2012)

Hallo Majestic_1987,

also die Sache ist etwas komplizierter. Ich lese von einem Modbus Slave die Werte 0-90 die ich in einer Variable bekomme. Jede Zahl hat eine bedeutung. Zum Beispiel 5 Störung Kompressor usw. Diese Werte muss ich in Bits wandeln und anschliesen über ein Bacnet Protokoll an eine Visu schicken. Da man inerhalb eines Bausteins einzelne Bits eines ARRAYs auf Ausgänge schreiben kann, müstte das doch Extern auch funktionieren. Beispiel Intern:
VAR
Speicher : ARRAY[1..5]OF BOOL;
PTOINTER TO ARRAY[1..5]OF BOOL;
VAR_END
VAR_OUTPUT
A1:BOOL;
A2:BOOL;
A3:BOOL;
A4:BOOL;
A5:BOOL;
END_VAR


PT:=ADR(A1);
PT^:=Speicher;

Wenn jetzt Speicher[1]=TRUE ist dann ist der Ausgang A1 auch TRUE.
Jetzt dachte ich mir wenn das intern funktioniert dann müsste das doch exter auch funktionieren. Wenn ich jetzt das ARRAY direckt auf die einzelen Bits der GLOBALEN Variablen schreiben könnte dann würde ich mir die Arbeit ersparen 90 Variablen an die 90 Ausgänge des Bausteins zu parametrieren. Da ich jetzt aber 6 Slaves habe müsstte ich 540 Variablen händisch an die Bausteine schreiben. Könnte ich das ganze mit einem Pointer machen würde es schneller gehen.
Verstehst du was ich meine?


----------



## Majestic_1987 (8 November 2012)

Du bekommst also vom Modbus-Slave ein Array von 90 BOOLs, die dann auf einzelne boolesche Variablen gemappt werden müssen, da du diese dann an die Visu schickst bzw. aus der Visu heraus ausliest?
Dass jeder Index eine bestimmte Meldung darstellt, war mir schon klar ;-) Trotzdem war der von dir gepostete Code hochgradig verkompliziert.

Ich weiß allerdings noch immer nicht, weswegen du einen Pointer auf ein Array von Bool definierst, um dem dann die Adresse eines Bool zuzuweisen. Das ergibt nicht unbedingt Sinn, weil das von der Typisierung her nicht passt und eigentlich sollte das nen Compilerfehler zur Folge haben. Rein THEORETISCH könnte das Konzept allerdings funktionieren, aber nur, wenn das einzelne Bool in der von dir verwendeten Steuerung auch wirklich exakt die selbe Speicherdarstellung hat, wie ein Element eine Bool-Array.

Folgender Code funktioniert:

```
FUNCTION Test : BOOL
VAR_INPUT
    arrArray: ARRAY[1..10] OF BOOL;   (*Quelldaten von z.B. Modbus-Slave*)
END_VAR
VAR_IN_OUT
    bBegin: BOOL;                            (*Erste Zielvariable*)
END_VAR
VAR
    pBegin: POINTER TO BOOL;
    iLoop: INT;
END_VAR

pBegin := ADR(bBegin);           (*Adresse der Booleschen Variable holen*)
FOR iLoop:=1 TO 10 DO
    pBegin^:=arrArray[iLoop];   (*Der Variable den entsprechenden Wert aus dem Array zuweisen*)
    pBegin := pBegin + 1;         (*Zieladresse um Datentyplänge BOOL inkrementieren*)     
END_FOR
```

Dann sollte man aber auch die Feinheit besitzen, eine globale Konstante MAX_MELD zu deklarieren und die als obere Array-Grenze und Schleifenvariable zu verwenden, damit es nachher wirklich flexibel ist. Nicht zu vergessen: Diese Konstante dann auch intern im FC anlegen mit dem Schlüsselwort EXTERNAL...


----------



## Babylonkiller (8 November 2012)

also ich hab grad deinen Code getestet. Mit meiner 750-841 funktioniert der Code nicht. Wenn ich Bit 2 im ARRAY auf TRUE setze dann ist Bit 1 TRUE und alle anderen FALSE. Warum funktioniert es bei mir nicht?


----------



## Majestic_1987 (8 November 2012)

Weil deine Array-Indizes bei 0 beginnen, würde ich vermuten. Bit 2 im Array (also arrMeldungen[2]) ist ja das 3. Bit. Beginnt die Schleife aber nicht bei 0 sondern bei 1 wurde die Adresse, die im Pointer steht, einmal zu wenig inkrementiert. Du musst dann die Schleife entsprechend anpassen.


----------



## Babylonkiller (8 November 2012)

ich hab nur deinen code kopiert und getestet. aber irgendwie gehts nicht. ich vermute ja das es an der Steuerung liegt. Mein ursprünglicher code funktioniert bis Meldung[64] in der 750-830 ohne probleme. In der 750-841 geht aber garnix. Scheiss Computer gelumpe muahahahahahaha


----------



## Majestic_1987 (8 November 2012)

Du kannst davon ausgehen, dass es nicht an der Steuerung liegt. Schau dir mittels Breakpoints mal an, welche Adressen in der Schleife stehen...und vergleich die mit den Adressen deiner Bools. Ich habs eben auf nem TwinCat getestet. Läuft problemlos.


----------



## Babylonkiller (8 November 2012)

Jetzt versteh ich überhaupt nix mehr.


----------



## Majestic_1987 (8 November 2012)

Poste mal bitte deinen Code. Die Funktion und den kompletten Aufruf. Wichtig ist auch: Du MUSST wenn du mit Pointern rumhantierst und die nicht in jedem Zyklus aktualisierst (ob das so ist hängt von deinem Programm ab) in jedem Fall nen kompletten Download machen, nicht nur ein Online Change, da andernfalls die Pointer ihre Werte behalten, die nach einem Online-Change i.d.R. NICHT mehr den wirklichen Adressen der Variablen entsprechen.

Übrigens scheint die Funktion ja zu stimmen. Allerdings hast du ne Verschiebung in den Adressen um 5 Bit. Das scheint zumindest ein systematischer Fehler zu sein. Könnte an der Speicherverwaltung in der Steuerung liegen (auch wenn ich mir die Verschiebung damit nich wirklich konkret erklären kann).

Versuch mal, die Pointerinkrementierung anzupassen:


```
pBegin := pBegin + SIZEOF(pBegin^);
```


----------



## Babylonkiller (12 November 2012)

Hallo                                                                                     Majestic_1987,

also der berschriebene Code von dir Funktioniert werder inerhalb eines Bausteins noch auserhalb. Das kann nur ein WAGO Problem sein. Ich werd mal bei WAGO nachfragen. Trotzdem danke für deine Hilfe


----------



## Oberchefe (12 November 2012)

> Wenn ich Bit 2 im ARRAY auf TRUE setze dann ist Bit 1 TRUE und alle anderen FALSE. Warum funktioniert es bei mir nicht?



Weil ein BOOL bei Codesys in Wirklichkeit 1 Byte belegt (wenn es sich nicht gerade um einen Eingang/Ausgang/Merker handelt).

BOOL-Arrays gehören von daher eigentlich verboten 

Kommen die über Modbus tatsächlich als BOOL Arrays an?


----------



## Majestic_1987 (14 November 2012)

Wenn das die Ursache WÄRE würde der Zeiger immer um 1 Byte inkrementiert und dann sollte sich diese Verschiebung auch erkennen lassen. Richtig ist, dass intern immer nur Bytes gespeichert werden. Eigentlich sollte der Compiler aber ein Array aus Bool auch entsprechend im Speicher allokieren.

überprüfen könnte man die These, wenn man die Ziel-Bits mal in den Merkerbereich an aufsteigend sortierte Adressen legt. Auch wenn ich Merker bei Codesys unsinnig finde XD

Und genaugenommen: Wenn es in einer Steuerung funktioniert MUSS es auch in ner anderen funktionieren. Das ist ja der Sinn einer Norm ;-)


----------

