Step 7 mehrere Bits zurücksetzen, wenn irgendein anderes in der Gruppe höher wird - Simatic S7-300 KOP/STL

silva.nrc

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

Ich brauche ein paar Tipps, um meinen Code ein wenig einfacher und einfacher zu machen, um ihn mit mehreren Variablen zu schreiben.

Ich muss alle Bits auf Low / 0 zurücksetzen, wenn eines der anderen Bits High / 1 wird.

Mit einer begrenzten Anzahl von Bits ist es einfach zu schreiben, aber in meinem Prozess spreche ich von mehr als 50 Bits, was den Code zu groß macht, so wie ich es in SCL getan habe.

Beispiel, wie es jetzt funktioniert.

Ich wäre dankbar, wenn jemand eine bessere Idee hätte. ( Simatic S7 - CPU 315-2 DP) Simatic S7)

Vielen Dank im Voraus.

Code:
// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 20.4 hoch ist.

      A     DB10.DBX   20.4

      R     DB10.DBX   21.4
      R     DB10.DBX   22.4
      R     DB10.DBX   23.4
      R     DB10.DBX   24.4
      R     DB10.DBX  25.4

// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 21.4 hoch ist.

      A     DB10.DBX   21.4

      R     DB10.DBX   20.4
      R     DB10.DBX   22.4
      R     DB10.DBX   23.4
      R     DB10.DBX   24.4
      R     DB10.DBX  25.4

// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 22.4 hoch ist.

      A     DB10.DBX   22.4

      R     DB10.DBX   20.4
      R     DB10.DBX   21.4
      R     DB10.DBX   23.4
      R     DB10.DBX   24.4
      R     DB10.DBX  25.4

// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 23.4 hoch ist.

      A     DB10.DBX   23.4

      R     DB10.DBX   20.4
      R     DB10.DBX   21.4
      R     DB10.DBX   22.4
      R     DB10.DBX   24.4
      R     DB10.DBX  25.4

// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 24.4 hoch ist.

      A     DB10.DBX   24.4

      R     DB10.DBX   20.4
      R     DB10.DBX   21.4
      R     DB10.DBX   22.4
      R     DB10.DBX   23.4
      R     DB10.DBX  25.4

// ALLE ANDEREN BIT ZURÜCKSETZEN, WENN 25.4 hoch ist.

      A     DB10.DBX  25.4

      R     DB10.DBX   20.4
      R     DB10.DBX   21.4
      R     DB10.DBX   22.4
      R     DB10.DBX   23.4
      R     DB10.DBX   24.4
 
Zuletzt bearbeitet von einem Moderator:
Hallo,
mich wundert, warum dieser Code funktioniert ?
Sobald DB10.DBX 20.4 true ist werden alle anderen dauerhaft auf false gesetzt egal was neues hinzukommt.
Wenn ich das richtig verstehe soll maximal 1 Bit True sein und ein anderes neue alle anderen zurücksetzen.
Da wirst du nicht drum rum kommen dir das alte Bit zu speichern. entweder du legst eine kopie aller bits ab oder wenns eh nur eins sein kann könnte man das auch mit einer zahl machen.

ich würde das auch in SCL machen nicht in AWL. Da bin ich aber raus was die Möglichkeiten von SCL in Step7 angeht. Ist zu lange her ...

grüße

Balu
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Kopiere Deine Bits in ein DWORD in der Reihenfolge, daß das Bit mit der höchsten Priorität an der niedrigsten Bitstelle liegt und das Bit mit der niedrigsten Priorität an der höchsten Bitstelle.

Dann brauchst Du nur noch das niedrigstwertige 1-Bit isolieren ( LeastBitOnly := (IN & -IN); ) und die Bits aus dem DWORD auf die Einzelbits zurückkopieren. Wenn Du mehr als 32 Bits brauchst, dann mache die Auswertung mit 2 DWORDs getrennt.

