Bitsummenprüfung

Topse

Level-1
Beiträge
34
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe folgendes Problem:

In einem Byte stellt jedes Bit einen Eingang dar.
Jeder Eingang symbolisiert einen Fehler an der Maschine.

0011 0100 --> hier habe ich 3 Fehler an der Maschine.

Folgende Auswertung ist gewünscht:
Ich soll die Anzahl der Fehler in einen OP darstellen, hierzu müsste ich die Summe der 1nsen in diesen Bit erfassen.
0000 0000-->keine Eins-->bedeutet kein Fehler
0001 0000-->eine Eins-->bedeutet ein Fehler
0010 0010-->mehr als eine Eins-->bedeutet multi Fehler

Die genaue Anzahl spielt hierfür keine Rolle ich muss nur zwischen 0, 1, und mehr Fehler unterscheiden.


Hoffentlich könnt Ihr mit meiner Beschreibung etwas anfangen und mir eventuell eine kleine Strategie zukommen lassen.
 
Hier ein AWL-Quelltext.Falls du nicht nur eine Funktion anwenden, sondern auch verstehen willst.

Code:
FUNCTION "FCBitSumB" : VOID
TITLE = Bitsumme aus BYTE
VERSION : 0.1

VAR_INPUT
 inb :BYTE;
END_VAR

VAR_OUTPUT
 sum :INT;
END_VAR

VAR_TEMP
 mask: WORD; //Bitmaske zur Abfrage
END_VAR

BEGIN

L 0; T #sum;  
L 1; T #mask;

m1: L #inb ;L #mask; UW ; SPZ m2; // Abfragen mit UW, wenn Bit=0 springen 
 
L #sum; L 1 ;+I; T #sum;   // Summe um 1 erhöhen

m2: L #mask; SLW 1;T #mask; // Maske verschieben zum nächsten Bit

L 256;<I;SPB m1; //Zurück solange Maske kleiner 256 (8.Bit)

END_FUNCTION
 
Ich vermisse die Frage nach einer Lösung mit einem Any-Pointer :s1: .

Gruß, Onkel


Code:
FUNCTION "COUNT_BITS" : VOID
TITLE =
VERSION : 0.1
 
VAR_INPUT
  DATENBEREICH : ANY ; 
END_VAR
 
VAR_OUTPUT
  ANZAHL : INT ; //Anzahl gesetzer Einträge
  KEIN_BIT_HIGH : BOOL ; 
  GENAU_EIN_BIT_HIGH : BOOL ; 
  MINDESTENS_EIN_BIT_HIGH : BOOL ; 
  MEHR_ALS_EIN_BIT_HIGH : BOOL ; 
  ERROR : INT ; //0-kein Fehler, 1-Datentyp nicht Byte
END_VAR
 
VAR_TEMP
  AR1_TEMP : DWORD ; 
  TEMP_INT : WORD ; 
  TEMP_DINT : DWORD ; 
  TEMP_ANZAHL_HIGH : INT ; 
  LOOP : INT ; 
END_VAR
 
BEGIN
 
NETWORK
TITLE =
 
//*** AR1 sichern
      TAR1  #AR1_TEMP; 
      SET   ; 
      SAVE  ; 
 
//*** Ergebnisse initialisieren
      L     B#16#0; 
      T     #TEMP_ANZAHL_HIGH; 
      T     #ANZAHL; 
      T     #ERROR; 
      SET   ; 
      R     #KEIN_BIT_HIGH; 
      R     #GENAU_EIN_BIT_HIGH; 
      R     #MINDESTENS_EIN_BIT_HIGH; 
      R     #MEHR_ALS_EIN_BIT_HIGH; 
 
//*** AR2 auf Datenbereich
      L     P##DATENBEREICH; 
      LAR2  ; 
 
