Step 7 Laufbit: Anfangsadresse als Pointer + Länge angeben

wellenbrecher

Level-1
Beiträge
25
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich habe heute einen Baustein geschrieben, der ein Bit in einem variablen Speicherbereich "laufen" lässt. Dabei habe ich einiges über Any-Pointer, indirekte Adressierung usw. gelernt.
Meine prinzipielle Vorgangsweise:
1. Anypointer auswerten (Adresse, evtl. DB, Speicherbereich)
2. Anhand Speicherbereich jeweils die Laufbit-Routine durchlaufen
3. Routine: Gesetztes Bit suchen, dann zurück setzen und nächstes Bit setzen. Bis Bereichsende, dann evtl. wieder erstes Bit setzen.

Nun meine Frage: Geht das auch einfacher?
- Muss ich z.B. für jeden Speicherbereich die Routine extra aufrufen?

Code:
FUNCTION FC 997 : VOID
TITLE =Laufbit
VERSION : 0.1


VAR_INPUT
  Takt : BOOL ;    //Takt für Geschwindigkeit Laufbit
  Adr : ANY ;    //Startadresse (M, A, DB)
  AnzBit : INT ;    //Anzahl der Bits
  Wdh : BOOL ;    //Am Ende von Vorn beginnen (1: Ja/ 0: Nein)
END_VAR
VAR_TEMP 
  Schleife : INT ;    
  SpBer : INT ;    //Speicherbereich
  DBNr : INT ;    
  StAdr : DWORD ;    
END_VAR
BEGIN
NETWORK
TITLE =Ausführung, nur wenn Takt

      U     #Takt; 
      SPBN  Ende; 
NETWORK
TITLE =Anypointer Auswerten