Code:
FUNCTION LeastBit_AWL : DWORD
TITLE =Das niedrigste 1-Bit isolieren
//LeastBitOnly := (IN & -IN);
AUTHOR  : PN_DP
NAME    : LBO
VERSION : 0.1

VAR_INPUT
  IN : DWORD ;
END_VAR
BEGIN
NETWORK
TITLE =LeastBitOnly := (IN & -IN);

      L     #IN ;
      PUSH ;
      NEGD ;
      UD ;
      T     #RET_VAL ;

END_FUNCTION

Harald
 
Das gleiche in SCL:
Code:
FUNCTION LeastBit_SCL : DWORD
TITLE ='Das niedrigste 1-Bit isolieren'
//LeastBitOnly := (IN & -IN);
AUTHOR  : PN_DP
NAME    : LBO
VERSION : '0.1'

VAR_INPUT
  IN : DWORD;
END_VAR

  LeastBit_SCL := IN AND DINT_TO_DWORD(-DWORD_TO_DINT(IN));

END_FUNCTION
 
Mit einer begrenzten Anzahl von Bits ist es einfach zu schreiben, aber in meinem Prozess spreche ich von mehr als 50 Bits, was den Code zu groß macht, so wie ich es in SCL getan habe.
Vielleicht schreibst du doch etwas mehr zu deinem Vorhaben und wie es genau werden soll.
Warum in deinem Beispiel immer nur das Bit x.4 ?
Was ist mit den anderen Bits der beteiligten Bytes ...?
 
Hello,
The application is quite nice, I use this bit to select a specific function, for example I can have up to 50 functions, which can include move conveyor to home position, move conveyor forward or backward.
This function shows me which function the operator has selected, then I can use a common screen button to perform all functions without creating multiple screens. (space problem)
Answering the question regarding the other missing bits!
they are for example the status of the particular function, for example conveyor is at home position, or the conveyor has reached the limit, out of the 8 available bits I use 7 as feedback and the "0.4" as function selection.
I hope my explanation is clear, otherwise I can try to give some better examples.

NRC
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So wie ich das sehe würde ich anstelle von Bits einen Integerwert verwenden. Jede gewünschte Funktion setzt einen anderen Wert. Dieser Wert wird dann verglichen und die gewünschte Funktion ausgewührt. Es ist doch viel einfacher bis 50+ zu zählen als 50+ Bits zurückzusetzen, wenn das 51. Bit gesetzt wird.
 
Natürlich könnte auch die Visualisierung beim Drücken eines Buttons mit der gewünschten Funktion zuerst alle Bits löschen (Doppelwörter mit 0 beschreiben) und dann das eine Bit setzen. Dann bräuchte es die Rücksetzlogik nicht in der SPS.
 
Code:
// Was soll der gezeigte BeispielCode aus Beitrag #1 machen?
// Alle X.4-Bits rücksetzen, wenn 20.4 TRUE ist ODER
// 21.4 TRUE ist ODER
// 22.4 TRUE ist ODER
// 23.4 TRUE ist ODER
// 24.4 TRUE ist ODER
// 25.4 TRUE ist?
// Z.B. so?

      O     DB10.DBX   20.4
      O     DB10.DBX   21.4
      O     DB10.DBX   22.4
      O     DB10.DBX   23.4
      O     DB10.DBX   24.4
      O     DB10.DBX   25.4
      R     DB10.DBX   20.4
      R     DB10.DBX   21.4
      R     DB10.DBX   22.4
      R     DB10.DBX   23.4
      R     DB10.DBX   24.4
      R     DB10.DBX   25.4
    
