Step 7 Any Pointer in AR1 für globales DB

Noebsi

Level-2
Beiträge
12
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo, ich versuche gerade ANY Pointer zu verstehen und habe hierzu folgendes probiert:
Das ganze ist auf einer 300 in einem FB geschrieben und ich will mir den Wert 44 auf Array[0..10]ofReal Adresse 0.0 im globalen Datenbaustein 1 schreiben.

Code:
      LAR1  P##tPoint1                  //Zeiger ins Adressregister laden
      L     W#16#10                     //Syntax ID --> bei S7 immer 10
      T     LB [AR1,P#0.0]
      L     W#16#8                      //Typ REAL
      T     LB [AR1,P#1.0]
      L     11                          //Anzahl der REAL
      T     LW [AR1,P#2.0]
      L     1                           //Quell-Datenbaustein
      T     LW [AR1,P#4.0]
      L     0                           //Anfang der Quelle
      SLD   3                           //Pointer bauen
      T     LD [AR1,P#6.0]
      L     DW#16#84000000                //Speicherbereich
      T     LB [AR1,P#6.0]

      AUF   "DB_DATA"
      L     44
      T     DBD [AR1,P#0.0]

Problem:
Der Wert 44 wird nicht auf mein erstes REAL im Array (Adresse 0.0) sondern auf das 4e (Adresse 12.0) geschrieben.
Auf dem 4en REAL steht nun also der Wert 002C0000.

Hab ich hier was falsch verstanden?
Ich dachte der Befehl T DBD[AR1, P#0.0] soll mir den Wert 44 als Double in DB1 auf Stelle AR1 mit Offset 0 schreiben.

Lg
 
Hallo, ich versuche gerade ANY Pointer zu verstehen und habe hierzu folgendes probiert:
Das ganze ist auf einer 300 in einem FB geschrieben und ich will mir den Wert 44 auf Array[0..10]ofReal Adresse 0.0 im globalen Datenbaustein 1 schreiben.

Code:
      LAR1  P##tPoint1                  //Zeiger ins Adressregister laden
      L     W#16#10                     //Syntax ID --> bei S7 immer 10
      T     LB [AR1,P#0.0]
      L     W#16#8                      //Typ REAL
      T     LB [AR1,P#1.0]
      L     11                          //Anzahl der REAL
      T     LW [AR1,P#2.0]
      L     1                           //Quell-Datenbaustein
      T     LW [AR1,P#4.0]
      L     0                           //Anfang der Quelle
      SLD   3                           //Pointer bauen
      T     LD [AR1,P#6.0]
      L     DW#16#84000000                //Speicherbereich
      T     LB [AR1,P#6.0]

      AUF   "DB_DATA"
      L     44
      T     DBD [AR1,P#0.0]

Problem:
Der Wert 44 wird nicht auf mein erstes REAL im Array (Adresse 0.0) sondern auf das 4e (Adresse 12.0) geschrieben.
Auf dem 4en REAL steht nun also der Wert 002C0000.

Hab ich hier was falsch verstanden?
Ich dachte der Befehl T DBD[AR1, P#0.0] soll mir den Wert 44 als Double in DB1 auf Stelle AR1 mit Offset 0 schreiben.

Lg
Dein AR1 zeigt ziemlich sicher nicht auf DBX0.0
Was für eine Variable ist #tPoint1? Wo ist die deklariert? In TEMP oder STAT?
Dein Code sieht aus, als ob du einen ANY-Pointer zusammenbasteln willst - wofür?
Register-indirekte Adressierung mit Adressregistern arbeitet nicht mit ANY-Pointern.

(PS: Löschst du wieder alles wenn dir die Antworten nicht gefallen?)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ich nehme an, dass P##tPoint1 der any-zeiger im temp-bereich ist.
was du machst ist einen zeiger auf die anfangsadresse diesers zeigers zu erstellen.
mit diesem zeiger kannst du nicht mal eben direkt ein dbd beschreiben.
schau dir das mal an
und das

so sieht dein programm online aus
1730208757392.png
 
ich will mir den Wert 44 auf Array[0..10]ofReal Adresse 0.0 im globalen Datenbaustein 1 schreiben.

Code:
LAR1  P#DBX 0.0   //Anfangsadresse des REAL-Array in DB1
AUF   DB1

L     44
T     DBD [AR1,P#0.0]


PS:
Das ganze ist auf einer 300 in einem FB geschrieben
Vorsichtshalber Achtung: in einem FB darf man das AR2 nicht verändern, wenn man noch auf STAT-Variablen im IDB zugreifen will.
Und wenn man auf die Adressen von STAT-Variablen zugreifen will, dann muss man den Multiinstanz-Offset aus AR2 addieren.
 
Zuletzt bearbeitet:
Code:
LAR1  P#DBX 0.0   //Anfangsadresse des REAL-Array in DB1
AUF   DB1

L     44
T     DBD [AR1,P#0.0]

Ich denke er möchte dementsprechend dann noch alle Indexe des Array beschreiben oder?
Dann entweder mit Loop oder:

L 44
T DBD[AR1, P#0.0] // Erster Index
T DBD[AR1, P#4.0] // Erster Index
T DBD[AR1, P#8.0] // Erster Index
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich denke er möchte dementsprechend dann noch alle Indexe des Array beschreiben oder?
Ja, das wollte er gestern mit LOOP, hat dann aber alles gelöscht und "SOLVED" geschrieben. War dann wohl doch noch nicht so ganz "solved" ...
 
Hallo!

Erstmal vielen Dank für die ganzen Antworten!
Hier nochmal: Ich habe erst vor 2 Wochen mit der SPS Programmierung begonnen und habe auch zuvor wenig Erfahrung in der Programmierung generell, deshalb bitte ich um Verständnis, falls ich ab und an "blöde" Fragen stelle.

- tPoint1 ist eine ANY die in TEMP deklariert ist.
- Den ANY Pointer wollte ich zur Daten Verschiebung in Datenbausteinen nehmen, jedoch weiß ich nun mittlerweile, dass diese eher für größere Datenblöcke verwendet wird und ich mit "normalem" indirekten Adressieren besser bedient bin.
ich nehme an, dass P##tPoint1 der any-zeiger im temp-bereich ist.
was du machst ist einen zeiger auf die anfangsadresse diesers zeigers zu erstellen.
mit diesem zeiger kannst du nicht mal eben direkt ein dbd beschreiben.
Ich habe angenommen, dass durch das deklarieren des ANY meine Anfangsadresse von ihm an DB1 0.0 liegt.
Deshalb wollte ich auf diese Anfangsadresse zeigen und schreiben.
Code:
LAR1  P#DBX 0.0   //Anfangsadresse des REAL-Array in DB1
AUF   DB1

L     44
T     DBD [AR1,P#0.0]

PS:
Vorsichtshalber Achtung: in einem FB darf man das AR2 nicht verändern, wenn man noch auf STAT-Variablen im IDB zugreifen will.
Und wenn man auf die Adressen von STAT-Variablen zugreifen will, dann muss man den Multiinstanz-Offset aus AR2 addieren.
Danke, so habe ich das ganze mittlerweile gelöst.
Der Tipp ist ebenfalls sehr hilfreich, da ich das leider erst nach vielem suchen im Internet herausgefunden habe.

Mein neues Programm läuft nun in einem FC, womit das Problem mit AR2 gelöst sein sollte.
Wie könnte ich den Multiinstanzen Offset denn eruieren?
Dein AR1 zeigt ziemlich sicher nicht auf DBX0.0
Was für eine Variable ist #tPoint1? Wo ist die deklariert? In TEMP oder STAT?
Dein Code sieht aus, als ob du einen ANY-Pointer zusammenbasteln willst - wofür?
Register-indirekte Adressierung mit Adressregistern arbeitet nicht mit ANY-Pointern.

(PS: Löschst du wieder alles wenn dir die Antworten nicht gefallen?)
Ja, das wollte er gestern mit LOOP, hat dann aber alles gelöscht und "SOLVED" geschrieben. War dann wohl doch noch nicht so ganz "solved" ...
Hierzu:
Den anderen Beitrag habe ich "gelöscht" da noch keine Antworten dazu geschrieben wurden und ich das Thema vorerst zur Seite schieben wollte nachdem ich das ganze mit einem JUMP anstelle des LOOP gelöst habe.

Deine Frustration verstehe ich natürlich wenn du schon beim Verfassen einer Erklärung warst und das tut mir leid.
JEDOCH bitte ich dich das wo Anders rauszulassen, da mich deine leicht passiv aggressive Art eher dazu bringt nicht mehr auf diesem Forum posten zu wollen und es mir so schon schwer genug fällt im Alleingang SPS von Grund auf zu lernen.

Nun zum Programm:
Ich habe das ganze über den Haufen geworfen und in einem FC neu angefangen.
So sieht das ganze gerade aus (ich arbeite noch daran):
Code:
      U     #TAKT
      UN    #FLANKENMERKER
      =     #POS_FLANKE                 //Taktprüfer
      U     #POS_FLANKE
      SPB   THEN                        //Bei positiver Flanke wird gearbeitet
      SPA   ELSE                        //Sonst übergeht SPB Befehl und springt hier absolut zu ELSE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
THEN: AUF   "DB_DATA"
      L     #ZAEHLER
      SLW   3
      LAR1
      L     #IN
      T     DBD [AR1,P#0.0]
      L     44
      SLW 
      LAR2
      L     11
SPRG: T     #tForZaehler
      AUF   "DB_DATA"
      L     DBD [AR1,P#0.0]
      T     #tSave
      L     4
      +AR1
      AUF   "DB_DATA_REVERSE"
      L     #tSave
      T     DBD [AR2,P#0.0]
      L     -4
      +AR2
      L     #tForZaehler
      LOOP  SPRG
      L     #ZAEHLER
      +     4
      T     #ZAEHLER
      L     #ZAEHLER
      L     44
      ==D 
      SPB   FULL
      SPA   ELSE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FULL: L     0
      T     #ZAEHLER                    //Setze Zähler zurück, wenn Datenbaustein voll
ELSE: U     #TAKT
      SPB   EIN
      R     #FLANKENMERKER              //Resete den Flankenmerker
      SPA   ENDE                        //Wenn TAKT FALSE wird SPB übergangen und absolut auf AUS gesprungen
EIN:  S     #FLANKENMERKER              //Setze den Flankenmerker
      SPA   ENDE
ENDE: L     0

Was mich trotzdem noch interessieren würde wäre, warum ich bei meiner ursprünglichen Methode den Wert an Adresse 12.0 anstehen hatte.
Mit welchen Werten wurden BYTE 0-11 voll geschrieben, sodass ich hier erst bei Byte Adresse 12 anfing, oder hat es etwas mit meinen Befehlen zu tun?

Lg
Noebsi
 
Zuletzt bearbeitet:
Mittlerweile bin ich in meinem FC an diesem Punkt:

Code:
      U     M      0.5
      UN    "FLANKENMERKER"
      =     "POS_FLANKE"                //Taktprüfer
      U     "POS_FLANKE"
      SPB   THEN                        //Bei positiver Flanke wird gearbeitet
      SPA   ELSE                        //Sonst übergeht SPB Befehl undspringt hier absolut zu ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
THEN: AUF   "DB_DATA"
      L     "ZAEHLER"                   //Lade Durchlaufzähler in AR1 --> 4Byte Schritte (0..4..8..12..etc.)
      SLW   3
      LAR1 
      L     7                           //Testwert statt Eingabewert, zum Testen
      T     DBD [AR1,P#0.0]
      L     44                          //Lade Startwert 44 in AR2 --> Zählt 11 mal runter weil Array[0..10]
      SLW   
      LAR2 
      L     11                          //Lade 11 als LOOP Länge in ForZähler (Zwischenspeicher)
SPRG: T     #tForZaehler
      AUF   "DB_DATA"
      L     DBD [AR1,P#0.0]
      AUF   "DB_DATA_REVERSE"
//      T     DBD [AR2,P#0.0]             //Schreibe Wert von AR1 DB1 auf AR2 DB2
      L     4
//      +AR1 
      L     -4
//      +AR2 
      L     #tForZaehler
      LOOP  SPRG
      L     "ZAEHLER"
      +     4                           //Erhöhe Durchlaufzähler um "1" (4Byte Schritte)
      T     "ZAEHLER"
      L     "ZAEHLER"
      L     44
      ==I                               //Wenn Zähler voll, setze Zähler auf 0
      SPB   FULL
      SPA   ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FULL: L     0
      T     "ZAEHLER"                   //Setze Zähler zurück, wenn Datenbaustein voll
ELSE: U     M      0.5
      SPB   EIN
      R     "FLANKENMERKER"             //Resete den Flankenmerker
      SPA   ENDE                        //Wenn TAKT FALSE wird SPB übergangen und absolut auf AUS gesprungen
EIN:  S     "FLANKENMERKER"             //Setze den Flankenmerker
      SPA   ENDE
ENDE: L     0

Problem: Wenn ich AR1 in der LOOP erhöhen möchte oder AR2 verringern möchte stoppt die CPU.
Außerdem kann ich den Befehl "T DBD [AR2,P#0.0]" wieder nicht ausführen ohne einen CPU Stopp zu erhalten.
Wird das AR2 in FC auch im Hintergrund verwendet oder habe ich hier einen anderen Fehler?

Außerdem würde mich interessieren ob es im Simatic Manager beim "Debuggen" von AWL Code auch irgendwo ein Fehlermeldungsfenster gibt?
Das würde das Problem suchen bei CPU Stopps enorm erleichtern.

Lg
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mein neues Programm läuft nun in einem FC, womit das Problem mit AR2 gelöst sein sollte.
Wie könnte ich den Multiinstanzen Offset denn eruieren?
Forumssuche: ar2 multiinstanzoffset addieren
liefert z.B. folgendes

Code:
      TAR2                      //Multiinstanzoffset aus AR2
      UD    DW#16#FFFFFF        //Bereichskennung (DB) entfernen
      L     P##String_B         //Adresse String_B in dieser Instanz mit Bereichskennung (DI)
      +D                        //dazu addieren
      LAR1                      //AR1 und DI-Register enthalten nun die Anfangsadresse von String_B


4 Varianten für Kopierschleifen in FB

Den Multiinstanzoffset aus AR2 braucht man nur addieren, wenn man die Adresse einer FB-Instanzvariable im IDB braucht.
Wenn man zwischen globalen DB oder TEMP-Speicher kopiert, braucht man den Multiinstanzoffset aus AR2 nicht addieren. In einem FB muss man beachten, dass man auf die Instanz-Variablen im IDB nicht mehr zugreifen kann, wenn man AR2 oder das DB2/DI-Register verändert. Man kann aber AR2 und das DI-Register in TEMP sichern und später wiederherstellen.


- tPoint1 ist eine ANY die in TEMP deklariert ist.
(...)
Was mich trotzdem noch interessieren würde wäre, warum ich bei meiner ursprünglichen Methode den Wert an Adresse 12.0 anstehen hatte.
Weil LAR1 P##tPoint1 die Adesse L12.0 in AR1 lädt (beim Beobachten des AWL-Codes genau hinsehen!). Die Adresse L12.0 der TEMP-Variable tPoint1 hat nichts mit der Adresse in einem DB zu tun.
Später mit der Anweisung T DBD [AR1,P#0.0] schreibst du in einen DB an den Offset, der gerade in AR1 ist. Die Bereichskennung "L" in AR1 wird ignoriert, weil in der Anweisung explizit "DBD" angegeben ist, also: AR1=L12.0 und "DBD" wird zu DBD12 (ab DBX12.0)
siehe Hilfe zu AWL: Bereichsinterne, registerindirekte Adressierung
 
Problem: Wenn ich AR1 in der LOOP erhöhen möchte oder AR2 verringern möchte stoppt die CPU.
Außerdem kann ich den Befehl "T DBD [AR2,P#0.0]" wieder nicht ausführen ohne einen CPU Stopp zu erhalten.
Wird das AR2 in FC auch im Hintergrund verwendet oder habe ich hier einen anderen Fehler?
Nein, AR2 wird nicht verwendet und kann beliebig verändert werden. PS: Nur bei der Parameterversorgung bestimmter CALL könnte AR2 verwendet/verändert werden (da gibt es irgendwo ein Hilfethema). Wenn man AR2 erst direkt vor der Verwendung mit einer Adresse lädt, dann ist das aber kein Problem.
Deine CPU geht vermutlich in STOP, weil deine Adresse in AR2 nicht korrekt ist. Weil du nie eine sinnvolle gültige Adresse in AR2 lädst.

Außerdem würde mich interessieren ob es im Simatic Manager beim "Debuggen" von AWL Code auch irgendwo ein Fehlermeldungsfenster gibt?
Das würde das Problem suchen bei CPU Stopps enorm erleichtern.
Zielsystem > Baugruppenzustand > Diagnosepuffer
 
Zuletzt bearbeitet:
Forumssuche: ar2 multiinstanzoffset addieren
liefert z.B. folgendes




4 Varianten für Kopierschleifen in FB

Den Multiinstanzoffset aus AR2 braucht man nur addieren, wenn man die Adresse einer FB-Instanzvariable im IDB braucht.
Wenn man zwischen globalen DB oder TEMP-Speicher kopiert, braucht man den Multiinstanzoffset aus AR2 nicht addieren. In einem FB muss man beachten, dass man auf die Instanz-Variablen im IDB nicht mehr zugreifen kann, wenn man AR2 oder das DB2/DI-Register verändert. Man kann aber AR2 und das DI-Register in TEMP sichern und später wiederherstellen.



Weil LAR1 P##tPoint1 die Adesse L12.0 in AR1 lädt (beim Beobachten des AWL-Codes genau hinsehen!). Die Adresse L12.0 der TEMP-Variable tPoint1 hat nichts mit der Adresse in einem DB zu tun.
Später mit der Anweisung T DBD [AR1,P#0.0] schreibst du in einen DB an den Offset, der gerade in AR1 ist. Die Bereichskennung "L" in AR1 wird ignoriert, weil in der Anweisung explizit "DBD" angegeben ist, also: AR1=L12.0 und "DBD" wird zu DBD12 (ab DBX12.0)
siehe Hilfe zu AWL: Bereichsinterne, registerindirekte Adressierung
Danke das hat mir sehr geholfen das ganze Thema zu verstehen!

Nein, AR2 wird nicht verwendet und kann beliebig verändert werden. PS: Nur bei der Parameterversorgung bestimmter CALL könnte AR2 verwendet/verändert werden (da gibt es irgendwo ein Hilfethema). Wenn man AR2 erst direkt vor der Verwendung mit einer Adresse lädt, dann ist das aber kein Problem.
Deine CPU geht vermutlich in STOP, weil deine Adresse in AR2 nicht korrekt ist. Weil du nie eine sinnvolle gültige Adresse in AR2 lädst.


Zielsystem > Baugruppenzustand > Diagnosepuffer
Ich teste das sofort aus, danke!
Den Fehler mit AR2 kann ich mir somit ja erklären, da Adresse 44 nicht existiert, aber warum stoppt die CPU dann auch beim erhöhen des AR1?
Liegt es daran, dass ich bei 11 Durchläufen auf 44 zählen würde und das ja auch außerhalb meines Adressbereiches liegt?

Danke für die großartigen Erklärungen, ich habe bis dato in diesem Forum mehr über S7 Programmierung erfahren als im Rest des Internets.
Leider sind dort vereinzelt viele Erklärungen auf TIA bezogen und lassen sich deshalb oft im Simatic Manager nicht anwenden.

Lg
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
      L     4
//      +AR1
      L     -4
//      +AR2

das erhöht, bzw. verringert deine Adressregister nur um 4 Bit...
Wenn du um Doppelwortbreite ändern willst muss das so aussehen:

Code:
l p#4.0
+ar1

oder kürzer

+ar1 p#4.0

//-ar1 oder -ar2 gibt es nicht. p#-4.0 geht auch nicht. Deshalb musst du mit

tar2
l p#4.0
-d
lar2

verringern
 
Code:
      L     4
//      +AR1
      L     -4
//      +AR2

das erhöht, bzw. verringert deine Adressregister nur um 4 Bit...
Wenn du um Doppelwortbreite ändern willst muss das so aussehen:

Code:
l p#4.0
+ar1

oder kürzer

+ar1 p#4.0

//-ar1 oder -ar2 gibt es nicht. p#-4.0 geht auch nicht. Deshalb musst du mit

tar2
l p#4.0
-d
lar2

verringern
Danke das klingt logisch!

Leider funktioniert das ganze dennoch nicht.
Meine CPU geht nach wie vor auf Stopp sobald AR1 oder AR2 gerechnet werden.
(Der DBD ist nur in klammer, da er auf 44 schreiben würde, was nicht geht. Dazu muss ich eben zuerst AR2 um 4Byte verkleinern.)

Es hat sich nicht viel getan, weil ich die ganze Zeit am Fehlersuchen war, aber so sieht mein Code im Moment aus:
Code:
      U     M      0.5
      UN    "FLANKENMERKER"
      =     "POS_FLANKE"                //Taktprüfer
      U     "POS_FLANKE"
      SPB   THEN                        //Bei positiver Flanke wird gearbeitet
      SPA   ELSE                        //Sonst übergeht SPB Befehl undspringt hier absolut zu ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
THEN: AUF   "DB_DATA"
      L     "ZAEHLER"                   //Lade Durchlaufzähler in AR1 --> 4Byte Schritte (0..4..8..12..etc.)
      SLW   3
      LAR1 
      L     7                           //Testwert statt Eingabewert, zum Testen
      T     DBD [AR1,P#0.0]
      L     44                          //Lade Startwert 44 in AR2 --> Zählt 11 mal runter weil Array[0..10]
      SLW   3
      LAR2 
      L     11                          //Lade 11 als LOOP Länge in ForZähler (Zwischenspeicher)
SPRG: T     #tForZaehler
      AUF   "DB_DATA"
      TAR2                              //AR2 in AKKU1 abspeichern
      L     P#4.0                       //4Byte in AKKU1 laden
      -R                                //AKKU1 von AKKU2 subtrahieren (AR2-4)
      LAR2 
      L     DBD [AR1,P#0.0]
//      +AR1  P#4.0                       //Erhöhen von AR1 um 4Byte (nur eine 4 wären nur 4 Bit)
      AUF   "DB_DATA_REVERSE"
      T     DBD [AR2,P#0.0]             //Schreibe Wert von AR1 DB1 auf AR2 DB2
      L     #tForZaehler
      LOOP  SPRG
      L     "ZAEHLER"
      +     4                           //Erhöhe Durchlaufzähler um "1" (4Byte Schritte)
      T     "ZAEHLER"
      L     "ZAEHLER"
      L     44
      ==I                               //Wenn Zähler voll, setze Zähler auf 0
      SPB   FULL
      SPA   ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FULL: L     0
      T     "ZAEHLER"                   //Setze Zähler zurück, wenn Datenbaustein voll
ELSE: U     M      0.5
      SPB   EIN
      R     "FLANKENMERKER"             //Resete den Flankenmerker
      SPA   ENDE                        //Wenn TAKT FALSE wird SPB übergangen und absolut auf AUS gesprungen
EIN:  S     "FLANKENMERKER"             //Setze den Flankenmerker
      SPA   ENDE
ENDE: L     0

Bearbeitet:
Ok ich hab das ganze mal für AR2 mit -R (Weil sind ja irgendwie Gleitkommazahlen) gemacht, und so geht es.
Jetzt fehlt mir nur noch AR1.
 
Zuletzt bearbeitet:
Danke das klingt logisch!

Leider funktioniert das ganze dennoch nicht.
Meine CPU geht nach wie vor auf Stopp sobald AR1 oder AR2 gerechnet werden.
(Der DBD ist nur in klammer, da er auf 44 schreiben würde, was nicht geht. Dazu muss ich eben zuerst AR2 um 4Byte verkleinern.)

Es hat sich nicht viel getan, weil ich die ganze Zeit am Fehlersuchen war, aber so sieht mein Code im Moment aus:
Code:
      U     M      0.5
      UN    "FLANKENMERKER"
      =     "POS_FLANKE"                //Taktprüfer
      U     "POS_FLANKE"
      SPB   THEN                        //Bei positiver Flanke wird gearbeitet
      SPA   ELSE                        //Sonst übergeht SPB Befehl undspringt hier absolut zu ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
THEN: AUF   "DB_DATA"
      L     "ZAEHLER"                   //Lade Durchlaufzähler in AR1 --> 4Byte Schritte (0..4..8..12..etc.)
      SLW   3
      LAR1
      L     7                           //Testwert statt Eingabewert, zum Testen
      T     DBD [AR1,P#0.0]
      L     44                          //Lade Startwert 44 in AR2 --> Zählt 11 mal runter weil Array[0..10]
      SLW   3
      LAR2
      L     11                          //Lade 11 als LOOP Länge in ForZähler (Zwischenspeicher)
SPRG: T     #tForZaehler
      AUF   "DB_DATA"
      TAR2                              //AR2 in AKKU1 abspeichern
      L     P#4.0                       //4Byte in AKKU1 laden
      -R                                //AKKU1 von AKKU2 subtrahieren (AR2-4)
      LAR2
      L     DBD [AR1,P#0.0]
//      +AR1  P#4.0                       //Erhöhen von AR1 um 4Byte (nur eine 4 wären nur 4 Bit)
      AUF   "DB_DATA_REVERSE"
      T     DBD [AR2,P#0.0]             //Schreibe Wert von AR1 DB1 auf AR2 DB2
      L     #tForZaehler
      LOOP  SPRG
      L     "ZAEHLER"
      +     4                           //Erhöhe Durchlaufzähler um "1" (4Byte Schritte)
      T     "ZAEHLER"
      L     "ZAEHLER"
      L     44
      ==I                               //Wenn Zähler voll, setze Zähler auf 0
      SPB   FULL
      SPA   ELSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FULL: L     0
      T     "ZAEHLER"                   //Setze Zähler zurück, wenn Datenbaustein voll
ELSE: U     M      0.5
      SPB   EIN
      R     "FLANKENMERKER"             //Resete den Flankenmerker
      SPA   ENDE                        //Wenn TAKT FALSE wird SPB übergangen und absolut auf AUS gesprungen
EIN:  S     "FLANKENMERKER"             //Setze den Flankenmerker
      SPA   ENDE
ENDE: L     0

Bearbeitet:
Ok ich hab das ganze mal für AR2 mit -R (Weil sind ja irgendwie Gleitkommazahlen) gemacht, und so geht es.
Jetzt fehlt mir nur noch AR1.
Hätte es für AR1 mit dem Trick von AR2 versucht, jedoch ohne Erfolg.
Hier der Ausschnitt vom Test:

Code:
      L     11                          //Lade 11 als LOOP Länge in ForZähler (Zwischenspeicher)
SPRG: T     #tForZaehler
      AUF   "DB_DATA"
      TAR2                              //AR2 in AKKU1 abspeichern
      L     P#4.0                       //4Byte in AKKU1 laden
      -R                                //AKKU1 von AKKU2 subtrahieren (AR2-4)
      LAR2
      L     DBD [AR1,P#0.0]
      AUF   "DB_DATA_REVERSE"
      T     DBD [AR2,P#0.0]             //Schreibe Wert von AR1 DB1 auf AR2 DB2
      TAR1
      L     P#4.0
      +R  
      LAR1
//      +AR1  P#4.0                       //Erhöhen von AR1 um 4Byte (nur eine 4 wären nur 4 Bit)
      L     #tForZaehler
      LOOP  SPRG

Er schreit mir hier wegen einem Bereichslängenfehler bei Lesen bei Zugriffsadresse 44.
Aber das AR1 ist doch nur nach dem letzten Durchlauf des LOOP 44 und wird danach wieder am Ablaufbeginn mit ZAEHLER überschrieben.
1730297047768.png
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hier mal Beispiele für das Kopieren zu reverser Reihenfolge. Alles ungetestet!
Der Code eignet sich für FB und FC. Bei FC müssen "Merkspeicher" (z.B. #Flankenmerker) in IN_OUT liegen oder Direktzugriff auf globalen Speicher (z.B. Merker)

Code:
      U     M0.5                  //CPU Taktmerker 1Hz
      =     #Kopie_Taktmerker     /weil Taktmerker asynchron! nur einmal lesen!

      U     #Kopie_Taktmerker
      UN    #Flankenmerker
      =     #Pos_Flanke

      U     #Kopie_Taktmerker
      =     #Flankenmerker

//oder einfach mit FP:
//      U     M0.5
//      FP    #Flankenmerker
//      =     #Pos_Flanke


//*** nur ausführen bei Pos_Flanke ***
      U     #Pos_Flanke
      SPBN  ENDE

//*** Kopieren Reverse ***************************************
// DB1.ARRAY_1 [0..10] OF REAL
// DB2.ARRAY_2 [0..10] OF REAL

// FOR i:= 0 TO 10 DO
//   ARRAY_2[10 - i] := ARRAY_1[i];
// END_FOR;

//oder AWL-LOOP-gerecht:
// FOR z:= 11 TO 1 BY -1 DO
//   ARRAY_2[11 - z - 1] := ARRAY_1[z - 1];
// END_FOR;

      L     11                    //11 Durchläufe 11..1
LOP1: T     #z
      +     -1                    // z=11..1 --> i=10..0
      L     4                     //REAL ist 4 Byte
      *D    
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1  hier eintragen
      +D                          //ergibt Offset von ARRAY_1[i]
      T     #tempdwPointer1

      L     11
      L     #z
      -I    
      L     4                     //REAL ist 4 Byte
      *D    
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_2 in DB2  hier eintragen
      +D                          //ergibt Offset von ARRAY_2[10 - i]
      T     #tempdwPointer2

//   ARRAY_2[10 - i] := ARRAY_1[i];     
      AUF   "DB_DATA"
      L     DBD [#tempdwPointer1]   //Speicherindirekte Adressierung
      AUF   "DB_DATA_REVERSE"
      T     DBD [#tempdwPointer2]

      L     #z                    //11..1
      LOOP  LOP1

ENDE: CLR                         //(oder SET oder NOP, irgendwas an Sprungmarke)

Code:
//oder Kopieren mit AR1 registerindirekte Adressierung
//wie in C: for (p1 = &ARRAY_1[0], p2 = &ARRAY_2[10], i = 11; i > 0; i--) *P2-- = *p1++;

      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1 hier eintragen
      T     #tempdwPointer1

      L     10                    //höchster Index
      L     4                     //REAL ist 4 Byte
      *D    
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_2 in DB2 hier eintragen
      +D                          //ergibt Offset von ARRAY_2[10]
      T     #tempdwPointer2

      L     11                    //11 Durchläufe 11..1
LOP2: T     #z

      LAR1  #tempdwPointer1
      AUF   "DB_DATA"
      L     DBD [AR1,P#0.0]       //Bereichsinterne registerindirekte Adressierung

      LAR1  #tempdwPointer2
      AUF   "DB_DATA_REVERSE"
      T     DBD [AR1,P#0.0]

      TAR1                        //AR1 in AKKU1
      L     P#4.0                 //REAL ist 4 Byte
      -D                          //Pointer2 4 Bytes vorher
      T     #tempdwPointer2

      L     #tempdwPointer1
      L     P#4.0                 //REAL ist 4 Byte
      +D                          //Pointer1 4 Bytes weiter
      T     #tempdwPointer1

      L     #z                    //11..1
      LOOP  LOP2

Code:
//oder bei wenigen Kopiervorgängen 
//oder Kopieren von Strukturen und AR1/AR2 zeigen auf den Anfang der Strukturen
//Kopieren ohne Schleife

      LAR1  #tempdwPointer1
      LAR2  #tempdwPointer2

      AUF   "DB_DATA"
      AUF   DI 2                  // "DB_DATA_REVERSE"

//oder:
//      AUF   "DB_DATA_REVERSE"
//      TDB   
//      AUF   "DB_DATA"

      L     DBD [AR1,P#0.0]       //DB1.Array_1[0]
      T     DID [AR2,P#40.0]      //DB2.Array_2[10]

      L     DBD [AR1,P#4.0]
      T     DID [AR2,P#36.0]

      L     DBD [AR1,P#8.0]
      T     DID [AR2,P#32.0]

//    ...

      L     DBD [AR1,P#36.0]
      T     DID [AR2,P#4.0]

      L     DBD [AR1,P#40.0]
      T     DID [AR2,P#0.0]

//(da sieht man schön, was wie variabel sein muss, falls als Schleife)
 
Falls in FB DI-Register oder AR2 verändert werden sollen, dann in TEMP-Speicher sichern und später wiederherstellen.
Nach Änderung DI-Register oder AR2 kann nicht auf die lokalen IDB-Instanzdaten zugegriffen werden!
Code:
//in FB AR2 und DI-Register sichern
      TAR2  #tempdwAR2save
      L     DINO
      T     #tempwDIsave

// ..... tue was ...

//in FB AR2 und DI-Register wiederherstellen
      LAR2  #tempdwAR2save
      AUF   DI [#tempwDIsave]
 
Bearbeitet:
Ok ich hab das ganze mal für AR2 mit -R (Weil sind ja irgendwie Gleitkommazahlen) gemacht, und so geht es.
Jetzt fehlt mir nur noch AR1.
-D ist 100% richtig. Dein Problem liegt woanders.

btw Deine Initialisierung mit 44 ist glaub auch verkehrt, da dass Array(11) entspricht. Probier mal 40 - DAS stimmt nicht, grad erst gesehen, dass du vor dem ersten Zugriff schon verringerst...

Ergänzung:
Deine SPS geht wegen einem ähnlichen Problem in Stopp. Hab das grad mal probiert... Du liest den Wert 11 mal ein, dadurch probiert das Programm auf Adresse 44 zu schreiben, was es bei einem DB mit 10 REAL Werten nicht gibt.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
-R, SLW, ... sind falsch.
Wenn mit Adressen gerechnet wird, dann immer mit 32-Bit-Ganzzahl-Operationen: +D, -D, SLD, ...

#tForZaehler ist in TEMP? Dann kann sich die Variable nichts merken bis zum nächsten Code-Durchlauf.

Und dein bisheriger Code funktioniert nur, wenn die Arrays direkt am Anfang der DBs an Offset 0.0 liegen.
 
Die Merk-Variable #ZAEHLER darf nicht in TEMP liegen, weil Variablen in TEMP sich nichts merken können bis zum nächsten Code-Duchlauf. #ZAEHLER muss IN_OUT oder STAT sein.

Der Wert von ZAEHLER muss VOR Verwendung geprüft und begrenzt werden, da bietet es sich an, das gleich zusammen mit dem Weitersetzen des ZAEHLER auf das nächste Array-Element zu machen, dann braucht man das nur einmal machen.

Code:
//*** nur ausführen bei Pos_Flanke ***************************
      U     #Pos_Flanke
      SPBN  ENDE

//*** neuen Wert zu Array_1 hinzufügen ***********************
      L     #ZAEHLER              //muss IN_OUT oder STAT sein
      +     1                     //nächstes Array-Element
      L     11                    //Anzahl Einträge im Array_1[0..10] OF REAL
      MOD                         //auf 0..10 begrenzen
      T     #ZAEHLER              //und merken
      L     4                     //REAL ist 4 Byte
      *D    
      SLD   3                     //Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1 hier eintragen
      +D                          //ergibt Offset von ARRAY_1[ZAEHLER]
      LAR1  
      AUF   "DB_DATA"
      L     #IN
      T     DBD [AR1,P#0.0]       //DB1.ARRAY_1[ZAEHLER] := IN

//*** Kopieren Reverse ***************************************
      ...
 
Wunderschönen guten Morgen!
Danke für die großen Hilfestellungen!
Hier mal Beispiele für das Kopieren zu reverser Reihenfolge. Alles ungetestet!
Der Code eignet sich für FB und FC. Bei FC müssen "Merkspeicher" (z.B. #Flankenmerker) in IN_OUT liegen oder Direktzugriff auf globalen Speicher (z.B. Merker)

Code:
      U     M0.5                  //CPU Taktmerker 1Hz
      =     #Kopie_Taktmerker     /weil Taktmerker asynchron! nur einmal lesen!

      U     #Kopie_Taktmerker
      UN    #Flankenmerker
      =     #Pos_Flanke

      U     #Kopie_Taktmerker
      =     #Flankenmerker

//oder einfach mit FP:
//      U     M0.5
//      FP    #Flankenmerker
//      =     #Pos_Flanke


//*** nur ausführen bei Pos_Flanke ***
      U     #Pos_Flanke
      SPBN  ENDE

//*** Kopieren Reverse ***************************************
// DB1.ARRAY_1 [0..10] OF REAL
// DB2.ARRAY_2 [0..10] OF REAL

// FOR i:= 0 TO 10 DO
//   ARRAY_2[10 - i] := ARRAY_1[i];
// END_FOR;

//oder AWL-LOOP-gerecht:
// FOR z:= 11 TO 1 BY -1 DO
//   ARRAY_2[11 - z - 1] := ARRAY_1[z - 1];
// END_FOR;

      L     11                    //11 Durchläufe 11..1
LOP1: T     #z
      +     -1                    // z=11..1 --> i=10..0
      L     4                     //REAL ist 4 Byte
      *D  
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1  hier eintragen
      +D                          //ergibt Offset von ARRAY_1[i]
      T     #tempdwPointer1

      L     11
      L     #z
      -I  
      L     4                     //REAL ist 4 Byte
      *D  
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_2 in DB2  hier eintragen
      +D                          //ergibt Offset von ARRAY_2[10 - i]
      T     #tempdwPointer2

//   ARRAY_2[10 - i] := ARRAY_1[i];   
      AUF   "DB_DATA"
      L     DBD [#tempdwPointer1]   //Speicherindirekte Adressierung
      AUF   "DB_DATA_REVERSE"
      T     DBD [#tempdwPointer2]

      L     #z                    //11..1
      LOOP  LOP1

ENDE: CLR                         //(oder SET oder NOP, irgendwas an Sprungmarke)

Code:
//oder Kopieren mit AR1 registerindirekte Adressierung
//wie in C: for (p1 = &ARRAY_1[0], p2 = &ARRAY_2[10], i = 11; i > 0; i--) *P2-- = *p1++;

      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1 hier eintragen
      T     #tempdwPointer1

      L     10                    //höchster Index
      L     4                     //REAL ist 4 Byte
      *D  
      SLD   3                     // Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_2 in DB2 hier eintragen
      +D                          //ergibt Offset von ARRAY_2[10]
      T     #tempdwPointer2

      L     11                    //11 Durchläufe 11..1
LOP2: T     #z

      LAR1  #tempdwPointer1
      AUF   "DB_DATA"
      L     DBD [AR1,P#0.0]       //Bereichsinterne registerindirekte Adressierung

      LAR1  #tempdwPointer2
      AUF   "DB_DATA_REVERSE"
      T     DBD [AR1,P#0.0]

      TAR1                        //AR1 in AKKU1
      L     P#4.0                 //REAL ist 4 Byte
      -D                          //Pointer2 4 Bytes vorher
      T     #tempdwPointer2

      L     #tempdwPointer1
      L     P#4.0                 //REAL ist 4 Byte
      +D                          //Pointer1 4 Bytes weiter
      T     #tempdwPointer1

      L     #z                    //11..1
      LOOP  LOP2

Code:
//oder bei wenigen Kopiervorgängen
//oder Kopieren von Strukturen und AR1/AR2 zeigen auf den Anfang der Strukturen
//Kopieren ohne Schleife

      LAR1  #tempdwPointer1
      LAR2  #tempdwPointer2

      AUF   "DB_DATA"
      AUF   DI 2                  // "DB_DATA_REVERSE"

//oder:
//      AUF   "DB_DATA_REVERSE"
//      TDB 
//      AUF   "DB_DATA"

      L     DBD [AR1,P#0.0]       //DB1.Array_1[0]
      T     DID [AR2,P#40.0]      //DB2.Array_2[10]

      L     DBD [AR1,P#4.0]
      T     DID [AR2,P#36.0]

      L     DBD [AR1,P#8.0]
      T     DID [AR2,P#32.0]

//    ...

      L     DBD [AR1,P#36.0]
      T     DID [AR2,P#4.0]

      L     DBD [AR1,P#40.0]
      T     DID [AR2,P#0.0]

//(da sieht man schön, was wie variabel sein muss, falls als Schleife)
Danke, das verdeutlicht einiges.
Gerade auf sowas wie im ersten Beispiel, wo du mit #z im LOOP den Multiplikator für 4 errechnest, wäre mir zumindest zum jetzigen Zeitpunkt nie eingefallen.
-D ist 100% richtig. Dein Problem liegt woanders.

btw Deine Initialisierung mit 44 ist glaub auch verkehrt, da dass Array(11) entspricht. Probier mal 40 - DAS stimmt nicht, grad erst gesehen, dass du vor dem ersten Zugriff schon verringerst...

Ergänzung:
Deine SPS geht wegen einem ähnlichen Problem in Stopp. Hab das grad mal probiert... Du liest den Wert 11 mal ein, dadurch probiert das Programm auf Adresse 44 zu schreiben, was es bei einem DB mit 10 REAL Werten nicht gibt.
Das hab ich mir schon gedacht, danke!
Hab das AR1 jetzt einfach vor dem LOOP nochmal auf 0 gesetzt und es funktioniert.

Gestern hat dafür der Kopf schon zu viel geraucht....
-R, SLW, ... sind falsch.
Wenn mit Adressen gerechnet wird, dann immer mit 32-Bit-Ganzzahl-Operationen: +D, -D, SLD, ...

#tForZaehler ist in TEMP? Dann kann sich die Variable nichts merken bis zum nächsten Code-Durchlauf.

Und dein bisheriger Code funktioniert nur, wenn die Arrays direkt am Anfang der DBs an Offset 0.0 liegen.
- Ah verstehe, Dankeschön.
- Ja tForZaehler ist TEMP, aber da er nur in der LOOP verwendet wird, ist es ja sogar in Ordnung, wenn er beim nächsten Durchlauf wieder gelöscht ist, soweit ich das richtig interpretiert habe.
- Ja das ist mir bewusst, ich wollte das Beispiel erst einmal her nehmen um generell das Lesen/Schreiben in DBs und die Verwendung von LOOP und "Pointern" bzw. Adressregistern zu verstehen.
Die Funktion könnte ich ja danach aufbauend als nächstes Übungsbeispiel einpflegen, danke!
Die Merk-Variable #ZAEHLER darf nicht in TEMP liegen, weil Variablen in TEMP sich nichts merken können bis zum nächsten Code-Duchlauf. #ZAEHLER muss IN_OUT oder STAT sein.

Der Wert von ZAEHLER muss VOR Verwendung geprüft und begrenzt werden, da bietet es sich an, das gleich zusammen mit dem Weitersetzen des ZAEHLER auf das nächste Array-Element zu machen, dann braucht man das nur einmal machen.

Code:
//*** nur ausführen bei Pos_Flanke ***************************
      U     #Pos_Flanke
      SPBN  ENDE

//*** neuen Wert zu Array_1 hinzufügen ***********************
      L     #ZAEHLER              //muss IN_OUT oder STAT sein
      +     1                     //nächstes Array-Element
      L     11                    //Anzahl Einträge im Array_1[0..10] OF REAL
      MOD                         //auf 0..10 begrenzen
      T     #ZAEHLER              //und merken
      L     4                     //REAL ist 4 Byte
      *D  
      SLD   3                     //Byteoffset --> P# Bitadresse
      L     P#0.0                 //AnfangsOffset ARRAY_1 in DB1 hier eintragen
      +D                          //ergibt Offset von ARRAY_1[ZAEHLER]
      LAR1
      AUF   "DB_DATA"
      L     #IN
      T     DBD [AR1,P#0.0]       //DB1.ARRAY_1[ZAEHLER] := IN

//*** Kopieren Reverse ***************************************
      ...
Danke, der Zähler ist noch ein Überbleibsel vom vorherigen versuch, ich versuche das direkt einzupflegen.
Bearbeitet: Zur Info ich verwende für TEMP Variablen ein kleines t vor der Variable, für STAT ein kleines s und für Ein-/Ausgänge nur Großbuchstaben.
Den MOD Befehl kannte ich noch nicht, danke fürs zeigen!

Ich versuche das ganze noch aufzuhübschen und poste später den "finalen" Code, so wie er jetzt mit meinem eigenen Lösungsweg funktioniert.
 
Zurück
Oben