# VAR_IN_OUT mit Merker



## Blockmove (14 August 2011)

Hallo Zusammen,

ich bin gerade dabei mich in Codesys und Modbus einzuarbeiten.
Dabei bin ich auf ein Problem gestossen:

An einem FB habe ich 2 Boolsche Variablen (IPS_AUF,IPS_AB) als IN_OUT definiert.


```
FUNCTION_BLOCK Schalten
VAR_INPUT
    Taster_Auf :BOOL;
    Taster_Ab :BOOL;
 
END_VAR
VAR_OUTPUT
    S1: BOOL;
    S2: BOOL;
END_VAR
VAR
    t1:TP;
    t2:TP;
END_VAR
VAR_IN_OUT
    IPS_Auf: BOOL;
    IPS_Ab:  BOOL;
END_VAR
```
Auf diese Variablen will ich per Modbus lesend und schreibend zugreifen.
Deshalb sind sie als globale Variablen (Merker 0.0 und 0.1) definiert


```
Taster1 AT %IX0.2: BOOL;
    Taster2 AT %IX0.3: BOOL;
    Modbus_Bit0 AT %MX0.0 : BOOL;
    Modbus_Bit1 AT %MX0.1 : BOOL;
    Auf :BOOL;
    Ab: BOOL;
```
Beim Aufruf des FB 


```
CAL        fbSchalten(
    Taster_Auf:= Taster1,
    Taster_Ab:= Taster2,
    IPS_Auf:= Modbus_Bit0,
    IPS_Ab:= Modbus_Bit1,
    S1=> Auf,
    S2=> Ab)
```
Erhalte ich die Fehlermeldung


```
Fehler 4060: Test (5): 'VAR_IN_OUT' Parameter 'IPS_AB' von 'SCHALTEN' benötigt Varibale mit Schreibzugriff als Eingabe
```
Ich weiss, dass an In-Out-Parameter die Variable als Zeiger übergeben wird, aber wieso funktioniert das Ganze nicht mit Merkern?
Gibts dafür eine einfache Lösung / Workaround?

Als Steuerung kommt eine Wago 750-841 zum Einsatz.

Besten Dank!

Gruß
Dieter (Codesys - Neuling)


----------



## mac203 (15 August 2011)

Hallo Dieter,

warum sollen die Variablen denn überhaupt als VAR_IN_OUT deklariert werden?
Üblicherweise übergibt man nur besonders Große Variablen per Zeiger an einen Baustein.
Die AT%MB Variablen würde man eher GLOBAL deklarieren und hätte somit lesenden und schreibenden Zugriff aus jeder Instanz des Bausteins.

Gruß,
Marco


----------



## Blockmove (15 August 2011)

mac203 schrieb:


> Hallo Dieter,
> 
> warum sollen die Variablen denn überhaupt als VAR_IN_OUT deklariert werden?
> Üblicherweise übergibt man nur besonders Große Variablen per Zeiger an einen Baustein.
> ...


 
Der Zustand von IPS_Auf und IPS_Ab wird zuerst im FB abgefragt und dann ggf. verändert. Deshalb eine Deklaration als IN_OUT.
Die Variablen sind Global deklariert. Nur ist mein Problem, dass sobald ich diese Variablen mit AT auf einen Merker lege, ich die Fehlermeldung bekomme. Verwende ich die Variablen als "normale" globale Variablen (ohne Merker) funktioniert alles wie erwartet.

Gruß
Dieter


----------



## Thomas_v2.1 (15 August 2011)

Bei Codesys gibt es Unterschiede zwischen bool'schen Variablen im Merkerbereich und im Variablenbereich eines Bausteins.
Siehe hier:
http://spsforum.com/showthread.php?p=249322

Ich finde das auch äußerst unpraktisch. Gerade wenn man die Merker für Modbus-Kommunikation benötigt.
Ich denke du wirst die Daten einmal im Programm als Variablen anlegen müssen, und dann nochmal separat auf den Merkerbereich umkopieren.


----------



## mac203 (15 August 2011)

