# Bitsummenprüfung



## Topse (5 Mai 2008)

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.


----------



## marlob (5 Mai 2008)

Suche mal nach Bitsum hier im Forum


----------



## Ralle (5 Mai 2008)

Guckst du hier: http://www.sps-forum.de/showthread.php?t=16055&highlight=BitSum

oder suchst mal unter "Bitsum".


----------



## marlob (5 Mai 2008)

http://www.sps-forum.de/showpost.php?p=102188&postcount=5


----------



## Machtnix (5 Mai 2008)

Hier ein AWL-Quelltext.Falls du nicht nur eine Funktion anwenden, sondern auch verstehen willst.


```
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
```


----------



## Topse (5 Mai 2008)

*Danke*

Danke Euch allen für die Mühe, hab die Aufgabe mit dem FC99 aus der Bibliothek gelöst.


----------



## Onkel Dagobert (5 Mai 2008)

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

Gruß, Onkel



```
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
```


----------



## Ralle (5 Mai 2008)

@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?


----------



## Onkel Dagobert (5 Mai 2008)

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


----------



## Flinn (6 Mai 2008)

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


----------



## marlob (6 Mai 2008)

Flinn schrieb:


> ...
> 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:
> ...


----------



## StephanFL (21 Februar 2017)

*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


----------

