# IEC-61131 Pointer mit Index auf BOOL Variable



## Stussi (9 August 2007)

Habe mich in letzter Zeit mal mit der 3S Sofware beschäftigt und bin auf ein für mich noch nicht lösbares Problem gestoßen.
Ich möchte gerne mit einem Zeiger in einer BYTE oder WORD oder sonstwas Variablen auf die einzelnen Bits dieser Variablen zugreifen und mit einem Indexwert jedes einzelne Bit ansprechen können.
Ich habe es schon mit einem ARRAY OF BOOL hinbekommen, aber mit ner Normalen BYTE Variablen gehts irgendwie nicht.
Wollte dann das BYTE in ein ARRAY [0..7] OF BOOL schreiben, das geht aber auch nur total umstaendlich ueber Scheibebefehle usw. (Fehlermeldung war bei normalem move Befehl "Kann BYTE nicht in BOOL konvertieren "
Komme normalerweise aus der Siemenswelt und würde das dort mit einem Pointer machen, den ich dann bitweise hochzaehlen würde.
Hat einer von euch ne Idee wie man so etwas "einfaches" in IEC hinbekommen kann ?


----------



## JesperMP (9 August 2007)

Verwendest du ST (Structured Text) ?
Du hast ein Array von BYTEs oder WORDs und du willst die einzelne bits zugreifen. Was wäre es mit ein zweidimensionalen array ?


----------



## Stussi (9 August 2007)

*ST oder alles andere*

Ich verwende ST oder auch alles andere wenns nur geht.
Nein ich habe kein Array, das war nur ein Versuch von mir der aber super umständlich ist.
Ich versuch es mal in AWL-S7 zu zeigen.
Mein Wunsch war es (Sinn oder Unsinn mal dahingestellt) indirext auf ein einzelnes Bit einer BYTE, WORD oder sonst was Variablen zuzugreifen.

S7 Bsp.:

L P##Word        //Anfangsadresse des Variablen
LAR1                        //Adressregister geladen

u b[ar1,P#0.0]   //Nulltes Bit
= Signal

L 1
+AR1                     //Adressregister in Bit weitergesetzt

LOOP             // danach z.B Schleifen umlauf bis Ende WORD usw.


Wie kann ich sowas in IEC machen ?? Ohne ein ARRAY zu benutzen?
Es gibt ja ADR Befehle und auch POINTER sind möglich, doch immer wenn
ich darin was verändern will, streikt die PLC.


----------



## JesperMP (9 August 2007)

Dies ist also ein ganz klares job für IEC ST oder S7 SCL.
Ich habe keine ahnung von indirektes addresierung in IEC IL oder LD.
Ich kenne und hasse das indirekte addressierung in S7 STL.


----------



## Stussi (9 August 2007)

*Schade*

Schade, wollte mal ein bisschen mit diesem IEC spielen, muß dann wohl mal umdenken und anders programmieren. Vielleicht hat ja noch jemand ne Idee ansonsten erst mal danke Jesper. Und nen schönen Gruß nach Kopenhagen.


----------



## JesperMP (9 August 2007)

> Und nen schönen Gruß nach Kopenhagen.


Oh danke schön.

Warum willst du nicht mit IEC ST "spielen" ?
Bei S7 muss du dafür viel geld bezahlen. Bei CoDeSys kriegst du es umsonst.
Wenn es um arrays un indirekte addressierung handelt, ist ST (und SCL) 100x mehr produktiv.


----------



## Stussi (9 August 2007)

*ST ist nicht das Problem*

Ich schreib mal in ST was ich schon probiert habe oder wo ich hin will.

VAR
Zeiger= POINTER_TO_BOOL;   (*Zeiger auf das Byte*)
Wert = BYTE;  (*Byte aus dem gelesen werden soll*)
Index = INT;   (*Indexzeiger fuer Bitadresse*)
Start = BOOL;   (*Startsignal*)
Ergebniss = BOOL;    (*Ergebnissbit*) 
VAR_END

Zeiger:= ADR(Wert);

if Start=true
   Then
       for Index:=0 to 7 by 1 do     (*Index von 0 bit 7tes Bit durchgehen*)
          Ergebniss:= Zeiger^+Index;  (*BOOL Ergebniss aus Zeiger + Index*)
                if Ergebniss = true   (*Ergebniss OK dann Ende*)
                    Then RETURN
        END_FOR
END_IF    (*usw.*)


Sowas in der Art hatt ich eigendlich vor, aber das hochsetzten des POINTER und die Derefferenzierung des POINTER funktionieren so nicht.
Hab langsam keine Idee mehr wie man sowas machen kann.


----------



## JesperMP (9 August 2007)

Vergiess pointern ! Mit ST und arrays verwendet man indexe.
Hier ist ein beispiel von ein 2-dimensionalen array:


```
FUNCTION FC10 : INT
VAR_INPUT
  byteindex : INT ;
  boolindex : INT ;
  testvalue : BOOL ;
END_VAR
 
VAR_OUTPUT
  result : BOOL ;
END_VAR
 
VAR
  datas : ARRAY[0..100,0..7] OF BOOL ;
END_VAR ;
 
result:= (datas[byteindex,boolindex] = testvalue) ;
 
    FC10 := 100;
END_FUNCTION
```
Du siehst wo einfach es ist.
Das durchschleifen kannst du schnell hinzufügen.
"datas" kann auch ein extern definiertes block von variablen sein.


----------



## Stussi (9 August 2007)

*Na dann eben doch mit Array's*

Hm,

ok dann werde ich das mit den Array's mal versuchen, vielen Dank noch mal.
Will aber irgendwann noch mal rausfinden, was man mit den Pointer sonst noch so machen kann.
Wenn einer noch ne Idee hat bitte melden.
Bis die Tage mal.


----------



## zotos (9 August 2007)

Nun ja also in ST kann man auch viel machen.

Also nicht flexibel da eine Konstante wäre z.B. myByte.0 := TRUE; würde das niederwertigste Bit in der Variable myByte auf True setzen (in der Hilfe Bit-Adressierung).

Ich habe mal Funktionen gebaut um auf Einzelne Bits in (I,Q,M) Bytes zuzugreifen. Hier mal das Beispiel für Lesen von Input Bits:

myBool := get_IX(iByte:=ByteNummer, iBit:=BitNummer);

```
FUNCTION get_IX : BOOL
VAR_INPUT
    iByte        :INT;
    iBit        :INT;
END_VAR
VAR
    pStart    :POINTER TO BYTE ;
    pOffset   :POINTER TO BYTE ;
    pLese     :POINTER TO BYTE ;
    myByte    :BYTE ;
    forCount  :INT;
END_VAR

pStart := ADR(%IB0);
pOffset:= 0;
FOR forCount:=0 TO iByte - 1 DO
    pOffset:= pOffset +1;
END_FOR;
pStart := pStart + pOffset;
pLese  := pStart;
myByte := pLese^;
myByte := SHR(myByte,iBit);
get_IX := myByte.0;
```
Hier für Ausgangs Bits:
set_QX(iByte:=ByteNummer, iBit:=BitNummer, bValue:=BoolWert);

```
FUNCTION set_QX : BOOL
VAR_INPUT
    iByte        :INT;
    iBit        :INT;
    bValue  :BOOL;
END_VAR
VAR
    pStart    :POINTER TO BYTE ;
    pOffset   :POINTER TO BYTE ;
    pLese     :POINTER TO BYTE ;
    myByte    :BYTE ;
    forCount  :INT;
END_VAR

pStart := ADR(%QB0);
pOffset:= 0;
FOR forCount:=0 TO iByte - 1 DO
    pOffset:= pOffset +1;
END_FOR;
pStart := pStart + pOffset;
pLese  := pStart;
myByte := 0;

IF (bValue = TRUE) THEN
    myByte.0 := bValue;
    myByte := SHL(myByte,iBit);
    pLese^ := pLese^ OR myByte;
ELSE
    myByte.0 := NOT bValue;
    myByte := SHL(myByte,iBit);
    myByte := NOT myByte;
    pLese^ := pLese^ AND myByte;
END_IF
```


----------



## zotos (9 August 2007)

Ergänzend:
Die Problematik bei Bits ist das in CoDeSys ein BOOL (Speicher intern) als Byte gehandhabt wird. Sonst könnte man ganz einfach mit Pointern arbeiten:

```
(* Dieser Code kann nicht gehen!!! *)
VAR
  myByte  : BYTE;
  pMyByte : POINTER TO ARRAY[0..7] OF BOOL;
  aBool   : ARRAY [0..7] OF BOOL;
END_VAR

pMyByte := ADR(myByte);
aBool   := pMyByte^;
(* usw. *)
```



Stussi schrieb:


> Schade, wollte mal ein bisschen mit diesem IEC spielen, muß dann wohl mal umdenken und anders programmieren.
> ...



Ja da würde sich ein Umdenken Lohnen ;o) ich brauch die Funktion ein Bit n einer Variable zu manipulieren so gut wie nicht. Man arbeitet mit den Variablen und Strukturen. In speziellen Fällen kann man auch noch auf Merker zurückgreifen also die Variable mit "AT" in einem Merkerbereich speichern.

Für welche Anwendung musst Du denn mit Byte Variablen arbeiten wo man einzelne Bits drin ändert?


----------



## repök (9 August 2007)

*Extract*

Ich meine bei codesys gibts eine EXTRACT (so od. ähnlich) - Funktion. da kann mann dann einfach die Bit-Nummer angeben und schon ist das fertig.


----------



## zotos (9 August 2007)

```
[B]EXTRACT[/B] Eingänge dieser Funktion [URL="http://www.sps-forum.de/Die_Elemente_der_Bibliothek_Util_lib.htm"](util.lib)[/URL] sind ein DWORD X, sowie ein BYTE N.  Ausgegeben wird ein BOOL-Wert, der den Inhalt des N-ten Bits der Eingabe X  enthält, wobei mit dem nullten Bit zu zählen begonnen wird.
 Beispiele in ST:
 FLAG:=EXTRACT(X:=81, N:=4); 
  (* Ergebnis : TRUE, weil 81 ist binär 10[B]1[/B]0001, das 4. Bit also 1 *)
 FLAG:=EXTRACT(X:=33, N:=0); 
  (* Ergebnis : TRUE, weil 33 ist binär 10000[B]1[/B], das 0. Bit also 1 *)
```

Aber das setzen geht so nicht.


----------



## repök (9 August 2007)

Fürs setzen haben die auch eine funktion, ich meine PUT oder so??


----------



## zotos (9 August 2007)

repök schrieb:


> Fürs setzen haben die auch eine funktion, ich meine PUT oder so??



Ich lerne jeden Tag was neues ;o) beides habe ich noch nie benutzt.