// Oder gilt die AbsichtsErklärung, die man "nur" in den Kommentaren erahnen kann,
// dass wirklich nur "ALLE ANDEREN" X.4-Bits rückgesetzt werden sollen, nicht jedoch das
// Bit, das das RückSetzen auslöst, weil es zufällig (?) das erste ist, das abgefragt wird?
// Falls es nicht so gemeint ist, was dann? Eins der X.4-Bits bleibt immer stehen, weil bzw.
// solange kein höherpriores Bit gesetzt ist bzw. gesetzt sein kann. Man wird beobachten können,
// warum Harald die scheinbar willkürliche PrioritätenVergabe hinzugefügt hat ... und, dass
// dies allein noch nicht die Lösung des Problems sein kann.
:unsure: Sorry, ich habe nicht verstanden, was der Code wirklich tun und wie er funktionieren soll.
Irgendwie scheint mir das noch nicht zu Ende gedacht zu sein ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Funkey,

Ich mag die Art und Weise, wie Sie das Problem sehen, ich bin nur verwirrt, wie ich vergleichen soll.
Mein Hauptanliegen ist es, um jeden Preis zu vermeiden, dass mehr als eine Funktion zur Ausführungszeit ausgewählt wird.
Ich stimme zu, dass die Verwendung von Integern viel einfacher und selbsterklärend wäre, nur nicht sicher, wie sichergestellt werden kann, dass nie mehr als eine aktivierte Funktion vorhanden ist.
 
Heinileini,

Denken Sie über jeden beschriebenen Bit bis als Spieler nach. [x.4]
20.4 ist Spieler Nummer eins.
21,4 ist Spieler Nummer zwei. usw.

Der Code sollte vermeiden, dass mehr als ein Spieler gleichzeitig läuft, so dass im Falle eines neuen Spielers automatisch jeder aktive Spieler in dieser Zeit entfernt wird.

Die Idee hinter der Logik ist sicherzustellen, dass ein neuer Spieler immer Vorrang hat.
 
Eigentlich kann der HMI-Bediener am HMI-Panel nicht gleichzeitig mehrere Buttons drücken, doch die Button-Bits könnten gleichzeitig in der SPS ankommen. Wenn man sicher sein will, daß nicht mehrere Funktionen gleichzeitig aktiviert werden können, dann könnte man eine Command-Variable als Int benutzen (wie funkey schon vorgeschlagen hat), und jeder Button am HMI schreibt eine unique Funktions-Nummer oder Button-Nummer als Zahl hinein - da kann nur eine Zahl drin stehen.

Oder man zeigt gar nicht erst so viele Buttons gleichzeitig am HMI an. Wieso könnte ein Bediener gleichzeitig mehrere Förderer bedienen? Wenn ich viele Förderer im HMI-Bild habe, dann erstelle ich nur einen Bediendialog (Faceplate) für alle Förderer gemeinsam, und arbeite mit Variablen-Multiplexen. Dann kann überhaupt nur ein Bediendialog für nur einen Förderer "gleichzeitig" auf dem Bild sichtbar sein. Alle Bedienbuttons und Anzeigen in dem Dialog arbeiten mit Multiplex-Variablen, und öffnen des Bediendialogs setzt die Multiplex-Indexvariable auf den Index des Förderers. Schließen des Dialogs setzt die Index-Variable auf 0. Die Index-Variable ungleich 0 steuert auch die Sichtbarkeit der Bildelemente des Bediendialogs.

Irgendwie ist es auch eine falsche Denkweise für SPS-Programmierung - da werden Bits logisch verknüpft, und nicht unliebsame Bits vorsichtshalber mit Reset-Orgien gelöscht. Bei echten Hardware-Bedientasten kann man ja auch nicht die gerade unerwünschten Tasten mechanisch blockieren oder "mit 'nem Hammer" 'rausklopfen.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ich bin nur verwirrt, wie ich vergleichen soll.
Den Wert in der Command-Variable nacheinander auf die Funktions-/Button-Nummer vergleichen:
Code:
L "DB_HMI".command
L 1
==I
= DB10.DBX20.4

POP    //command zurück in AKKU1
L 2
==I
= DB10.DBX21.4

...

POP
L 6
==I
= DB10.DBX25.4
am Ende des Codes ist höchstens ein Bit DB10.DBX...4 gesetzt

