Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: Bit aus Array of Bool (mit Variable als Index) lesen, setzen, rücksetzen in AWL

  1. #1
    Registriert seit
    10.08.2015
    Beiträge
    4
    Danke
    3
    Erhielt 0 Danke für 0 Beiträge

    Frage


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hallo zusammen!

    Bei folgendem Szenario habe ich Probleme mit der Umsetzung:
    Ich habe ein Array of Bool mit 15 Einträgen. Nennen wir dieses Array mal TestArrayBool[0..14]. Ich möchte gerne einzelne Bits lesen, setzen und rücksetzen können. Der Zugriff auf die Einträge soll mittels einer Indexvariable (Index) bestimmt werden können.

    Mein erster Ansatz wäre folgender gewesen:

    Code:
    // Variablen:
    // TrayIndex als INT
    // TestArrayBool als Array [0..14] of Bool
    
    
    // Eintrag prüfen
    U TestArrayBool[Index]
    
    // Bit setzen
    S TestArrayBool[Index]
    
    // Bit rücksetzen
    R TestArrayBool[Index]
    Der Ansatz hat natürlich nicht funktioniert (Syntaxfehler) und ich habe in diesem Forum einige ähnliche Beispiele dazu gefunden. Wie in den Artikel beschrieben, ist diese Aufgabe in AWL nicht ganz so einfach zu lösen. Um den indirekten Zugriff auf ein Arrayelemt zu ermöglichen, muss mit Pointern gearbeitet werden.


    Ich konnte mit Hilfe des Beitrages über Pointer Zeiger die Aufgabenstellung zumindest für ein Array of Int lösen.

    Funktion fürs Laden
    Code:
    // Funktion: Laden eines Arrayeintrages
    // Variablen:
    // TrayIndex als INT
    // TestArrayInt als Array [0..14] of Int
    
    // TrayIndex testweise beschreiben
    L         4
    T         TrayIndex
    
    L         P##TestArrayInt         //Pointer auf Array laden
    LAR1                                    //ins Adressregister AR1 speichern
    L         #TrayIndex               // TrayIndex laden
    L         2
    *I                                       // mit 2 multiplizieren da Typ: int
    SLD     3                             // Pointer bauen
    +AR1                                 // zum Adressregister hinzuaddieren
    L         W [AR1,P#0.0]        // Syntax läd den Wert von #TestArrayInt[4]
    Funktion fürs Schreiben:
    Code:
    // Funktion: Schreiben eines Arrayeintrages
    // Variablen:
    // TrayIndex als INT
    // TestArrayInt als Array [0..14] of Int
    
    // TrayIndex testweise beschreiben
    L         4
    T         TrayIndex
    
    L         P##TestArrayInt         //Pointer auf Array laden
    LAR1                                    //ins Adressregister AR1 speichern
    L         #TrayIndex               // TrayIndex laden
    L         2
    *I                                       // mit 2 multiplizieren da Typ: int
    SLD     3                             // Pointer bauen
    +AR1                                 // zum Adressregister hinzuaddieren
    L         50                          // Intwert von 50 laden
    T        W [AR1,P#0.0]        // Syntax schreibt den Wert 50 in den Arrayeintrag #TestArrayInt[4]
    Anschließend habe ich versucht die Funktion auf ein Array of Bool anzupassen:

    Code:
    // Funktion: Lesen eine Arrayeintrages
    // Variablen:
    // TrayIndex als INT
    // TestArrayBool als Array [0..14] of Bool
    
    // TrayIndex testweise beschreiben
    L         4
    T         TrayIndex
    
    L         P##TestArrayBool         //Pointer auf Array laden
    LAR1                                    //ins Adressregister AR1 speichern
    L         #TrayIndex               // TrayIndex laden
    L         8
    /I                                       // durch 8 multiplizieren da Typ: Bool
    SLD     3                             // Pointer bauen
    +AR1                                 // zum Adressregister hinzuaddieren
    
    // Bit lesen
    U  ??????? // Welcher Syntax muss hier stehen, damit ich das Bit TestArrayBool[TrayIndex] abfragen kann bzw. geht das überhaupt so einfach, wie ich mir das vorstelle?
    
    Wie würde der Syntax aussehen, wenn ich beschreiben (S) bzw. rücksetzen (R) will?
    Danke im Voraus!
    Zitieren Zitieren Bit aus Array of Bool (mit Variable als Index) lesen, setzen, rücksetzen in AWL  

  2. #2
    Registriert seit
    13.11.2014
    Ort
    Paderborn
    Beiträge
    187
    Danke
    15
    Erhielt 12 Danke für 11 Beiträge

    Standard

    Hi,

    ich hab mich kürzlich auch erst damit auseinandersetzten müssen, nicht in dem gleichen Zusammenhang wie du, aber
    vllt finden wir gemeinsam eine Lösung

    Ich geh mal davon aus, dass du dein Array in einem DB stehen hast und die Start Adresse DB1.DBX0.0 ist

    Ganz wichtig natürlich die Datentypen der verschiedenen Variablen richtig angeben, sonst klappt es nicht.

    Ich wäre jetzt so vorgegangen (schreiben):

    L #Index //Zahlenwert zwischen 0..14
    SLD3
    T #Addr

    // Sprungbedingung ob L1 oder L0 geladen werden soll

    L 1 // Lade 1 oder 0 in Abhängigkeit was du machen möchtest
    AUF DB1 //Aufruf DB1
    T DBW[#Addr] //Wert 1 auf die Adresse die im Addr steht transferieren


    lesen:



    L #Index //Zahlenwert zwischen 0..14
    SLD3
    T #Addr

    L DBW[#Addr] //Wert 1 auf die Adresse die im Addr steht transferieren
    T HM // HM Hilfsmerker

    U HM
    =M0.2 //Was du dann auch immer damit machen möchtest
    ...
    ..
    Geändert von Junge (11.08.2015 um 13:46 Uhr)

  3. Folgender Benutzer sagt Danke zu Junge für den nützlichen Beitrag:

    WTEFUE (11.08.2015)

  4. #3
    Registriert seit
    22.11.2006
    Ort
    CH
    Beiträge
    3.618
    Danke
    775
    Erhielt 646 Danke für 492 Beiträge

    Standard

    Solches Zeug ist in SCL eben schon sehr übersichtlich und einfach zu machen.

    kleines Beispiel.

    Code:
    VAR_IN_OUT
        testarray : ARRAY[0..15] OF BOOL;
        merker : BOOL;
    END_VAR
    
    
    VAR_TEMP
    index : INT;
    END_VAR
    
    
    FOR index := 0 TO 15 DO
        IF testarray[index] THEN // alle elemente des array abfragen wenn eines wahr ist dann 
             merker := true; // merker setzen
        END_IF;
            
    END_FOR;
    
    
    END_FUNCTION_BLOCK

  5. Folgender Benutzer sagt Danke zu vollmi für den nützlichen Beitrag:

    WTEFUE (11.08.2015)

  6. #4
    Registriert seit
    10.10.2008
    Beiträge
    43
    Danke
    1
    Erhielt 1 Danke für 1 Beitrag

    Standard

    Hi WTEFUE,

    so arg falsch ist dein Weg gar nicht! Ausgehend von deinen Zeilen oben und der Annahme, dass TrayIndex als INT an (Lokal)Adresse 0.0 und TestArrayBool an (Lokal)Adresse 2.0 steht:
    Code:
    // Variablen:
    // TrayIndex als INT
    // TestArrayBool als Array [0..14] of Bool
    
    // TrayIndex testweise beschreiben
    L         10
    T         TrayIndex
    
    L         P##TestArrayBool         //Pointer auf Array laden
    // AKKU1 enthält jetzt (hex)8600 0010 und zeigt
    // somit auf Byte 2 der Lokaldaten. Entspricht TrayIndex = 0.
    // Daran denken, dass ein Pointer in den untersten drei
    // Bit die 8 einzelnen Bits eines Bytes addressiert!
    // Es würde jetzt also auf TestArrayBool[0] gezeigt.
    
    // Soll bspw. auf TestArrayBool[10] (TrayIndex = 10) gezeigt
    // werden, muss einfach TrayIndex (also 10) zum Wert im
    // AKKU1 addiert werden. AKKU1 enthält dann
    // (hex)8600 001A. Oder anders ausgedrückt: die Adresse
    // auf das Bit L3.2.
    L        TrayIndex
    +D
    LAR1
    
    // Zum Vergleich ein Laden der Adresse auf L3.2 direkt.
    L P#L 3.2
    
    // Um den Zustand des Bits 10 im Array (auf das zeigt AR1
    // zu lesen/zu schreiben, die gewohnte Semantik verwenden.
    // Also bspw. zum Lesen:
    SET
    U        L [AR1, P#0.0]
    =        M4711.0
    
    // Oder zum Übernehmen eines anderen Bits
    SET
    U        M4711.1
    =        L [AR1, P#0.0]
    
    // Das Setzen wie üblich mit
    SET
    S        L [AR1, P#0.0]
    
    // Oder das Rücksetzen mit
    SET
    R        L [AR1, P#0.0]
    Grüße
    Max
    Geändert von Löwensenft (10.08.2015 um 23:12 Uhr)

  7. Folgender Benutzer sagt Danke zu Löwensenft für den nützlichen Beitrag:

    WTEFUE (11.08.2015)

  8. #5
    WTEFUE ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    10.08.2015
    Beiträge
    4
    Danke
    3
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Zitat Zitat von vollmi Beitrag anzeigen
    Solches Zeug ist in SCL eben schon sehr übersichtlich und einfach zu machen.
    Ansich würde ich das sicherlich auch in SCL machen anstatt in AWL. Mein Problem ist nur, dass ich zwar eine Professionallizenz (mit SCL) auf dem Rechner habe, jedoch mein Kunde auf AWL besteht, da er nur eine Basic Lizenz hat.

    Trotzdem danke ich dir!

    EDIT: Ist es möglich ein bereits übersetztes SPS-Projekt (mit SCL Bausteinen) mit einer Basiclizenz auf die SPS zu übertragen. Wird nur für das Übersetzen eine Professionallizenz benötigt?

    Lg
    WTEFUE
    Geändert von WTEFUE (11.08.2015 um 12:07 Uhr) Grund: Unklarheiten hinsichtlich Lizenz

  9. #6
    WTEFUE ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    10.08.2015
    Beiträge
    4
    Danke
    3
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Hallo Löwensenft!

    Ich habe deine Lösung ausprobiert und es hat funktioniert.

    Ist es auch möglich das TestArrayBool nicht in dem TEMP-Bereich zu haben. Ich würde mir gerne einen Baustein basteln, den ich mit INPUTS füttere. Dann wird allerdings die Syntax L [Ar1,P#0.0] nicht funktionieren, da diese ja auf den TEMP-Bereich zugreift.

    Im Prinzip würde ich gerne den Baustein aufrufen können und die Eingangs und Ausgangsparameter definieren.

    Beispiel:
    Ich baue mir einen FB, nennen wir ihn TestArray. Dieser Baustein hat als INPUT den #TrayIndex und ein #AktionsInt. Als IN_OUt ist das #TestArrayBool definiert. Den zugehörigen Instanzbaustein nennen wir INST_DB_TestArray. Die gefütterten Daten kommen von Datenbausteinen. Nennen wir diese DB_Parameter1 und DB_Parameter2.


    Code:
    // Aufruf von FB TestArray gefüttert durch DB_Parameter1
    Call "TestArray";"INST_DB_TestArray"
    TrayIndex     := "DB_Parameter1".TrayIndex                 //INPUT
    AktionsInt     := "DB_Parameter1".AktionsInt                 //INPUT: AktionsInt=0 --> lesen; AktionsInt=1 --> setzen, AktionsInt=2 -->rücksetzen
    TestArray     := "DB_Parameter1".TestArray                  //IN_OUT
    
    
    //später im Programm möchte ich denselben Baustein verwenden, aber zum Beispiel den TrayIndex und den AktionsInt direkt bestimmen und das TestArray aus dem DB_Parameter2 verwenden.
    Call "TestArray";"INST_DB_TestArray"
    TrayIndex     := 2                                                      //INPUT
    AktionsInt     := 0                                                      //INPUT: AktionsInt=0 --> lesen; AktionsInt=1 --> setzen, AktionsInt=2 -->rücksetzen
    TestArray     := "DB_Parameter2".TestArray                  //IN_OUT
    Geht so viel Flexibilität ohne SCL oder muss ich mich an Junge's Beitrag orientieren und meine Datenbausteine direkt ansprechen.

    Liebe Grüße
    WTEFUE

  10. #7
    Registriert seit
    10.10.2008
    Beiträge
    43
    Danke
    1
    Erhielt 1 Danke für 1 Beitrag

    Standard

    Hi,

    ich vermute es hat einen Grund, dass du einen FB brauchst?

    Zurück zum Thema: In den Baustein wird nur ein Pointer (6 Byte) übergeben. Das heißt ein
    Code:
    L P#TestArray
    zeigt dann auf die Stelle an der die eigentliche Adresse der Daten steht.

    Das heißt es gilt nun zunächst die eigentliche Adresse für dich "verfügbar" zu machen. Schau nach dem POINTER Typ, wenn du mehr über dessen Aufbau wissen willst.
    Code:
    L P#TestArray
    LAR1
    
    L W[AR1, P#0.0]
    T #tmpDataDBNum   // #tmpDataDBNum muss vom Typ WORD (oder INT) sein
    L D[AR1, P#2.0]
    T #tmpDataAddress // #tmpDataAdress muss vom Typ DWORD (oder DINT) sein
    Nun kann wie bisher auf die Daten zugegriffen werden:
    Code:
    // Datenbaustein öffnen, falls Daten in einem DB stehen
    AUF DB[#tmpDataDBNum]
    // "Start-"Adresse der Daten laden, Index aufrechnen und in Adressregister laden
    L #tmpDataAddress
    L #TrayIndex
    +D
    LAR1
    
    // Als Beispiel: Bit prüfen. Der Zugriff mittels des "allgemeinen" "L[AR1...]" sollte hier funktionieren.
    SET
    U L[AR1, P#0.0]
    Sollte so funktionieren. Habs jetzt aber nicht nochmal getestet.

    Gruß
    Max

  11. #8
    Registriert seit
    13.11.2014
    Ort
    Paderborn
    Beiträge
    187
    Danke
    15
    Erhielt 12 Danke für 11 Beiträge

    Standard

    Ich hab gerade nochmal mein Quellcode ins PG eingegeben und gesehen das da noch ein Fehler ist ..deswegen hier noch eine kleine Korrektur:

    Array[0..14] of Bool


    Schreiben:
    Code:
          L     #Index                      //Datentyp Byte
          SLD   3
          LAR1  
          T     #Addr                      //Datentyp Dword
                                                // Sprungbedingung ob L1 oder L0 geladen werden soll
          L     1                             // Lade 1 oder 0 in Abhängigkeit was du machen möchtest
          AUF   DB     2                   //Aufruf DB2
          T     DBW [#Addr]             //Datentyp Byte DBB,Word  DBW, DWord DBD?!
    Mit dem Datentyp bei dem Transfer bin ich auch überfragt, wäre schön wenn mir das auch noch einer beantworten könnte
    Da nur die Werte 1 oder 0 übertragen werden, müsste es doch egal sein welchen Datentyp wir angeben, der Rest würde einfach wegfallen?!

  12. #9
    WTEFUE ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    10.08.2015
    Beiträge
    4
    Danke
    3
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Hallo nochmal Löwensenft!


    Ich habe folgenden Code nachgebaut und ausgetestet:

    Code:
    L P#TestArray                      // Da #TestArray als IN_OUT definiert ist und im Bausteinaufruf TestArray:= "DB_Parameter1".TestArray definiert worden ist, sollte hier auch das TestArray aus dem DB_Parameter1 verwendet werden?!
    
    
    LAR1                               // und ins Adressregister geschrieben werden
    
    
    L W[AR1, P#0.0]                
    T #tmpDataDBNum             // #tmpDataDBNum muss vom Typ WORD (oder INT) sein
    L D[AR1, P#2.0]              
    T #tmpDataAddress         // #tmpDataAdress muss vom Typ DWORD (oder DINT) sein
    
    // Datenbaustein öffnen, falls Daten in einem DB stehen
    AUF DB[#tmpDataDBNum]           // habe mit und ohne dieser Zeile getestet. In meinem Test ist nämlich TrayIndex direkt als Zahl angegeben. Lediglich das Array soll aus dem DB entnommen werden und nachher falls geändert wieder in                                                    //den DB geschoben werden. Deshalb sollte ich diese Zeile nicht benötigen.
    
    
    // "Start-"Adresse der Daten laden, Index aufrechnen und in Adressregister laden
    L #tmpDataAddress               // in tmpDataAddress sollte jetzt die Start-Addesse vom DB_Parameter1.TestArray stehen oder?
    L #TrayIndex                       // den TrayIndex laden (4)
    +D                                     // zum Adressregister wird der TrayIndex hinzuaddiert, damit auf TestArray[4] zugegriffen werden kann.
    LAR1
    
    
    // Als Beispiel: Bit prüfen. Der Zugriff mittels des "allgemeinen" "L[AR1...]" sollte hier funktionieren.
    SET
    U L[AR1, P#0.0]             // für Testzwecke setze ich M10.0 auf 1.
    = M10.0

    #TestArray ist dabei als IN_OUT definiert (Array[0..14] of Bool)
    #TrayIndex ist als IN definiert (INT)
    #tmpDataDBNum ist als TEMP definiert (WORD)
    #tmpDataAddress ist als TEMP definiert (DWORD)

    Ich rufe den Baustein so auf:
    CALL "TestArray","INST_DB_TestArray"
    TrayIndex := 4 // auf 4 gesetzt zum Testen
    TestArray := "DB_Parameter1".Testarray // Array[0..14] of Bool --> zum Testen habe ich alle Einträge auf True gesetzt


    Die Abfrage U L[AR1,P#0.0] hat als VKE 0, obwohl ich im DB_Parameter1 alle Einträge im TestArray auf True gesetzt habe.
    M10.0 sollte 1 werden, wird es aber leider nicht...



    Ich werde mir, wie von dir vorgeschlagen, den Pointer Typ genauer anschauen.

    Aus dem Kontext heraus kann ich zwar annehmen, dass der Syntax L W[AR1, P#0.0] die DBNummer extrahiert und der Syntax L D[AR1, P#2.0] die Adresse extrahiert. Wieso und warum zum Beispiel der Versatz P#2.0 benötigt wird verstehe ich leider noch nicht.


    Vielen Dank für die Bemühungen.
    Ich freue mich über jeglichen weiteren Tipps und melde mich hier mit meiner Lösung, falls ich sie gefunden habe.

    Lg
    WTEFUE

  13. #10
    Registriert seit
    10.10.2008
    Beiträge
    43
    Danke
    1
    Erhielt 1 Danke für 1 Beitrag

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hi,

    sorry, mein Fehler. Ich dachte dass der Zugriff (ob DB oder Lokal) automatisch korrekt gemacht wird. *grübel*

    Wenn du deine Bits tatsächlich in einem DB abspeichert, musst du mit "U DBX[AR1, P#0.0]" zugreifen... Allerdings funktioniert DBX nicht, wenn dein AR1 auf Lokaldaten zeigt...

    Da muss ich nochmal in mich gehen.

    Gruß
    Max

Ähnliche Themen

  1. Boolschen Array mit einem Bool auf True setzen bzw. auf False setzen
    Von Step7Neuling im Forum CODESYS und IEC61131
    Antworten: 6
    Letzter Beitrag: 29.03.2015, 14:38
  2. IEC-61131 Pointer mit Index auf BOOL Variable
    Von Stussi im Forum CODESYS und IEC61131
    Antworten: 21
    Letzter Beitrag: 14.12.2007, 09:11
  3. Bool-Variable setzen/rücksetzen
    Von Supervisor im Forum Simatic
    Antworten: 2
    Letzter Beitrag: 18.07.2006, 12:29
  4. Antworten: 27
    Letzter Beitrag: 17.07.2006, 22:20
  5. Mit F-Tasten Bit Setzen oder Rücksetzen
    Von Anonymous im Forum HMI
    Antworten: 0
    Letzter Beitrag: 28.04.2005, 11:32

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •