TC2: Überprüfen, ob nur ein Eingang gesetzt ist.

Beiträge
5.697
Reaktionspunkte
1.182
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich stehe gerade auf dem Schlauch.
Eine beliebige Anzahl boolscher Werte soll dahingehend überprüft werden, ob nur einer gesetzt ist. Meine Lösung wäre:

Code:
Ergebnis := (Eing1 OR Eing2 OR Eing3 … OR EingX) AND
(
(Eing1 AND NOT Eing2 AND NOT Eing3 … AND NOT EingX)
OR
[LEFT][COLOR=#222222][FONT=Verdana](NOT Eing1 AND Eing2 AND NOT Eing3 … AND NOT EingX)[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]OR[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana](NOT Eing1 AND NOT Eing2 AND Eing3 … AND NOT EingX)[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]...
OR[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana](NOT Eing1 AND NOT Eing2 AND NOT Eing3 … AND EingX)
)[/FONT][/COLOR][/LEFT]
Aber das geht doch sicher einfacher/eleganter, oder? Nur wie?

Gruß

Oliver
 
Hab selber eine andere Lösung gefunden, bin aber für andere Vorschläge offen.
Code:
[FONT=Verdana,Arial,Tahoma,Calibri,Geneva,sans-serif]TestErg := (BOOL_TO_INT(Eing1) + BOOL_TO_INT(Eing2) +BOOL_TO_INT(Eing3) + BOOL_TO_INT(Eing4)) > 1;[/FONT]
Es werden nicht so viele Eingänge sein, daher sollte diese Lösung reichen.
 
Hab selber eine andere Lösung gefunden, bin aber für andere Vorschläge offen.
Code:
[FONT=Verdana,Arial,Tahoma,Calibri,Geneva,sans-serif]TestErg := (BOOL_TO_INT(Eing1) + BOOL_TO_INT(Eing2) +BOOL_TO_INT(Eing3) + BOOL_TO_INT(Eing4)) > 1;[/FONT]
Deine Aufgabenstellung ist nicht vollständig formuliert. Deshalb hast Du nun zwei Lösungen, die verschiedene Ergebnisse liefern...
Deine Überschrift: Überprüfen, ob nur ein Eingang gesetzt ist
Deine Lösung: überprüft ob mehr als 1 Bit gesetzt ist
Welches Ergebnis soll kommen, wenn kein Bit gesetzt ist?

Es gibt 3 Fälle
- kein Bit gesetzt
- genau 1 Bit gesetzt
- mehr als 1 Bit gesetzt

Es gibt mehrere "uralte" Algorithmen, um zu prüfen, ob in einem WORD oder DWORD (wTest) höchstens 1 Bit gesetzt ist, z.B.

(A) schauen, ob der Wert eine Potenz von 2 ist (dann ist genau 1 Bit gesetzt)
Bit Twiddling Hacks: Determining if an integer is a power of 2
Code:
[COLOR="#008000"]//xResult ist true wenn höchstens 1 Bit gesetzt ist[/COLOR]
[COLOR="#008000"]//        und false wenn mehr als 1 Bit gesetzt ist[/COLOR]
xResult := (wTest AND (wTest - 1)) = 0;

(B) oder das niederwertigste (oder höchstwertige) Bit maskieren ("LeastBitOnly") und vergleichen ob das Ergebnis den selben Wert wie das ganze DWORD hat - dann ist nur höchstens ein 1-Bit enthalten (das maskierte).
Code:
[COLOR="#008000"]//xResult ist true wenn höchstens 1 Bit gesetzt ist[/COLOR]
[COLOR="#008000"]//        und false wenn mehr als 1 Bit gesetzt ist[/COLOR]
xResult := (wTest AND -wTest) = wTest;
Beide Algorithmen liefern auch bei wTest = 0 das Ergebnis TRUE !

(C) Wenn Du auf genau 1 Bit gesetzt prüfen willst, dann mußt Du noch den Spezialfall wTest = 0 behandeln, z.B.
Code:
[COLOR="#008000"]//xResult ist true wenn genau 1 Bit gesetzt ist[/COLOR]

IF wTest = 0 THEN
  xResult := 0;
ELSE
  xResult := (wTest AND -wTest) = wTest;
END_IF;

[COLOR="#008000"]//oder ohne IF[/COLOR]
xResult := wTest <> 0 AND ((wTest AND -wTest) = wTest);

Mit Twincat kenne ich mich nicht aus, möglicherweise braucht man für den Twincat-ST-Compiler auch noch Typecasts, und insbesondere überprüfe den Code mit Fällen, wo das höchste Bit (.31) gesetzt ist z.B. wTest = 16#80000000
Code:
VAR
  wTest : DWORD;
  xResult : BOOL;
END_VAR

[COLOR="#008000"]//xResult ist true wenn höchstens 1 Bit gesetzt ist[/COLOR]
[COLOR="#008000"]//        und false wenn mehr als 1 Bit gesetzt ist[/COLOR]
xResult := (wTest AND DINT_TO_DWORD( -DWORD_TO_DINT(wTest) )) = wTest;

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,
Deine Aufgabenstellung ist nicht vollständig formuliert. Deshalb hast Du nun zwei Lösungen, die verschiedene Ergebnisse liefern...
Deine Überschrift: Überprüfen, ob nur ein Eingang gesetzt ist
Deine Lösung: überprüft ob mehr als 1 Bit gesetzt ist
Welches Ergebnis soll kommen, wenn kein Bit gesetzt ist?

Es gibt 3 Fälle
- kein Bit gesetzt
- genau 1 Bit gesetzt
- mehr als 1 Bit gesetzt
Es darf maximal einer der Boolschen Eingänge TRUE sein, keiner TRUE ist auch OK.
Nachtrag: Mist, habe gerade gesehen, dass meine erste Lösung gar nicht das macht was ich möchte, danke für den Hinweis.
 
Zuletzt bearbeitet:
Es darf maximal einer der Boolschen Eingänge TRUE sein, keiner TRUE ist auch OK.
Dann empfehle ich meine Variante (B) (bzw. die Letzte, falls Twincat das so braucht)

Da kannst Du bis zu 32 Bits in ein DWORD kopieren und dann testen.
Oder vielleicht liegen die Bits schon so, daß man sie als DWORD ansprechen kann? Die nicht auszuwertenden Bits kann man einfach mit "wMyWord AND wBitMaske" ausblenden/ausmaskieren.

Harald
 
Tach.

Da du die Eingänge wahrscheinlich ja eh umkopieren musst, warum dann nicht in ein Bool Array und dann mit einer Schleife darüber die Anzahl der gesetzten Eingänge zählen?
Dann kannst auch individuell für jede Anzahl etwas machen und bist auch nicht begrenzt in der Anzahl der Eingänge.

Hando0815
 
Zuviel Werbung?
-> Hier kostenlos registrieren
mit einer Schleife darüber die Anzahl der gesetzten Eingänge zählen
Zum Glück muß SPS-Software heutzutage nicht mehr effizient und durchdacht programmiert werden. ;) Bei Code, der 100 mal langsamer als ein effizienter Code ist, kann man ja eine stärkere SPS fordern ... Oder die SPS langweilt sich eh schon und ist froh, ordentlich was zu tun zu bekommen ;)