Blockmove schrieb:


> Der Zustand von IPS_Auf und IPS_Ab wird zuerst im FB abgefragt und dann ggf. verändert. Deshalb eine Deklaration als IN_OUT.
> Die Variablen sind Global deklariert. Nur ist mein Problem, dass sobald ich diese Variablen mit AT auf einen Merker lege, ich die Fehlermeldung bekomme. Verwende ich die Variablen als "normale" globale Variablen (ohne Merker) funktioniert alles wie erwartet.
> 
> Gruß
> Dieter



Hallo Dieter,

in diesem Fall muss ich Dir recht geben. Das funktioniert so auch nicht.
Die VAR_IN_OUT Klasse ist "eigentlich" ein automatische Zeigerklasse, in der ich mich nicht um Referenzierung und Dereferenzierung kümmern muss.

Warum soll denn überhaupt über diese Zeigerklasse der Wert geprüft werden, wenn ich doch diese Variablen auch als VAR_INPUT übergeben und anschlißend auf die GLOBALE Variable intern aus dem Baustein schreibe oder sonstiges?

Gruß,
Marco


----------



## StructuredTrash (15 August 2011)

Wenn die Bits im Merkerbreich nicht unbedingt gepackt werden müssen, könnte man die Variablen als Bytes anlegen und im FB in der Form "Var.0" darauf zugreifen. So bliebe der FB mehrfach instanziierbar, das Datenaufkommen bei der ModBus-Kommunikation würde allerdings steigen.


----------



## RobiHerb (16 August 2011)

*Compiler Problem*

Das ganze ist (nicht nur) ein Compiler Problem.

Die darunter liegende Processor Struktur (8,16,32 Bit) kann normalerweise nur auf Bytes als kleinste Einheit zugreifen. Die declarierten Vars sind aber Bool, wobei 8 Bool in der SPS Umgebung in ein Byte passen. (Auf PC werden BOOL sehr oft als INT 0=FALSE, alles andere TRUE implementiert).

Zeiger sind Adressen im Speicherbereich des Processors. Somit sind Codesys IN_OUT Variablen vom Typ Bool erst einmal nur in der Lage auf ein Byte zuzugreifen , dieses Byte zu "Locken", die Bitmanipulationen durchzuführen, rückspeichern und wieder freigeben. Diese Manipulationen müssen Processor unabhängig implementiert werden, sonst müssten die Entwickler von Codesys immer wieder das Rad neu entwickeln, wenn ein neuer Kunde mit neuer Hardware kommt.

Jetzt kommt der Aufruf des FB. Innnerhalb dieses FB ist "vergessen" was die Variablen aussen darstellen, hier insbesondere Variable auf festen Adressen. Der Entwickler des FB könnte ja auf den Gedanken kommen, nicht nur auf die Adresse lesend oder schreibend zuzugreifen sondern auch Zeiger Arithmetik zu betreiben...

In moderneren Sprachen gibt es deshalb CONST auch auf Zeiger, wobei man zusätzlich durch die Position des CONST vor oder hinter dem Namen der Variablen festlegen kann, ob der Zeiger nicht verändert werden kann oder ob der Wert, auf den der Zeiger zeigt, fix ist.

Natürlich hätte man auch den Compiler so auslegen können, wie BlockMove es gerne gehabt hätte, aber das würde ihn unnötig kompliziert machen.

Vergesst nie, ST ist 30 Jahre alt, eigentlich ein von der zu akademischen Lehrzwecken entwickelten Sprache Pascal abgeleiteter Dialekt, die nie für Bit Manipulationen und die heutige Rechenpower gedacht war.


----------



## Blockmove (16 August 2011)

RobiHerb schrieb:


> Natürlich hätte man auch den Compiler so auslegen können, wie BlockMove es gerne gehabt hätte, aber das würde ihn unnötig kompliziert machen.
> 
> Vergesst nie, ST ist 30 Jahre alt, eigentlich ein von der zu akademischen Lehrzwecken entwickelten Sprache Pascal abgeleiteter Dialekt, die nie für Bit Manipulationen und die heutige Rechenpower gedacht war.