oder mit Sprungliste:
Code:
      L     "DB_HMI".command
      JL    LEND
      JU    LEND    //bei 0
      JU    CM01    //bei 1
      JU    CM02    //bei 2
      ...
      JU    CM06    //bei 6
LEND: JU    COMM

CM01: tue irgendwas
      JU    COMM

      ...

CM06: tue irgendwas
      JU    COMM

COMM: L     0
      T     "DB_HMI".command

Harald
 
@Funkey
Ich mag die Art und Weise, wie Sie das Problem sehen, ich bin nur verwirrt, wie ich vergleichen soll.
Mein Hauptanliegen ist es, um jeden Preis zu vermeiden, dass mehr als eine Funktion zur Ausführungszeit ausgewählt wird.
Ich stimme zu, dass die Verwendung von Integern viel einfacher und selbsterklärend wäre, nur nicht sicher, wie sichergestellt werden kann, dass nie mehr als eine aktivierte Funktion vorhanden ist.
Ich finde auch, dass dieser Vorschlag absolut sinnvoll ist und eine Mehrfach-Anwahl absolut ausschliesst.
Wenn du eine Button-Anwahl z.B. der Wert 3 (oder welcher auch immer) angewählt wird dann kann auch nur die Funktion 3 ausgeführt werden. Das muss dann natürlich ein Wert-Vergleich werden und kein Bit-Vergleich. Dies könnte man dann auch sehr schön mit SCL und dem CASE-Befehl umsetzen ...
 
Hallo,

Ich schätze die Ideen und Lösungen sehr, ich werde das eine Angebot von Harald ausprobieren, in der Zwischenzeit habe ich eine Simulation mit der Idee gemacht, die mir von FUNKEY gegeben wurde, und mit einigen anderen Ideen kompiliert, im Fall unten, sobald eine Funktion aktiviert ist, werde ich es tun Deaktiviere alle anderen im HMI, ich verstecke die Schaltflächen im Bildschirm, die werden nicht ausgewählt.


Network 1 - Aktive Funktion von HMI überwachen

O DB10.DBX 20.4 // funktion 1
O DB10.DBX 21.4 // funktion 2
O DB10.DBX 22.4 // funktion 3
O DB10.DBX 23.4 // funktion 4
O DB10.DBX 24.4 // funktion 5
O DB10.DBX 25.4 // funktion 6
O DB10.DBX 26.4 // funktion 7
= #einFunkIstAkt // // Mindestens eine Funktion ist aktiviert

Network 2 - Deaktivieren Sie die nicht aktive Funktion von der HMI


A #einFunkIstAkt // Mindestens eine Funktion ist aktiviert
= L 3.0
A L 3.0
AN DB10.DBX 20.4 // funktion 1
= DB10.DBX 20.5 // Deaktivierungstaste auf dem HMI 1
A L 3.0
AN DB10.DBX 21.4 // funktion 2
= DB10.DBX 21.5 // Deaktivierungstaste auf dem HMI 2
A L 3.0
AN DB10.DBX 22.4 // funktion 3
= DB10.DBX 22.5 // Deaktivierungstaste auf dem HMI 3
A L 3.0
AN DB10.DBX 23.4 // funktion 4
= DB10.DBX 23.5 // Deaktivierungstaste auf dem HMI 4
A L 3.0
AN DB10.DBX 24.4 // funktion 5
= DB10.DBX 24.5 // Deaktivierungstaste auf dem HMI 5
A L 3.0
AN DB10.DBX 25.4 // funktion 6
= DB10.DBX 25.5 // Deaktivierungstaste auf dem HMI 6
A L 3.0
AN DB10.DBX 26.4 // funktion 7
= DB10.DBX 25.5 // Deaktivierungstaste auf dem HMI 7
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Auch mit diesem Code kannst Du nicht verhindern, daß mehr als eine Funktion aktiviert wird. Weil zwischen dem Aktivieren einer Funktion und dem Sperren der Tasten für die anderen Funktionen wegen der Kommunikation Zeit vergeht, in der ein Bediener weitere noch nicht gesperrte Tasten drücken kann. Wie ich in #14 schon schrieb, ist das Deaktivieren der anderen unerwünschten Tasten keine Lösung. Dem SPS-Programm muß es grundsätzlich egal sein, ob HMI-Tasten zu ungünstiger Zeit gedrückt werden. Wenn garantiert nur eine Funktion aktiv sein darf, dann muß in der Funktionsumschaltung für alle Funktionen eine gemeinsame Variable verwendet werden, in der nur ein Wert drin stehen kann (z.B. eine Int-Variable). Dann findet das aktivieren einer Funktion und deaktivieren aller anderen Funktionen auch garantiert gleichzeitig statt. Die Tastenbits zum Anfordern einer Funktions-Aktivierung/Umschaltung und die Variable, wo die aktive Funktion drin steht, müssen verschiedene Variablen sein.

