indirekte Adressierung und Pointer ??????????????

M

Mathias W.

Guest
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Leute, brauche ein Schieberegister das folgende ersetzt und Flexibler zu Handhaben ist!


Netzwerk 1:
U M 0.0 // SPS-Taktmerker
FP M 10.0 // Pos-Flanke
= M 11.0 // Flankenimpulsmerker

Netzwerk 2:
U M 11.0
SPBN M001

AUF DB 10
L DBB 4
T DBB 5
L DBB 3
T DBB 4
L DBB 2
T DBB 3
L DBB 1
T DBB 2
L DBB 0
T DBB 1

L EB 1
T DBB 0

M001: NOP 0

Dieser Code funktioniert ja, aber da ich so circa 100 Impulse land die Daten im DB erhalten muß ist das verdammt viel Schreibarbeit und das ganze ist äußerst unflexsibel.

Ich habe dieses ausprobiert, aber es funktioniert nicht!!!!

FC irgendwas

Netzwerk 1:

AUF DB [#DB_Nummer] // Die DB-Nr wird beim Aufruf des FC's an die
// Lokalvariable übergeben (funktioniert noch)

L #Takte // hier wird die Länge Schieberegisters erstellt
SCHL: T #Sch_Zaehler

L DBB [#DB_Nr_Lesen] // z.B. Byte 9 einlesen
T DBB [#DB_Nr_Schreiben] // und in Byte 10 ablegen, danach
// Byte 8 einlesen und in Byte
L #DB_Nr_Lesen // 9 ablegen, usw.
+ -1 // "DB_Nr_Lesen"
L #DB_Nr_Schreiben // und "DN_Nr_Schreiben" sind Lokal-
+ -1 // Variablen vom Typ DWORD

L #Sch_Zaehler
LOOP SCHL

NOP 0
L #Ein_Byte // Nach jedem Schleifendurchlauf werden die neuen
T DBB 0 // Informationen im DB XX.DBB 0 gespeichert

Wenn ich den Code in die SPS (CPU 313C) dann geht die CPU in Stop und der Fehler liegt irgendwo bei der Zeile:

L DBB [#DB_Nr_Lesen] und
T DBB [#DB_Nr_Schreiben].

wenn ich dort direkte Adressen eingebe dann läufts! Was aber dann kein Schieberegister mehr ist!

Kann mir jemand helfen bei der indirekten Adressierung, aber bitte ganz langsam, zum mitmeißeln????

Gruß Mathias
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Sorry, man kann schon mal was vergessen, oder???? :roll:

********************************************************
OB 1

Netzwerk 1:
U "Taktmerker7"
FP "Flankenmerker 1"
= "Taktflanke"

Netzwerk 2:
U "Taktflanke"
SPBN M004

CALL FC96
Takte :=100
Ein_Byte:=EB1
DB_Nr :=96

M004: NOP 0
*****************************************************
FC 96:
Deklarationsteil:
IN:
Takte = Integer
Ein_Byte = Byte
DB_Nr = Integer
OUT:
IN/OUT:
TEMP:
Sch_Zaehler = Integer
DB_Nummer = Integer
Zahl1 = DWord
Zahl2 = DWord

Netzwerk 1:
L #DB_Nr
T #DB_Nummer

L #Takte
T #Zahl1

L #Zahl1
+ -1
T #Zahl2

Netzwerk 2:
AUF DB [#DB_Nummer]

L #Takte
SCHL: T #Sch_Zaehler
L #Zahl1
SLW 3

L #Zahl2
SLW 3

L DBB [#Zahl2]
T DBB [#Zahl1]

L #Zahl1
+ -1
T #Zahl1

L #Zahl2
+ -1
T #Zahl2

L #Sch_Zaehler
LOOP SCHL

NOP 0
L #Ein_Byte
T DBB 0

Ich hoffe dieses Beispiel sagt etwas mehr aus! wenn nicht dann fragt mich ruhig nochmal! Brauche dringend hilfe!!!!
 
Problem

also erstmal solltest du SLD anstatt SLW benutzen, sowie + L#-1. Sollte aber bei 100 Bytes noch keine Probleme bereiten. Den Rest probier ich mal.

MfG
André Räppel
 
Lösung

so, das müsste jetzt so gehen. Die SLW die sind ja nur im Akku gelandet und nich auf der Variable. Kannst aber in deinem Fall direkt vom Schleifenzähler abhängig machen da du ja vom grösseren Wert zum kleineren gehst. Hier mal der Lösungsansatz. Nachvollziehen und Verschönern musste ihn selber. Bedenke auch solche Sachen mit Datenformaten.

Code:
FUNCTION FC 96 : VOID
TITLE =
AUTHOR : ARaeppel
VERSION : 1.0


VAR_INPUT
  Takte : INT ;	
  Ein_Byte : BYTE ;	
  DB_Nr : INT ;	
END_VAR
VAR_TEMP
  Sch_Zaehler : INT ;	
  DB_Nummer : INT ;	
  Adr_Quelle : DWORD ;	
  Adr_Ziel : DWORD ;	
END_VAR
BEGIN
NETWORK
TITLE =

      L     #DB_Nr; 
      T     #DB_Nummer; 
NETWORK
TITLE =

      AUF   DB [#DB_Nummer]; 

      L     #Takte; 
SCHL: T     #Sch_Zaehler; 

// Schleifenzähler im Akku
      SLD   3; 
      T     #Adr_Ziel; 

      L     #Sch_Zaehler; 
      +     L#-1; 
      SLD   3; 
      T     #Adr_Quelle; 


      L     DBB [#Adr_Quelle]; 
      T     DBB [#Adr_Ziel]; 


      L     #Sch_Zaehler; 
      LOOP  SCHL; 


      L     #Ein_Byte; 
      T     DBB    0; 
END_FUNCTION

MfG
André Räppel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ich habe mir jetzt nicht viel zeit genommen, und den code auch nicht ganz
durchgeschaut, aber bist du sicher das das mit den temporären lokalvariblen von fc&s geht?
mit den dingern sollte man vorsichtig sein, besser nen fb + idb anlegen und statische lokalvariablen benutzen.

muss die db-nr nicht auch mit slw angepasst werden?

bei einem schieberegister ist es einfacher mit den adressregistern zu arbeiten.


also

#Pointer
slw 3

LAR1

AUF DB96

L #Wert_1
T DBW [AR1,P#0.0]

L #Wert_2
T DBW [AR1,P#2.0]


wenn der Pointer=4 ist dann wird wert_1 in dbw4 eingetragen und wert_2 in dbw6
 
Code

Also DB-Nr muss nicht angepasst werden und wenn man für sowas nen FB mit IDB verwendet das is glatte Verschwendung. Mit den temporären Variablen das klappt sofern sie immer beschrieben werden. Es passiert ja alles in einem SPS-Zyklus und es muss nichts gemerkt werden. Die Verwendung des Adressregisters ist in dem Fall nicht nötig, da es alles über bereichsinterne indirekte Adressierung erfolgt.

MfG
André Räppel
 
Es funktioniert!!!!

Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke, Danke,
Du rettest einem Kleingeist das Leben, das Problem ist immer:

Wie sollst du was finden, wenn Du nicht weißt wonach Du suchst!!!!!

Danke, alles funktioniert bestens!!!

Gruß Mathias

P.S.: über den Vorschlag von Markus denke ich noch nach, es wird wahrscheinlich so kommen das das Ding in einen FB kommt und mit einem Instanz-DB versorgt wird, aber das weiss ich noch nicht!
:lol:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Mathias
Bin auch der Meinung, dass für diese Aufgabe eine Funktion ausreicht.

Obwohl Du schon eine Lösung gefunden hast, poste ich hier noch meine beiden Lösungsvorschläge.

Die erste Variante arbeitet ohne Adressregister (AR1 oder AR2).

Code:
FUNCTION FC1 : VOID
TITLE =Schieberegister mit speicherindirekter Adressierung

VAR_INPUT
  DB_Nr : INT ;	//DB-Nr. des Schieberegisters
  Takte : INT ;	//Länge des Schieberegister 
  Ein_Byte : BYTE ;	//Akt.Wert
END_VAR

VAR_TEMP
  DB_Nummer : INT ;	//Temp.Variable für DB-Nr.
  Sch_Zaehler : INT ;	//Akt.Schleifenzähler
  Zeiger_lesen : DWORD ;	//Lesezeiger für die speicherindirekte Adressierung
  Zeiger_schreiben : DWORD ;	//Schreibzeiger für die speicherindirekte Adressierung
END_VAR

BEGIN
NETWORK
TITLE =DB aufschlagen
//Parameter können in einem FC nicht direkt für die Speicherindirekte 
//Adressierung verwendet werden, darum wird die DB-Nr. zuerst in eine 
//Temp.Variable kopiert.
      L     #DB_Nr; 
      T     #DB_Nummer; 
      AUF   DB [#DB_Nummer]; 

NETWORK
TITLE =Prüfen ob die Länge des Schieberegisters  1 ist
//Hier wird als Beispiel einer der möglichen Sonderfälle geprüft. 
//Im Baustein könnte z.B. noch folgendes gerprüft werden:
//- DB-Nr. gültig
//- Länge des DB gültig
      L     #Takte; 
      L     1; 
      ==I   ; 
      SPB   Lae1; 

NETWORK
TITLE =Schleife für Schieberegister

//letzte Byteadresse im Schieberegister berechnen
      L     #Takte; 
      +     L#-1; 
      SLD   3; 
      T     #Zeiger_schreiben; 

//zweitletzte Byteadresse im Schieberegister berechnen
      L     P#1.0; //Im Akku steht 00000000_00000000_00000000_00001000
      -D    ; 
      T     #Zeiger_lesen; 

      L     #Takte; 
      +     L#-1; 
SCHL: T     #Sch_Zaehler; 

      L     DBB [#Zeiger_lesen]; 
      T     DBB [#Zeiger_schreiben]; 

//Lesezeiger wird zum Schreibzeiger 
      L     #Zeiger_lesen; 
      T     #Zeiger_schreiben; 

//Neuer Lesezeiger berechnen -> um 1 Byte verkleinern
      L     P#1.0; 
      -D    ; 
      T     #Zeiger_lesen; 

      L     #Sch_Zaehler; 
      LOOP  SCHL; 

NETWORK
TITLE =Akt.Wert in Schieberegister schreiben

Lae1: L     #Ein_Byte; 
      T     DBB    0; 
END_FUNCTION

In der zweiten Variante wird das AR1 verwendet.

Code:
FUNCTION FC 2 : VOID
TITLE =Schieberegister mit registerindirekter Adressierung

VAR_INPUT
  DB_Nr : INT ;	//DB-Nr. des Schieberegisters
  Takte : INT ;	//Länge des Schieberegister 
  Ein_Byte : BYTE ;	//Akt.Wert
END_VAR

VAR_TEMP
  DB_Nummer : INT ;	//Temp.Variable für DB-Nr.
END_VAR

BEGIN
NETWORK
TITLE =DB aufschlagen
//Parameter können in einem FC nicht direkt für die Speicherindirekte 
//Adressierung verwendet werden, darum wird die DB-Nr. zuerst in eine 
//Temp.Variable kopiert.
      L     #DB_Nr; 
      T     #DB_Nummer; 
      AUF   DB [#DB_Nummer]; 

NETWORK
TITLE =Prüfen ob die Länge des Schieberegisters  1 ist
//Hier wird als Beispiel einer der möglichen Sonderfälle geprüft. 
//Im Baustein könnte z.B. noch folgendes gerprüft werden:
//- DB-Nr. gültig
//- Länge des DB gültig
      L     1; 
      L     #Takte; 
      ==I   ; 
      SPB   Lae1; 

NETWORK
TITLE =Schleife für Schieberegister

//zweitletzte Byteadresse im Schieberegister berechnen
      PUSH  ; //Anzahl Takte wird später noch einmal benötigt -> Kopie in Akku2
      +     L#-2; 
      SLD   3; 
      LAR1  ; //-> Zeiger in Akku1 wird in das AR1 geladen

      TAK   ; //Anzahl Takte steht wieder im Akku1
      +     L#-1; //Anzahl Schleifendurchläufe berechnen
SCHL: L     DBB [AR1,P#0.0]; 
      T     DBB [AR1,P#1.0]; //Offset auf die nächste Byteadresse

      TAK   ; //Schleifezähler steht wieder im Akku1

//AR1 muss über den Akku1 um 1 Byte verkleinert werden
      TAR1  ; //AR1 in Akku1 schreiben (Schleifezähler steht im Akku2)
      +     L#-8; //Akku1 um 1 Byte dekrementieren (Wert 8 steht für 1000 -> P#1.0)
      LAR1  ; //Akku1 wieder in AR1

      TAK   ; //Schleifezähler steht wieder im Akku1
      LOOP  SCHL; 

NETWORK
TITLE =Akt.Wert in Schieberegister schreiben
Lae1: L     #Ein_Byte; 
      T     DBB    0; 

END_FUNCTION

PS: Kennst Du die Möglichkeit solche Programme im HALT-Modus (Debugmodus) zu beobachten?
 
Leider nein

Hallo, leider kenne ich diese möglich nicht, wäre sehr interresant dies zu erfahren.

Gruß Mathias
 
Hallo Mathias (Sorry war zuvor nicht eingelogt)
Damit ein Baustein im Haltemodus beobachtet werden kann muss folgendermasen vorgegangen werden:

1. Der Baustein muss Online geöffnet werden. (Umschalten auf Online)
2. Im Editor muss explizit die Darstellung AWL angewählt sein. (unbedingt kontrollieren)
3. Die CPU muss sich im Testbetrieb und nicht im Prozessbetrieb befinden (Standard ist Testbetrieb, kann aber je nach CPU in der HW-Konfiguration geändert werden, PCL-SIM ist Standardmässig im Prozessbetrieb)

Nun muss noch unter Ansicht die Haltepunktleiste angezeigt werden.
Jetzt kann ein Haltepunkt im Baustein plaziert und anschliessend aktiviert werden. Wenn nun das Programm an einem Haltepunkt vorbeikommen, wechselt die CPU vom RUN-Betrieb in den HALT-Betrieb (gelbe Anzeige unten rechts). Die STOP-LED an der CPU leuchtet und die RUN-LED blinkt. In diesem Modus ist die Ausgabesperre aktiv, sprich alle Ausgänge werden log.0
Es öffnet sich ein Fenster indem der Akku1/Akku2, die Statusbit das AR1 /AR2 und die beiden DB-Register angezeigt werden.
Jetzt kann das Programm Schritt für Schritt beobachtet werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke Martin, könnte bei diesem Projekt noch nützlich sein!
Ich bin eigentlich mehr Elektriker und kein Profiprogrammierer, nur manchmal hat mein Chef das wohl vergessen???

Naja, Danke für den Tipp, Gruß Mathias :lol:
 
Zurück
Oben