Mal abgesehen, dass es bei Siemens problemlos geht, hat es nichts mit ST an sich zu tun. Es funktioniert in KOP/FUP/AWL genauso wenig.

Das Verhalten lässt sich wohl auf bestimmten Plattformen / Steuerungen einstellen.
In den Zielsystemeinstellungen von Codesys gibt des Punkt "VAR_IN_OUT als Referenz". Nur leider ist der auf meiner Wago 750-841 "ausgegraut".

Naja, wenn man das Verhalten kennt, ist ja nicht sonderlich schwer einen Workaround zu programmieren.

Besten Dank für eure Antworten

Gruß
Dieter


----------



## Thomas_v2.1 (16 August 2011)

RobiHerb schrieb:


> Die darunter liegende Processor Struktur (8,16,32 Bit) kann normalerweise nur auf Bytes als kleinste Einheit zugreifen. Die declarierten Vars sind aber Bool, wobei 8 Bool in der SPS Umgebung in ein Byte passen. (Auf PC werden BOOL sehr oft als INT 0=FALSE, alles andere TRUE implementiert).
> 
> Zeiger sind Adressen im Speicherbereich des Processors. Somit sind Codesys IN_OUT Variablen vom Typ Bool erst einmal nur in der Lage auf ein Byte zuzugreifen , dieses Byte zu "Locken", die Bitmanipulationen durchzuführen, rückspeichern und wieder freigeben. Diese Manipulationen müssen Processor unabhängig implementiert werden, sonst müssten die Entwickler von Codesys immer wieder das Rad neu entwickeln, wenn ein neuer Kunde mit neuer Hardware kommt.



Die Beckhoff Kiste hier bei mir auf den Tisch hat sogar echte Bitzugriffsfunktionen (C165 16-Bit Controller). Also könnte man dort auch ein BOOL als Variable die wirklich nur ein Bit benötigt darstellen.
Allerdings besitzen die Bit-Operationen keinen indirekten Addressierungsmodus, was bedeutet dass man hierauf keinen Zeiger bilden kann.
Bei meiner Steuerung könnte ich mir das mit den Merkern also mit dem Adressierungsmodus erklären, weil nur diese als echte Bit Variablen im Speicher abgelegt sind (VAR_IN_OUT als Zeiger geht also nicht).

Warum das aber auf Architekturen wie z.B. x86 die gar keine Bit-Operatoren besitzen auch so ist, kann ich mir nicht erklären. Wenn dort die Merkerbits auch nur einzelne Bits sind, würde das ja bedeuten dass ich bei jedem Bitzugrif per ausmaskieren darauf zugegriffen wird.

Was du mit "Locken" meinst ist mir auch nicht ganz klar. Wenn man jetzt auf Assembler-Ebene heruntergehe, benötigt ich sowas nur wenn auf Variablen aus verschiedenen Interrupts zugegriffen wird. Und dann ist es auch nur bei allen nicht atomaten Zugriffen notwendig. Man macht doch nicht pauschal alle Variablenzugriffe sicher, dann kommt der Prozessor zu sonst ja nichts mehr.

Leider ist das bei Codesys viel Spekulation, da über die Internas nicht viel zu erfahren ist. Ich habe mal versucht das Intel-Hex File welches beim Übersetzen erstellt wird in einen C16x Disassembler zu laden, aber das Format scheint nicht ganz Standarkonform zu sein. Ich habe aber auch nicht weiter nachgeforscht, so wichtig wars mir dann doch nicht.


----------



## RobiHerb (20 August 2011)

*Etwas zu den Internas*



Thomas_v2.1 schrieb:


> ...
> 
> Leider ist das bei Codesys viel Spekulation, da über die Internas nicht viel zu erfahren ist. Ich habe mal versucht das Intel-Hex File welches beim Übersetzen erstellt wird in einen C16x Disassembler zu laden, aber das Format scheint nicht ganz Standarkonform zu sein. Ich habe aber auch nicht weiter nachgeforscht, so wichtig wars mir dann doch nicht.



