Digitale Ausgänge in Schleife schalten (ST)

majaestix

Level-2
Beiträge
39
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Zusammen,

bei folgendem Problem komme ich einfach nicht weiter, vielleicht hat hier noch jemand einen Tip für mich:

An einem CX9010 hängen via digitalen Ausgängen eine grössere (>60 Stk.) Stückzahl Relais. Nun suche ich nach einer Möglichkeit, diese Relais mit nur einem FB zu schalten, dem ich gerne den Namen des mit AT %Q zugewiesenen Ausgangs mitgeben möchte. Deshalb habe ich mir einen Record erstellt, der pro Relais die Ausgänge beschreibt. Diese Rec's stehen in einem Array[1..60]. Jetzt wollte ich den FB aufrufen und ihm durch Übergabe der entsprechenden Arrayadresse die passenden Werte zur Verfügung stellen. Das klappt auch soweit. Nur eben nicht mit dem Namen. Der Lösungsversuch mit POINTER TO BOOL endet immer in einem Laufzeitfehler, vermutlich wg. dem boolschen Wert und der Typumwandlung von BITADR. Mit PBOOL_TO_POINTER bin ich auch nicht weitergekommen.

Wie macht man sowas? Vielleicht sehe ich den Wald ja vor lauter Bäumen nicht mehr.

Bin für jeden Tip dankbar.

Gruss

Majaetix
 
Leg doch die Ausgänge auch als Array an.
Code:
OutPuts AT %Q*:ARRAY[1..60] OF BOOL;
Dann belegt zwar jeder Ausgang ein Byte im Ausgangsabbild, aber Speicher hat der CX9010 doch genug.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo StructuredTrash,

vielen Dank für die Antwort.

Leg doch die Ausgänge auch als Array an.

Dagegen spricht Verschiedenes, zu einem, es sind insgesamt über 700 Ausgänge, natürlich nicht alle digital, bereits angelegt, zum anderen, ich verliere dann die beschreibende Bezeichnung der Ausgänge (wurde bereits in einem anderen Thread hier diskutiert).

Meine Hoffnung war eigentlich, dass ich nicht der erste bin, der ein solches Problem hat und ich nur zu blöd bin, es über Pointer etc. zu lösen.
Ich dachte, dass vielleicht irgendjemand anderes bereits eine elegante Lösung dafür entwickelt hat und diese mit mir teilen würde.

Gruss

Majaestix
 
Eine Möglichkeit wären Alias-Variablen
Code:
Outputs AT %QB0:ARRAY[1..60] of BOOL;
Output1 at %QX0.0:BOOL;
Output2 at %QX1.0:BOOL;
usw...
Sonst vielleicht ein Array[1..60] mit Byteadressen und Bitpositionen der Ausgänge.
Code:
TYPE strBitAdrs:
STRUCT
   ByteAdr:POINTER TO BYTE;
   BitAdr:BYTE;
END_STRUCT
END_TYPE
 
Hallo StructuredTrash,

Danke für Dein Interesse.

Sonst vielleicht ein Array[1..60] mit Byteadressen und Bitpositionen der Ausgänge.

Genau hier, glaube ich, liegt mein Problem. Wenn ich einen Pointer auf eine BOOL zeigen lasse, welches Bit(s) muss ich bei der Dereferenzierung dann auswerten? Wie gesagt, pauschal mit PBOOL_TO_BOOL habe ich das nicht hinbekommen.

Gruss

Majaestix
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo StructuredTrash,

entschuldige bitte, ich habe gerade erst erkannt, dass Dein Pointer auf BYTE zeigt und nicht auf BOOL.
Wie könnte ich denn hier BOOL abbilden?

Gruss

Majaestix
 
Nehmen wir als Beispiel einen Ausgang AT %QX3.5
In das Adressarray muss dafür beim Programmstart eingetragen werden
Code:
OutAdr[1].ByteAdr:=ADR(%QB3);
OutAdr[1].BitAdr:=5;
In dem FB, dem die Adressen übergeben werden, kann man natürlich nicht direkt auf BOOLs zugreifen, sondern muss das Byte "OutAdr[x].ByteAdr^" mit "SHL(1,OutAdr[x].BitAdr)" maskieren, um das gewünschte Bit zu manipulieren oder abzufragen.
 
Hallo StructuredTrash,

nochmals: Maximalen Dank!

das gewünschte Bit zu manipulieren

Wie wäre denn ein BOOL zu maskieren, etwa mit 5, sowie Du es im Beispiel zeigst? Und falls ja, wieso mit 5 Bits und nicht als Byte?
Oder habe ich da was nicht verstanden?