//-------------------------------------------------------------------------------
      L     P##Adr; // Startadresse in Adressregister laden
      LAR1  ; 
      L     B [AR1,P#1.0]; // Datentyp

      L     W [AR1,P#4.0]; // DB-Nummer
      T     #DBNr; 

      L     B [AR1,P#6.0]; // Speicherbereich
      T     #SpBer; 

      L     D [AR1,P#6.0]; // Adresse auslesen
      L     DW#16#7FFFF; // Maske für Bytadresse + Bitadresse 
      UD    ; 
      T     #StAdr; 
      LAR1  ; 
//-------------------------------------------------------------------------------
// Speicherbereich auswerten
      L     W#16#83; // Merker
      L     #SpBer; 
      ==I   ; 
      SPB   SpM; 

      L     W#16#84; // Datenbaustein
      ==I   ; 
      SPB   SpDB; 

      TAK   ; 
      L     W#16#82; // Ausgänge
      ==I   ; 
      SPB   SpA; 

      SPA   Ende; 
//-------------------------------------------------------------------------------
NETWORK
TITLE =Speicherbereich Merker

//-------------------------------------------------------------------------------
SpM:  L     #AnzBit; 
LoM:  T     #Schleife; // Gesetztes Bit im Bereich suchen

      U     M [AR1,P#0.0]; // Wenn gefunden aus Schleife springen
      SPB   GefM; 

      +AR1  P#0.1; 
      L     #Schleife; 
      LOOP  LoM; 
//-------------------------------------------------------------------------------
      SPA   Ende; // Wenn nichts gefunden: Ende
//-------------------------------------------------------------------------------
GefM: R     M [AR1,P#0.0]; // Gesetztes Bit zurück setzen

      L     #Schleife; // Überprüfen, ob letztes Bit im Bereich
      L     1; 
      ==I   ; 
      SPB   WdhM; 

      S     M [AR1,P#0.1]; // Nächstes Bit setzen
      SPA   Ende; 
//--------------------------------------------------------------------------
WdhM: U     #Wdh; 
      SPBN  Ende; 

      L     #StAdr; // Startadresse in Adressregister laden
      LAR1  ; 
      S     M [AR1,P#0.0]; // Erstes Bit setzen
//-------------------------------------------------------------------------------

NETWORK
TITLE =Speicherbereich Datenbaustein

//-------------------------------------------------------------------------------
SpDB: AUF   DB [#DBNr]; 
      L     #AnzBit; 
LoDB: T     #Schleife; // Gesetztes Bit im Bereich suchen

      U     DBX [AR1,P#0.0]; // Wenn gefunden aus Schleife springen
      SPB   GefD; 

      +AR1  P#0.1; 
      L     #Schleife; 
      LOOP  LoDB; 
//-------------------------------------------------------------------------------
      SPA   Ende; // Wenn nichts gefunden: Ende
//-------------------------------------------------------------------------------
GefD: R     DBX [AR1,P#0.0]; // Gesetztes Bit zurück setzen

      L     #Schleife; // Überprüfen, ob letztes Bit im Bereich
      L     1; 
      ==I   ; 
      SPB   WdhD; 

      S     DBX [AR1,P#0.1]; // Nächstes Bit setzen
      SPA   Ende; 
//--------------------------------------------------------------------------
WdhD: U     #Wdh; 
      SPBN  Ende; 

      L     #StAdr; // Startadresse in Adressregister laden
      LAR1  ; 

      S     M [AR1,P#0.0]; // Erstes Bit setzen
//-------------------------------------------------------------------------------

NETWORK
TITLE =Speicherbereich Ausgänge

//-------------------------------------------------------------------------------
SpA:  L     #AnzBit; 
LoA:  T     #Schleife; // Gesetztes Bit im Bereich suchen

      U     A [AR1,P#0.0]; // Wenn gefunden aus Schleife springen
      SPB   GefA; 

      +AR1  P#0.1; 
      L     #Schleife; 
      LOOP  LoA; 
//-------------------------------------------------------------------------------
      SPA   Ende; // Wenn nichts gefunden: Ende
//-------------------------------------------------------------------------------
GefA: R     A [AR1,P#0.0]; // Gesetztes Bit zurück setzen

      L     #Schleife; // Überprüfen, ob letztes Bit im Bereich
      L     1; 
      ==I   ; 
      SPB   WdhA; 

      S     A [AR1,P#0.1]; // Nächstes Bit setzen
      SPA   Ende; 
//--------------------------------------------------------------------------
WdhA: U     #Wdh; 
      SPBN  Ende; 

      L     #StAdr; // Startadresse in Adressregister laden
      LAR1  ; 
      S     A [AR1,P#0.0]; // Erstes Bit setzen
//-------------------------------------------------------------------------------

NETWORK
TITLE =Register wiederherstellen

Ende: NOP 0;
END_FUNCTION
 
Da ein Any ja ein Bereichszeiger ist, brauchst du die länge ja nicht als Extra Parameter!
Du brauchst auch keinen unterschiedlichen Code für Mer, Db, etc, da in dem Adressregister die Bereichskennung mit drinn ist. Du musst nur bei DB aufpassen das den Db aufmachst! Und bei Di den Di (wobei Ich da meist die Bereichskennung ändere!)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke für die Antwort.
Erstes verstehe ich, die Länge kann im Any-Pointer mit angegeben werden.
Wenn ich für die Speicherbereiche keinen unterschiedlichen Code schreiben muss, wie greife ich denn dann auf das Bit zu? Z.B. bei "U M [AR1,P#0.0];" gebe ich an, dass ich auf einen Merkerbereich schaue. Wie schreibe ich es, wenn es allgemein gültig sein soll?
 
Einfach die Bereichskennung "M" in der Anweisung weglassen: "U [AR1,P#0.0]"
siehe Step7 Hilfe zu AWL > Indirekte Adressierung > Bereichsübergreifende, registerindirekte Adressierung


Bei der bereichsinternen indirekten Adressierung wird der Speicherbereich im Operandenkennzeichen der Anweisung angegeben. Das Operandenkennzeichen enthält den Speicherbereich und die Zugriffsgröße, eine eventuell im Adressregister enthaltene Speicherbereichskennung wird ignoriert.
"U M [AR1,P#0.0]" "L LD [AR1,P#0.0]"

Bei der bereichsübergreifenden indirekten Adressierung wird kein Speicherbereich in der Anweisung angegeben, sondern aus dem Adressregister entnommen. Das Operandenkennzeichen enthält nur die Zugriffsgröße, bei Bitzugriffen entfällt das Operandenkennzeichen ganz, die Zugriffsgröße "Bit" ist schon aus der Operation (U O X = S R) eindeutig zu erkennen.
Diese Variante ist vollkommen flexibel, der komplette Pointer kann zur Laufzeit erstellt und mit der selben Anweisung verarbeitet werden (*)
"U [AR1,P#0.0]" "L D [AR1,P#0.0]"

(*) außer Zugriff auf Peripherieausgänge (PA): es gibt keinen bereichsübergreifenden Pointer auf PA, auf Peripherieausgänge kann nur mit bereichsinterner Adressierung zugegriffen werden.

Harald
 
Zurück
Oben