Harald
 
Zum Glück muß SPS-Software heutzutage nicht mehr effizient und durchdacht programmiert werden. ;) Bei Code, der 100 mal langsamer als ein effizienter Code ist, kann man ja eine stärkere SPS fordern ...

Ich gebe zu, dass eine Schleife und zählen, mein erster Gedanke bei dem Problem war. Den Faktor 100 halte ich für deutlich übertrieben. Der Faktor 20 wäre mir aber ein gut lesbares Programm wert. Zumal damit zu rechen ist, dass es morgen auf den Vergleich von 4 „Einsen“ geändert werden soll… :ROFLMAO:
 
Den Faktor 100 halte ich für deutlich übertrieben. Der Faktor 20 wäre mir aber ein gut lesbares Programm wert.
Grob geschätzt: die Schleife hat dreimal so viel Code wie die Formel mit (D)Word, und muß für 32 Bits 32 mal ausgeführt werden.

Genaues Beispiel S7-300 SCL (ich habe kein Codesys und kein Twincat)
(wTest ist DWORD, xArray ist ARRAY[0..31] OF BOOL):
Code:
[COLOR="#008000"]//xResult ist true wenn höchstens 1 Bit gesetzt ist[/COLOR]
[COLOR="#008000"]//        und false wenn mehr als 1 Bit gesetzt ist[/COLOR]
xResult := (wTest AND DINT_TO_DWORD( -DWORD_TO_DINT(wTest) )) = wTest;
Der SCL-Compiler erzeugt 7 AWL-Anweisungen, Codegröße 22 Bytes

Code:
[COLOR="#008000"]//xResult ist true wenn höchstens 1 Bit gesetzt ist[/COLOR]
[COLOR="#008000"]//        und false wenn mehr als 1 Bit gesetzt ist[/COLOR]
zaehler := 0;
FOR i := 0 TO 31 DO
  IF xArray[i] THEN
    zaehler := zaehler + 1;
  END_IF;
END_FOR;
xResult := zaehler <= 1;
Der SCL-Compiler erzeugt 29 AWL-Anweisungen (Codegröße 142 Byte), wovon 22 Anweisungen (118 Byte) 32 mal ausgeführt werden.
Insgesamt müssen 711 Anweisungen (3824 Byte Code) ausgeführt werden. (Ausführungszeit habe ich nicht gemessen)

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Na, zum Glück muss man für die meisten modernen Steuerungen keine 400€ mehr für eine 32kB Speicherkarte berappen.
Übrigens, die Effizienz von Programmcode an der Größe des Textes im Editor fest zu machen, ist dann doch etwas zu simpel gedacht... (Der Compiler hat da immer noch ein Wörtchen mit zu reden)

Solange wir hier nicht von Arraygrößen jenseits der 10.000 Elemente oder von Zykluszeiten <1ms reden. Sollte die Übersichtlichkeit, Nachvollziehbarkeit und evtl. Erweiterbarkeit des Codes mehr im Vordergrund stehen.

Ist die Lösung mir der Schleife die effizienteste? Sicherlich nicht! Kann man sie in Zukunft beliebig erweitern? Auf jeden Fall!
 
Übrigens, die Effizienz von Programmcode an der Größe des Textes im Editor fest zu machen, ist dann doch etwas zu simpel gedacht... (Der Compiler hat da immer noch ein Wörtchen mit zu reden)
Stimmt, ob die Schleife 1-mal oder 10.000-mal durchlaufen wird, hat praktisch keinen Einfluss auf den PlatzBedarf des Code im QuellText.
Und gerade das verleitet schon mal dazu, den Einfluss auf die Laufzeit zu übersehen oder zumindest zu unterschätzen.
Da Harald den PlatzBedarf in Anzahl AWL-Befehle und in Anzahl Byte in dieser Befehle "umgerechnet" hat, kann man zumindest ihm nicht vorwerfen, die Länge des QuellTextes als MassStab genommen zu haben.
 
Zurück
Oben