Gruss

Majaestix
 
Zuviel Werbung?
-> Hier kostenlos registrieren
"AT %QX3.5" bedeutet, dass das Ausgangsbit sich an Position 5 innerhalb des Ausgangsbytes 3 befindet (Zählung mit 0 beginnend). Eine Bitadressierung in der Art "Integervariable.Bitposition" ist aber nur möglich, wenn "Bitposition" eine Konstante ist. Mit Variablen, wie bei der Übergabe in Deinen FB, geht das nicht. Da muss man dann das ganze Byte mit logischen Verknüpfungen wie AND, OR bearbeiten. Um dabei nur das gewünschte Bit zu manipulieren, ist eine Maskierung notwendig, und zwar mit einem Bytewert, bei dem nur an der gewünschten Bitposition eine 1 bzw. eine 0 steht. Im Besipiel wäre diese Maske 1 SHL 5, also 2#00100000. Um z. B. das Bit zu setzen, müsstest Du "Variable:=Variable OR (1 SHL 5)" ausführen, zum Rücksetzen "Variable":=Variable AND NOT (1 SHL 5)".
 
Hallo StructuredTrash,

Danke!

Jetzt fehlt mir nur noch die Bitmaskierung eines boolschen Ausganges. Kennst Du die?

Gruss

Majaestix
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo StructuredTrash,

es sei denn, ich hätte Dein Problem völlig falsch verstanden
Nein, das hast Du nicht! Ich hatte Dich nicht ganz verstanden :oops:

Sonst vielleicht ein Array[1..60] mit Byteadressen und Bitpositionen der Ausgänge.
Wenn ich das sauber mitgelesen hätte, wäre mit der Fauxpas nicht passiert.

Also fasse ich jetzt mal zusammen:
Alle digitalen Ausgänge in einem zweidimensionalen Array of Byte abbilden, heisst, jeder Ausgang liegt auf einem Bit eines Bytes dieses Arrays. Somit würe bei TRUE des Ausgangs das Bit gesetzt sein und bei FALSE das Bit fallen. Damit könnte ich durch das Array laufen und jeden Ausgang abfrsgen.
Was mit jetzt noch nicht klar ist, wie setzte ich den Ausgang wieder?

Gruss

Majaestix
 
Also fasse ich jetzt mal zusammen:
Alle digitalen Ausgänge in einem zweidimensionalen Array of Byte abbilden, heisst, jeder Ausgang liegt auf einem Bit eines Bytes dieses Arrays. Somit würe bei TRUE des Ausgangs das Bit gesetzt sein und bei FALSE das Bit fallen. Damit könnte ich durch das Array laufen und jeden Ausgang abfrsgen.
So ganz ist es das noch nicht. Ich bin von Folgendem ausgegangen:
Du willst in einer Schleife 60 mal einen FB aufrufen und ihm dabei, mit Hilfe des Schleifenzählers als Arrayindex, Variablen aus dem PLC-Ausgangsabbild übergeben. Diese Variablen sind bereits als einzelne Bitvariablen im Ausgangsabbild vorhanden.
Dazu brauchst Du ein ARRAY[1..60] OF POINTER TO BIT, in das Du beim Programmstart die Adressen der einzelnen Ausgangsvariablen einträgst. Da eine indizierte Bitadressierung nicht möglich ist, bleibt nur der Umweg über POINTER TO BYTE und die zusätzliche Angabe der Bitposition innerhalb des Bytes. Logische Operationen wie AND und OR sind dann natürlich auch nur byteweise möglich und müssen maskiert werden, um nur das gewünschte Bit zu manipulieren oder abzufragen.
Deine Zusammenfassung geht eher in die Richtung meines ersten Vorschlags, nämlich die Ausgangsvariablen von vornherein so anzulegen, dass sowohl ein Einzelzugriff über die Variablennamen als auch ein indizierter Zugriff über ein Array möglich ist.
 
Hallo StructuredTrash,

nochmals, ganz vielen Dank für Deine Geduld!

Ich bin von Folgendem ausgegangen:
Also, alles nochmal zurück auf Anfang: ;)

Merin Wunsch:
Verschiedene digitale Ausgänge mit dem gleichen FB schalten zu können.

Dazu hatte ich die folgende Vorgehensweise geplant:

Diese globalen Variablen sind definiert (Auszug):