Außerdem mußt Du auch noch damit rechnen, daß die HMI-Kommunikation nicht im Zykluskontrollpunkt stattfindet (*), sondern Dein SPS-Programm unkoordiniert an irgendeiner Stelle unterbricht (Multitasking!). Deshalb dürfen die Variablen, die vom HMI beschrieben werden, nur einmal in der OB1-Task gelesen werden.
(*) S7-300: "priorisierte BuB-Kommunikation", S7-400/1200/1500 immer azyklisch zum OB1

Harald
 
Beispielcode für aktive Funktion mit HMI-Panel umschalten. Es kann nur eine Funktion gleichzeitig aktiv werden. Aktivieren einer anderen Funktion geht nur über vorheriges deaktivieren der aktiven Funktion (quasi über "0-Stellung"). So auch leicht in KOP/FUP programmierbar. Und leicht erweiterbar, z.B. verriegeln, wann eine Funktion aktiviert oder deaktiviert werden darf.
Code:
// Funktion 1 aktivieren
      U(
      L aktiveFunktion //Int-Variable mit der Nr der aktiven Funktion
      L 0
      ==I
      )
      U HMI_aktivieren_Fkt1 //Taste Funktion 1 aktivieren
      SPBN _001  //(KOP/FUP: SPBNB)
      L 1
      T aktiveFunktion
_001: SET        //(oder CLR, oder NOP 0 in KOP/FUP)

// Funktionen 2 .. 6 aktivieren (wie Funktion 1)
      ...

// Funktion 7 aktivieren (wie Funktion 1 .. 6)
      U(
      L aktiveFunktion
      L 0
      ==I
      )
      U HMI_aktivieren_Fkt7 //Taste Funktion 7 aktivieren
      SPBN _007
      L 7
      T aktiveFunktion
_007: SET

// aktive Funktion beenden/deaktivieren
      O HMI_deaktivieren_Taste1 //oder überhaupt nur eine HMI-Taste zum deaktivieren verwenden
      O HMI_deaktivieren_Taste2
      ...
      O HMI_deaktivieren_Taste7
      ON Hardware_deaktivieren_Taste //Hardware STOP-Taste (NC) falls HMI-Kommunik. ausfällt
      SPBN _000
      L 0
      T aktiveFunktion
_000: SET

// Anzeigen der aktiven Funktion am HMI
      L aktiveFunktion
      T HMI_aktiveFunktion

// falls auch einzelne Bits für die jeweils aktive Funktion benötigt werden
      L aktiveFunktion
      L 1
      ==I
      = DB10.DBX20.4
...
      L aktiveFunktion
      L 7
      ==I
      = DB10.DBX26.4

Harald
 
Hallo Harald,

vielen Dank, in meinen vorläufigen Tests hier funktioniert Ihre Idee großartig und ich kann einige andere Funktionen hinzufügen, ich weiß Ihre Hilfe wirklich zu schätzen. Nochmals vielen Dank für all Ihre Zeit in dieser Diskussion

Silva
 
Zurück
Oben