```
[B]PUTBIT[/B] Die Eingabe dieser Funktion [URL="http://www.sps-forum.de/Die_Elemente_der_Bibliothek_Util_lib.htm"](util.lib)[/URL] besteht aus einem DWORD X, einem BYTE N und  einem BOOLschen Wert B.
 PUTBIT setzt das N-te Bit von X auf den Wert B, wobei mit dem  nullten Bit zu zählen begonnen wird
 Beispiel in ST:
 var1:=38;   (* binär 100110 *)
 var2:=PUTBIT(A,4,TRUE); (* Ergebnis: 54 = 2#1[B]1[/B]0110 *)
 var3:=PUTBIT(A,1,FALSE); (* Ergebnis: 36 =  2#1001[B]0[/B]0 *)
```


----------



## repök (9 August 2007)

schön das ich dem 61131-fönig auch mal was zeigen konnte :-D


----------



## Oberchefe (9 August 2007)

Mit SHL und OR bzw. AND kann man auch die Bits setzen oder auslesen, was anderes steckt warscheinlich in den util.lib auch nicht drin.


----------



## Stussi (10 August 2007)

*Schiebung und Stoßung *

Vielen Dank erstmal an dieser Stelle für Eure Mühen.
Sagte ja bereits, das Sinn oder Unsinn mal beiseite geschoben werden sollte. Es ging nur um die Frage, wie man in IEC einen Pointer manipulieren kann.
Die Sache mit dem schieben der einzelnen Bits auf die letzte Stelle zur Auswertung, hatt ich auch schon versucht aber fuer zu aufwendig befunden.
Das mit PUTBIT usw. muß ich mir mal genauer anschauen.
Warum sowas mal nötig wäre?
Na ja wenn ich von einem Byte, das fest auf den Merkerbereich gelegt ist, nur einzelne BIT's beschreiben will (z.B. Modbus komm oder was ähnliches) dann müßte ich bei der indirekten Bearbeitung 8 BIT-Variablen im Merkerbereich anlegen und um mit dem ARRAY Index zu arbeiten, eine ARRAY-Variable, die dann ebenfalls diesen Bereich beschreibt. Geht ja auch finde ich aber nicht so gelungen. Es schein aber so zu sein, das ich mich wohl an eine solche Vorgehensweise gewöhnen muß.