VAR_GLOBAL
DG_STUDIO_NORD_TANK_SD_S3_21 AT %Q* : BOOL;
DG_STUDIO_NORD_TANK_SD_S3_22 AT %Q* : BOOL;
DG_STUDIO_NORD_TANK_SD_S3_23 AT %Q* : BOOL;
DG_STUDIO_NORD_TANK_SD_S3_24 AT %Q* : BOOL;
DG_STUDIO_NORD_TANK_SD_S3_25 AT %Q* : BOOL;

sd_haus_dg_studio_nord_bt_s21 : sd_rec;
sd_haus_dg_studio_nord_bt_s22 : sd_rec;
sd_haus_dg_studio_nord_bt_s23 : sd_rec;
sd_haus_dg_studio_nord_bt_s24 : sd_rec;
sd_haus_dg_studio_nord_bt_s25 : sd_rec;

sd_array : ARRAY[0..5,1..150] OF sd_rec;​
END_VAR

Die ertsen fünf wurden von den Elektrikern als Ausgäne im Systgemmanager angelegt, deshalb Ort und Kabelnummern. Soweit ich weiss, haben die diese Variablen gleich an die PLC als globale Var's übergeben.

Hier folgt die von mir angelege Structur, Typ REC:

TYPE sd_rec :
STRUCT​
var_name : POINTER TO BOOL;
status : BOOL;
stromlos_geschlossen : BOOL := TRUE;
status_alarm : alarm_rec;
max_einschaltdauer : max_einschaltdauer_rec;
END_STRUCT
END_TYPE

Sie enthält zwei weitere Struct's vom Typ REC, die aber hier keine weitere Rolle spielen.

Als erstes führe ich bei der Initialisierung des Programms den folgenden FB aus:

FUNCTION_BLOCK dg_aus_variablen_setzen

VAR_INPUT
END_VAR

sd_array[DG,24].var_name := BITADR(DG_STUDIO_NORD_TANK_SD_S3_24);

Damit erfolgt die Zuordnung des Ausgangs auf die Variable in meinem REC.
Nun wollte ich den Ausgang folgendermassen schalten:

FUNCTION_BLOCK sd_schalten

VAR_INPUT
ein_aus : BOOL;
etage : INT;
kabel : INT;
END_VAR

sd_array[Etage,Kabel].var_name^ := ein_aus;

Genau hier komme ich aber nicht weiter, dass funktioniert nämlich nicht :eek:

Irgendwas habe ich im Infosys gelesen, dass es hier Probleme geben kann, aber richtig begriffen habe ich das nicht...

Vielleicht kannst Du mich da auf die richtige Spur bringen?

Gruss

Majaestix
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn Du eine BOOL-Variable anlegst, ist das ein Byte, von dem nur das unterste Bit genutzt wird. Ein "POINTER TO BOOL" zeigt natürlich auch auf so eine Variable. Nur im I/Q-Abbild können BOOL-Variablen auf ein einzelnes Bit innerhalb eines Bytes zeigen. Die Typbezeichnung "BOOL" ist da etwas irreführend, es wäre besser gewesen, solche Variablen z. B. als Typ "BIT" zu bezeichnen. Eine indizierte Adressierung solcher Bitvariablen ist, wie schon gesagt, nicht möglich.
Eine Lösung könnte so aussehen (allerdings nicht getestet):
Den Typ von "var_name" im Struct ändern: Statt POINTER_TO_BOOL den von mir beschriebenen Typ strBitAdrs
Bei der Initialisierung (ich nehme mal Dein Beispiel):
Code:
sd_array[DG,24].var_name.ByteAdr:=ADR(%QB0)+SHR(BITADR(DG_STUDIO_NORD_TANK_SD_S3_24),3);
sd_array[DG,24].var_name.BitAdr:=BITADR(DG_STUDIO_NORD_TANK_SD_S3_24) AND 7;
Und im FB "sd_schalten"
Code:
IF ein_aus
THEN
   sd_array[Etage,Kabel].var_name.ByteAdr^:=sd_array[Etage,Kabel].var_name.ByteAdr^ OR SHL(BYTE#1,sd_array[Etage,Kabel].var_name.BitAdr);
ELSE
   sd_array[Etage,Kabel].var_name.ByteAdr^:=sd_array[Etage,Kabel].var_name.ByteAdr^ AND NOT SHL(BYTE#1,sd_array[Etage,Kabel].var_name.BitAdr);
END_IF
 
Hallo StructuredTrash,

Deine Antworten sind sehr anspruchsvoll, danke dafür. Ich ziehe mir das jetzt mal rein und melde mich, wenn ich es kapiert habe.

Gruss

Majaestix
 
Zurück
Oben