//*** Prüfe, ob DATENBEREICH vom Typ=Byte
      L     W [AR2,P#0.0]; // Typ 
      L     W#16#1002; 
      ==I   ; 
      L     1; // Fehler 1: DATENBEREICH nicht vom Typ Byte
      SPBN  ERR; 
 
//*** Länge in Bits ermitteln
      L     W [AR2,P#2.0]; // Anzahl Bytes im DATENBEREICH
      SLW   3; 
      T     #LOOP; // Schleifenzähler initialisieren
 
//*** DB öffnen und Adressregister auf Bereichszeiger
      L     W [AR2,P#4.0]; 
      T     #TEMP_INT; 
      AUF   DB [#TEMP_INT]; 
      L     D [AR2,P#6.0]; 
      LAR2  ; // DATENBEREICH
 
//*** Schleife zur Zählung der gesetzten Bits
      L     #LOOP; 
LOOP: T     #LOOP; 
      U      [AR2,P#0.0]; 
      SPBN  M001; 
      L     #TEMP_ANZAHL_HIGH; 
      L     1; 
      +I    ; 
      T     #TEMP_ANZAHL_HIGH; 
M001: NOP   0; 
      +AR2  P#0.1; // Pointer erhöhen
      L     #LOOP; 
      LOOP  LOOP; 
 
//*** Anzahl gesetzter Bits
      L     #TEMP_ANZAHL_HIGH; 
      T     #ANZAHL; 
 
//*** kein Bit high
      L     0; 
      ==I   ; 
      =     #KEIN_BIT_HIGH; 
 
//*** Genau eine Bit high
      TAK   ; 
      L     1; 
      ==I   ; 
      =     #GENAU_EIN_BIT_HIGH; 
 
//*** Mindestens ein Bit high
      >=I   ; 
      =     #MINDESTENS_EIN_BIT_HIGH; 
 
//*** Mehr als ein Bit high
      >I    ; 
      =     #MEHR_ALS_EIN_BIT_HIGH; 
 
//*** AR1-Register wiederherstellen
      LAR1  #AR1_TEMP; 
      BEA   ; 
 
//*** Fehler
ERR:  T     #ERROR; 
 
//*** AR1-Register wiederherstellen
      LAR1  #AR1_TEMP; 
      BE    ; 
 
END_FUNCTION
 
@Onkel

Dazu hab ich mal ein paar kleine Fragen, weil es wirklich interessant ist darüber nachzudenken.
Warum rettest du AR1, nutzt dann aber ausschließlich AR2? Hat das einen Grund? Sollte man auch noch AR2 retten oder einfach statt AR2 AR1 nutzen, damit man in Multiinstanz-FB keine Probleme bekommt?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Ralle,

richtig, AR1 wird in diesem Fall nicht verwendet und muss daher auch nicht gesichert werden. Die Zeilen könnte man also getrost löschen.

AR2 kann man in FCs uneingeschränkt verwenden, so weit ich weiß. Probleme hatte ich damit noch nicht, auch nicht bei Verwendung derartiger FCs in Multiinstnzen. Beim AR2-Verbiegen unmittelbar in FBs sieht es natürlich ganz anders aus.


Gruß, Onkel


siehe auch:
Berger-Bibel "Automatisieren mit Step7 in AWL und SCL" Psalm 25.4
 
Zuletzt bearbeitet:
Hallo!

Habe noch mal über das AR1 nachgedacht: Ich rette das AR1 auch immer, Macht der Gewohnheit.

Aber !!?!!?
Wird nicht das AR1 automatisch vom Betriebssystem gerettet? So dass nach Unterbrechung von einem Interrupt-OB und Wiederkehr in das zykl. Programm das AR1 automatisch wiederhergestellt wird? Was meint Ihr?

Gruß
Flinn
 
...
Aber !!?!!?
Wird nicht das AR1 automatisch vom Betriebssystem gerettet? So dass nach Unterbrechung von einem Interrupt-OB und Wiederkehr in das zykl. Programm das AR1 automatisch wiederhergestellt wird? Was meint Ihr?
...
Das sagt Siemens dazu. Das Thema hatten wir aber schon ein paar Mal hier
Konfigurationshinweise:
Bei der Programmierung einiger Operationen werden Register- oder Akkuinhalte durch STEP 7 verändert. Insbesondere bei Programmierung mit absoluter Adressierung muss dieser Sachverhalt berücksichtigt werden. Nachfolgend sind einige der Operationen aufgeführt, durch die Inhalte von Register/Akku verändert werden:
  • Die Verwendung der folgenden höheren Sprachkonstrukte kann dazu führen, dass die Inhalte von DB-Register und Adressregister AR1 verändert werden:
  • vollqualifizierter DB-Zugriff (z.B. DB20.DBW10) als Aktualparameter für FC's
  • FB- und Multiinstanz-CALL
  • Strukturkomponente eines Formalparameters als Operand innerhalb eines FC's oder FB's
  • Strukturkomponente eines Formalparameters als Aktualparameter für FC oder FB
  • Beim FB-, FC-, Multiinstanz-CALL dürfen VKE oder AKKU1 und AKKU2 nicht als zusätzliche (implizite) Parameter verwendet werden.
  • Das DI-Register und das Adressregister AR2 wird systemseitig für den FB- und Multiinstanz-CALL verwendet und dürfen deshalb innerhalb von FB's nicht verändert werden (siehe hierzu auch Beitrags-ID 22531225).
  • Das Adressregister AR1 wird von einem Teil der ladbaren Standardbausteine verwendet.
  • Der Befehl "L P#Parametername" lädt innerhalb eines FBs den Adressoffset des angegebenen Parameters, relativ zum Adressregister AR2. Um in multiinstanzfähigen FB's den absoluten Offset im Instanzdatenbaustein zu ermitteln, muss zu diesem Wert noch der bereichsinterne Zeiger (nur Adresse) des AR2-Registers addiert werden.
Wenn Sie die oben genannten Programmiermöglichkeiten und gleichzeitig die genannten Register/Akkus nutzen, müssen Sie selbst für eine Wiederherstellung der Inhalte der verwendeten Register/Akkus Sorge tragen, da es sonst zu einem Fehlverhalten kommt. Einzelheiten hierzu sind im Topic "Vermeiden von Fehlern beim Aufrufen von Bausteinen" in der Hilfe zu STEP 7 nachzulesen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Bitsumme im Datenbereich (Byte,Word,DWord)

FUNCTION FC 1172 : INT
TITLE =Bitsumme im Datenbereich ermitteln
//
//================================================================================
// B I T S U M M E
//================================================================================
//
VERSION : 0.1

VAR_INPUT
Datenbereich : ANY ; //Datenbereich in dem die Bits gezählt werden sollen (Byte,Word,DWord)
END_VAR
VAR_OUTPUT
Falscher_DT : BOOL ; //Falscher Datentyp am Any-Pointer
END_VAR
VAR_IN_OUT
Schleifenzaehler : INT ; //Hilfswort für die Loop-Funktion
END_VAR
VAR_TEMP
WordVal : WORD ; //Hilfs-Variabel Word
DWordVaL : DWORD ; //Hilfs-Variabel DWord
Anzahl_Schleifen : INT ; //Anzahl der Schleifen
DB_Nr : WORD ; //Datenbaustein-Nummer
_Byte : BOOL ; //Datentype Byte angewählt
_Word : BOOL ; //Datentype Word angewählt
_DWord : BOOL ; //Datentype DWord angewählt
END_VAR
BEGIN
NETWORK
TITLE =Adresspointer für die Quelle laden
L P##Datenbereich; // Lade die Anfangsadresse des ANY-Pointers in AR1
LAR1 ;
L B [AR1,P#1.0]; //=============================
L 2; // Abfrage Datentype: Byte
==I ; //
= #_Byte; //=============================
L B [AR1,P#1.0]; //=============================
L 4; // Abfrage Datentype: Word
==I ; //
= #_Word; //=============================
L B [AR1,P#1.0]; //=============================
L 6; // Abfrage Datentype: DWord
==I ; //
= #_DWord; //=============================
L W [AR1,P#2.0]; //=============================
T #Anzahl_Schleifen; // Anzahl Schleifen
L W [AR1,P#4.0]; //=============================
T #DB_Nr; //
L 0; // Datenbaustein aufrufen, falls
==I ; // vorhanden
SPB N201; //
AUF DB [#DB_Nr]; //=============================
N201: CLR ;
NETWORK
TITLE =Abfrage Falscher Datentyp
UN #_Byte;
UN #_Word;
UN #_DWord;
= #Falscher_DT;
NETWORK
TITLE =Bitsumme ermitteln
//================================================================================
// BYTE-Bereich
//================================================================================
//
UN #_Byte;
SPB WORD;
L D [AR1,P#6.0];
LAR1 ; // Adresspointer einstellen
L 0; // Setze RET_VAL auf 0
T #RET_VAL; // RET_VAL
LpBy: L 1; //=============================
L #Schleifenzaehler; // Schleifenzähler um 1 erhöhen
+I ; //
T #Schleifenzaehler; //=============================
L B [AR1,P#0.0]; // Lade Eingangs-Wort
T #WordVal; // Temporäre Variabel
A201: L 0; // Wenn 0 wird Bearbeitung abgebrochen
L #WordVal; //
==I ; //
SPB A202; //
SRW 1; // Abfrage um 1 weiter schieben
T #WordVal; //
SPZ A201; //
L #RET_VAL; //=============================
L 1; // RET_VAL erhöhen
+I ; //
T #RET_VAL; //=============================
SPA A201;
A202: NOP 0;
+AR1 P#1.0; // Pointer um ein Byte erhöhen
L #Anzahl_Schleifen; //==============================
L #Schleifenzaehler; // Loop, wenn Anzahl der Bits
>I ; // noch nicht erreicht ist
SPB LpBy; //==============================
NETWORK
TITLE =Schleifenzähler rücksetzen
U( ;
L #Schleifenzaehler;
L #Anzahl_Schleifen;
>=I ;
) ;
SPBNB _001;
L 0;
T #Schleifenzaehler;
_001: NOP 0;
NETWORK
TITLE =Bitsumme ermitteln
//================================================================================
// WORD-Bereich
//================================================================================
//
WORD: UN #_Word;
SPB DWOR;
L D [AR1,P#6.0];
LAR1 ; // Adresspointer einstellen
L 0; // Setze RET_VAL auf 0
T #RET_VAL; // RET_VAL
LpWo: L 1; //=============================
L #Schleifenzaehler; // Schleifenzähler um 1 erhöhen
+I ; //
T #Schleifenzaehler; //=============================
L W [AR1,P#0.0]; // Lade Eingangs-Wort
T #WordVal; // Temporäre Variabel
A401: L 0; // Wenn 0 wird Bearbeitung abgebrochen
L #WordVal; //
==I ; //
SPB A402; //
SRW 1; // Abfrage um 1 weiter schieben
T #WordVal; //
SPZ A401; //
L #RET_VAL; //=============================
L 1; // RET_VAL erhöhen
+I ; //
T #RET_VAL; //=============================
SPA A401;
A402: NOP 0;
+AR1 P#2.0; // Pointer um 1 Wort erhöhen
L #Anzahl_Schleifen; //==============================
L #Schleifenzaehler; // Loop, wenn Anzahl der Bits
>I ; // noch nicht erreicht ist
SPB LpWo; //==============================
NETWORK
TITLE =Schleifenzähler rücksetzen
U( ;
L #Schleifenzaehler;
L #Anzahl_Schleifen;
>=I ;
) ;
SPBNB _002;
L 0;
T #Schleifenzaehler;
_002: NOP 0;
NETWORK
TITLE =Bitsumme ermitteln
//================================================================================
// DWORD-Bereich
//================================================================================
//
DWOR: UN #_DWord;
SPB Ende;
L D [AR1,P#6.0];
LAR1 ; // Adresspointer einstellen
L 0; // Setze RET_VAL auf 0
T #RET_VAL; // RET_VAL
LpDW: L 1; //=============================
L #Schleifenzaehler; // Schleifenzähler um 1 erhöhen
+I ; //
T #Schleifenzaehler; //=============================
L D [AR1,P#0.0]; // Lade Eingangs-Wort
T #DWordVaL; // Temporäre Variabel
A601: L L#0; // Wenn 0 wird Bearbeitung abgebrochen
L #DWordVaL; //
==D ; //
SPB A602; //
SRD 1; // Abfrage um 1 weiter schieben
T #DWordVaL; //
SPZ A601; //
L #RET_VAL; //=============================
L 1; // RET_VAL erhöhen
+I ; //
T #RET_VAL; //=============================
SPA A601;
A602: NOP 0;
+AR1 P#4.0; // Pointer um 1 D-Wort erhöhen
L #Anzahl_Schleifen; //==============================
L #Schleifenzaehler; // Loop, wenn Anzahl der Bits
>I ; // noch nicht erreicht ist
SPB LpDW; //==============================
NETWORK
TITLE =Schleifenzähler rücksetzen
U( ;
L #Schleifenzaehler;
L #Anzahl_Schleifen;
>=I ;
) ;
SPBNB _003;
L 0;
T #Schleifenzaehler;
_003: NOP 0;
NETWORK
TITLE =Setze BIE-Bit
Ende: SET ;
SAVE ;
END_FUNCTION
 
Zurück
Oben