----------



## Schlusel (13 Dezember 2007)

zotos schrieb:


> Ergänzend:
> Die Problematik bei Bits ist das in CoDeSys ein BOOL (Speicher intern) als Byte gehandhabt wird. Sonst könnte man ganz einfach mit Pointern arbeiten:
> ....


In diesem Zusammenhang würde mich interessieren ob ich besispielsweise so adressieren könnte:


```
FUNCTION fClear :VOID                     
VAR_INPUT
    Adress_1        : POINTER TO BYTE;    (* Adresse Variable 1 (ADR) *)
    Size               : DINT;                (* Größe Variable 1    (SIZEOF) *)
END_VAR
VAR
    i                : DINT;                (* Schleifenzähler *)
END_VAR


fClear:=FALSE;
IF Size >0 THEN (* Überprüfen ob Variable mindestens 1 Byte groß *)
    FOR i:=1 TO Size DO
        Adress_1^:=0;
        Adress_1:= Adress_1 + 1;
    END_FOR
    fClear:=TRUE;
END_IF
```
.. reine Spielerei soweit, aber wenn ich beispielsweise auf eine Struktur zugreifen möchte, die ich im Vorfeld nicht kenne, die aber möglicher Weise so aussieht:

```
TYPE strTestVar :
 STRUCT
        T_Var_1            :DINT;
        T_Var_2            :DINT;
        T_Var_3            :UDINT;
        T_VAR_4            :ARRAY[1..3] OF BOOL;
    END_STRUCT
```
dann kann ich leider nicht *Pointer to strTestVar* nutzen, da ich den Namen im Vorfeld nicht kenne wenn ich ein universelles Tool schreiben will.
Wenn ich stattdessen *Pointer to Byte* nehme, läuft der Vorgang dann in einen ungewünschten Speicherbereich oder ist die Struktur grundsätzlich in Bytegröße? Auch wenn ich nur ein einzelnes Bit als Struktur habe?