Codesys wurde zuerst in C geschrieben. Später in C++, wie wohl die meisten Module von 2.x.

Ab 3.x wird sehr viel in C# erledigt, gelegentlich wird auch Basic in .NET Umgebung eingesetzt, wenn Kunden diese Module beistellen. .NET ist auch ein Grund dafür, dass 3S mit einer Portierung nach Linux nicht voran kommt.

Grosse Teile der Libraries sind in Codesys ST entwickelt worden.


----------



## Thomas_v2.1 (20 August 2011)

RobiHerb schrieb:


> Codesys wurde zuerst in C geschrieben. Später in C++, wie wohl die meisten Module von 2.x.
> 
> Ab 3.x wird sehr viel in C# erledigt, gelegentlich wird auch Basic in .NET Umgebung eingesetzt, wenn Kunden diese Module beistellen. .NET ist auch ein Grund dafür, dass 3S mit einer Portierung nach Linux nicht voran kommt.
> 
> Grosse Teile der Libraries sind in Codesys ST entwickelt worden.



Was meinst du mit in C bzw. C++ geschrieben? Worin die Codesys Software geschrieben ist, ist mir eigentlich relativ egal. Mir gehts dabei um den SPS Code.
Ich weiß nicht ob es so funktioniert, aber der einfachste Weg einen ST Compiler zu erstellen wäre wohl erst von ST nach C zu übersetzen und dann einen handelsüblichen C-Compiler darauf loszulassen.
Das wäre für Codesys Seite auch viel einfacher, denn dann hätte die nur einen Übersetzer von ST nach C, und für die verschiedene Zielhardware kaufen sie einfach fertige Compiler zu.


----------



## Werner29 (23 August 2011)

Thomas_v2.1 schrieb:


> Was meinst du mit in C bzw. C++ geschrieben? Worin die Codesys Software geschrieben ist, ist mir eigentlich relativ egal. Mir gehts dabei um den SPS Code.
> Ich weiß nicht ob es so funktioniert, aber der einfachste Weg einen ST Compiler zu erstellen wäre wohl erst von ST nach C zu übersetzen und dann einen handelsüblichen C-Compiler darauf loszulassen.
> Das wäre für Codesys Seite auch viel einfacher, denn dann hätte die nur einen Übersetzer von ST nach C, und für die verschiedene Zielhardware kaufen sie einfach fertige Compiler zu.


Nein, so läuft es nicht. Würde wir fertige C-Compiler zukaufen, dann müsste der Endkunde die Lizenz dafür bezahlen. Also jeder, der jetzt CoDeSys kostenlos installiert. Aber davon abgesehen hat es Riesenvorteile, einen eigenen Compiler für jede Zielplattform zu schreiben. Und genau das machen wir. Das ist zwar ein einmaliger Aufwand um den Compiler zu schreiben, aber dafür hat man danach viel bessere Möglichkeiten um Online Change zu realisieren, für Monitoring, Powerflow, Breakpoints etc.
Hat aber mit dem Problem nichts zu tun.



> Warum das aber auf Architekturen wie z.B. x86 die gar keine Bit-Operatoren besitzen auch so ist, kann ich mir nicht erklären. Wenn dort die Merkerbits auch nur einzelne Bits sind, würde das ja bedeuten dass ich bei jedem Bitzugrif per ausmaskieren darauf zugegriffen wird.



Genau das ist das Problem. Wie sollte es denn anders sein? Wenn du mit MB0 auf das 0te Byte zugreifst, willst du ja alle Bits von MX0.0 bis MX0.7 bekommen. Natürlich ist das für alle Prozessoren dieser Welt ein Performanceproblem und dann kannst du dir auch vorstellen, warum ein BOOL der nicht auf einer direkten Adresse liegt, anders behandelt wird. Und dann sollte auch klar sein, warum es keine Pointer (und VAR_IN_OUT) auf Bits gibt.


----------

