Bitfeld - "rechtestes" Bit kopieren

FrankTheTank

Level-1
Beiträge
41
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo allerseits!

Ich werde gerade narrisch bei dem Versuch, eine Funktion zu schreiben, welche mir aus einem DWORD das Bit, das am weitesten rechts steht rauszusuchen und mir ein DWORD erzeugt, das nur ein Bit, genau an dieser Stelle hat.

Code:
DB60.selected_event1 := 0;
DB60.selected_event2 := 0;

FOR index := 0 TO 31 BY 1 DO
        IF (DB60.occ_events1 AND SHL(IN := DWORD#16#0000_0001, N := index)) <> 0 THEN
            DB60.selected_event1 := SHL(IN := DWORD#16#0000_0001, N := index);
        END_IF;
    
        IF (DB60.occ_events2 AND SHL(IN := DWORD#16#0000_0001, N := index)) <> 0 THEN
            DB60.selected_event2 := SHL(IN := DWORD#16#0000_0001, N := index);
        END_IF;
END_FOR;
In "occ_eventsX" stehen ein paar Bits drin. Jetzt will ich ein DWORD, dass nur das Bit enthält, welches am weitesten rechts steht. Was ist an dieser Funktion falsch?
Ich schiebe doch die 1 von rechts nach links, und sobald in "occ_eventsX" auch eine 1 steht, dann speicher ich die geschobene 1 in "selected_eventX". Leider klappt das nicht.

Nun hab ich mit dem Variablen beobachten/steuern vom Simatic ein wenig rumgefummelt und es hat sich herausgestellt, dass er mir das Bit, dass am weitesten LINKS steht speichert. Das habe ich doch aber nicht programmiert! :!:

Weiss jemand, was da schief läuft?

mfg,
Frank
 
du mußt nach dem ersten vorkommen die schleife verlassen, also entweder für jedes wort jeweils eine schleife oder eine zusätzliche boolsche variable pro wort "bit bereits gefunden"...
 
Ja, genau daran lags. Manchmal sieht man den Wald vor Bäumen nicht mehr. :D Danke

ich behaupte, dass hier ist schneller als deine variante:

Code:
*
FUNCTION FC20 : DWORD
VAR_INPUT
    dIn : DWORD;
END_VAR
VAR_TEMP
    dTemp : DINT;
    iI1 : INT;
    iI2 : INT;
END_VAR

    dTemp := DWORD_TO_DINT(dIn);
    
    FOR iI1 := 0 TO 31 BY 1 DO
        
        IF ((dTemp MOD 2) > 0) THEN            
            FC20 := DINT_TO_DWORD(REAL_TO_DINT(2**iI1));                       
            RETURN;  
        ELSE
            dTemp := dTemp / 2;          
        END_IF;
        
    END_FOR;
    
    FC20 := 0;
    
END_FUNCTION
 
Zuletzt bearbeitet:
Hallo ihr,
die Variante des TE wäre m.E. sinnvoller, wenn in der Schleife der Index IMMER fest auf 1 stehen würde (wenn an Stelle der Konstanten eine Variable verwendet wird - also so :
Code:
FOR index := 0 TO 31 BY 1 DO
        IF (DB60.occ_events1 AND SHL(IN := myDWordVar, N := 1)) <> 0 THEN
            DB60.selected_event1 := SHL(IN := myDWordVar, N := 1);
        END_IF;
 
        IF (DB60.occ_events2 AND SHL(IN := myDWordVar, N := 1)) <> 0 THEN
            DB60.selected_event2 := SHL(IN := myDWordVar, N := 1);
        END_IF;
END_FOR;

die Variante von 4L sieht sehr viel schöner aus - hat aber den bitteren Beigeschmack, dass bei der Funktion "**" mit einer REAL-Zahl gearbeitet wird und damit den daraus resultierenden Nachteilen bezüglich Wandlungs-Ungenauigkeit und Zahlengröße.

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
die Variante von 4L sieht sehr viel schöner aus - hat aber den bitteren Beigeschmack, dass bei der Funktion "**" mit einer REAL-Zahl gearbeitet wird und damit den daraus resultierenden Nachteilen bezüglich Wandlungs-Ungenauigkeit und Zahlengröße.

man kann die REAL-potenz auch durch eine schleife mit INT-Multiplikation ersetzen. war auch eine version aber die real-genauigkeit ist ausreichend in diesem zahlenbereich...
 
Zurück
Oben