----------



## J Schohaus (13 Dezember 2007)

Hallo 



> läuft der Vorgang dann in einen ungewünschten Speicherbereich oder ist die Struktur grundsätzlich in Bytegröße? Auch wenn ich nur ein einzelnes Bit als Struktur habe?


 
Ein BOOL in Codesys hat immer die Länge eines Byte!
( nur mit AT x.x zugewiesene BOOl nicht )

also
T_VAR_4 :ARRAY[1..3] OF BOOL;
benötigt z.B. 3 Byte

mfG Jochen


----------



## Schlusel (13 Dezember 2007)

Ok, danke Jochen,

ich hätte jetzt gedacht, dass die  
T_VAR_4 :ARRAY[1..3] OF BOOL;
ein Byte braucht.

Grüße
Sven


----------



## Werner29 (14 Dezember 2007)

*Ein paar Fakten zu Bits in CoDeSys*

Hallo,

eine kleine Zusammenfassung, einiges wurde schon gesagt:

1. Ein BOOL ist immer ein Byte gross es sei denn, es wird mit AT% explizit auf ein Bit gelegt.
2. Pointer zeigen immer auf Byte-Adressen. Bit-Pointer gibt es nicht! (d.h pointer + x schaltet den Pointer immer um x Bytes weiter). ADR(%M0.0) liefert einen Fehler.
3. Wenn man auf ein Bit in einem Wert zugreifen will kann man den Bitoperator verwenden, der funktioniert jedoch leider nur mit Konstanten : "dword.3". Insbesondere kann man nicht über die Bits eines Bytes iterieren.
4. In der Util.lib gibt es einige Funktionen zur Bitmanipulation:
"Extract" um ein Bit zu lesen
"Putbit" um ein Bit zu schreiben
"Pack" um 8 Bit zu einem Byte zusammenzufassen
"Unpack" um 8 Bit aus einem Byte zu extrahieren.

noch Fragen?

Bernhard


----------

