speicherdirekte Adressierung (Zeiger) auf DB

I

Incubant

Guest
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich hab folgendes Problem:

Ich will anhand eines Zählerstandes 1-10 ein Doppelword aus einem DB auslesen, das auslesen soll aber mit einem Zeiger erfolgen, also z.B. bei Zähler = 3 soll das Doppelword mit der Adresse 8.0 ausgelesen werden.

Was ich bei der ganzen sache nicht ganz versteh ist das AR (Adressregister) und der Zeiger, wie kann ich mit einem Zeiger arbeiten? Also z.b. wie kann ich ihn um 4 erhöhen.

Zähler: Z 12
Zeiger: MD 0
Wert: MD 4 (Ausgelesener Wert)

vielen Dank für die Hilfe.
 
Hallo,

habe im Moment kein Simatic zur Verfügung (surfe mit Linux), aber suche mal in der AWL-hilfe nach "Beispiele zu registerindirekten Adressierung" oder so ähnlich. Dort ist alles erklärt. Falls dir das nicht weiterhilft, nochmal posten.

mfg
marlob
 
Probier es mal damit,werte für dein Zähler in einem Array fest definieren,
dann mit einem pointer aufrufen

FUNCTION FC 2 : VOID
TITLE =
VERSION : 0.1


VAR_TEMP
TEST_ARRAY : ARRAY [0 .. 9 ] OF WORD ;
END_VAR
BEGIN
NETWORK
TITLE =Array Beschreiben

L 100;
T #TEST_ARRAY[0];

L 200;
T #TEST_ARRAY[1];

L 300;
T #TEST_ARRAY[2];

L 400;
T #TEST_ARRAY[3];

L 500;
T #TEST_ARRAY[4];

L 600;
T #TEST_ARRAY[5];

L 700;
T #TEST_ARRAY[6];

L 800;
T #TEST_ARRAY[7];

L 900;
T #TEST_ARRAY[8];

L 1000;
T #TEST_ARRAY[9];

NETWORK
TITLE =MB50 begrenzen

L MB 50;
L 0;
<I ;
SPB SET0;

L MB 50;
L 9;
>I ;
SPB SET9;

SPA NWE2;

SET0: L 0;
T MB 50;

SPA NWE2;

SET9: L 9;
T MB 50;

SPA NWE2;

NWE2: NOP 0;

NETWORK
TITLE =Pointer bilden

L P#2.0; //Pointer mit 2 Byte laden
L MB 50; //Index
*D ; // im Pointer format umwandeln
LAR1 ; // tranferiere in AR1

NETWORK
TITLE =Aus Array mit Index laden

L LW [AR1,P#0.0];
T MW 20; //Ergebnis

END_FUNCTION

beispiel:ist der MB=8 so ist MW20=900(wert aus array)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
das ganze würde ich gern als 2 dimensionales Array erstellen

Hallo,

das Beispiel hier ist super. Habe auch etwas gestutzt als ich die arrays nicht dynamisch indizieren kann.
Nun brauche ich aber das ganze für ein 2Dimensionales array.
Also test[0..7,1..24] of type word.
Wie muss ich das bisherige Programm anpassen um über 2 parameter auf mein array zugreifen zu können?

mfg Andreas
 
Deine DB-Quelle sieht so aus:

Code:
DATA_BLOCK DB 400
TITLE =
VERSION : 0.1


  STRUCT     
   Test : ARRAY  [0 .. 7, 1 .. 24 ] OF //vorläufige Platzhaltervariable
   INT ;    
  END_STRUCT ;    
BEGIN
   Test[0, 1] := 0; 
   Test[0, 2] := 0; 
   Test[0, 3] := 0; 
   Test[0, 4] := 0; 
   Test[0, 5] := 0; 
   Test[0, 6] := 0; 
   Test[0, 7] := 0; 
   Test[0, 8] := 0; 
   Test[0, 9] := 0; 
   Test[0, 10] := 0; 
   Test[0, 11] := 0; 
   Test[0, 12] := 0; 
   Test[0, 13] := 0; 
   Test[0, 14] := 0; 
   Test[0, 15] := 0; 
   Test[0, 16] := 0; 
   Test[0, 17] := 0; 
   Test[0, 18] := 0; 
   Test[0, 19] := 0; 
   Test[0, 20] := 0; 
   Test[0, 21] := 0; 
   Test[0, 22] := 0; 
   Test[0, 23] := 0; 
   Test[0, 24] := 0; 
   Test[1, 1] := 0; 
   Test[1, 2] := 0; 
   Test[1, 3] := 0; 
   Test[1, 4] := 0; 
   Test[1, 5] := 0; 
   Test[1, 6] := 0; 
   Test[1, 7] := 0; 
   Test[1, 8] := 0; 
   Test[1, 9] := 0; 
   Test[1, 10] := 0; 
   Test[1, 11] := 0; 
   Test[1, 12] := 0; 
   Test[1, 13] := 0; 
   Test[1, 14] := 0; 
   Test[1, 15] := 0; 
   Test[1, 16] := 0; 
   Test[1, 17] := 0; 
   Test[1, 18] := 0; 
   Test[1, 19] := 0; 
   Test[1, 20] := 0; 
   Test[1, 21] := 0; 
   Test[1, 22] := 0; 
   Test[1, 23] := 0; 
   Test[1, 24] := 0; 
   Test[2, 1] := 0; 
   Test[2, 2] := 0; 
   Test[2, 3] := 0; 
   Test[2, 4] := 0; 
   Test[2, 5] := 0; 
   Test[2, 6] := 0; 
   Test[2, 7] := 0; 
   Test[2, 8] := 0; 
   Test[2, 9] := 0; 
   Test[2, 10] := 0; 
   Test[2, 11] := 0; 
   Test[2, 12] := 0; 
   Test[2, 13] := 0; 
   Test[2, 14] := 0; 
   Test[2, 15] := 0; 
   Test[2, 16] := 0; 
   Test[2, 17] := 0; 
   Test[2, 18] := 0; 
   Test[2, 19] := 0; 
   Test[2, 20] := 0; 
   Test[2, 21] := 0; 
   Test[2, 22] := 0; 
   Test[2, 23] := 0; 
   Test[2, 24] := 0; 
   Test[3, 1] := 0; 
   Test[3, 2] := 0; 
   Test[3, 3] := 0; 

...
Daran kannst du die "lineare" Struktur deines zweidimensionalen Arrays erkennen und mußt dir damit die Datenwort-Adresse des jeweiligen Elements berechnen, damit dann auf das gewünschte Element über indirekte Adressierung zugreifen.
 
any und co?

leider ist da viel Neuland bei. Das Befüllen des Arrays ist nicht das Problem.
Das ist nur der ungefähre Wert.
Beschreibung meines Vorhabens:
Sollwertvorgaben von 0-23uhr und für jeden tag der Woche. Diese Werte stehen in dem array sollwert[0..7,0..23]of word.
Mit C Programmierung würde ich ja nun einfach sollwert[x,y] schreiben und könnte die entsprechenden Werte abrufen. Welchen Weg muss ich nun gehen um mit "Pointern" auch die 2.Stelle des Arrays anzusprechen? Werde aus den anderen Beispielen noch nicht weiter schlau.

Danke für die schnelle Unterstützung!!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ok, das geht so:

Code:
FUNCTION FC 400 : VOID
TITLE =
VERSION : 0.1


VAR_INPUT
  DB_Nr : INT ;    
  Spalte1 : INT ;    
  Spalte2 : INT ;    
END_VAR
VAR_OUTPUT
  Datenwert : INT ;    
END_VAR
VAR_TEMP
  ADR_INT : INT ;    
  DB_NR_Temp : WORD ;    
END_VAR
BEGIN
NETWORK
TITLE =

      L     #Spalte1; 
      L     24; 
      *I    ; 
      L     #Spalte2; 
      +I    ; 
      L     2; 
      *I    ; 
      T     #ADR_INT; 

      L     #DB_Nr; 
      T     #DB_NR_Temp; 
      AUF   DB [#DB_NR_Temp]; 

      L     #ADR_INT; 
      ITD   ; 
      SLD   3; 
      LAR1  ; 

      L     DBW [AR1,P#0.0]; 
      T     #Datenwert; 
END_FUNCTION
aber Achtung, das Array im DB läuft jetzt von 0..7, 0..23, anders als in deinem 1.Post. Außerdem mußt du dafür sorgen, daß in Spalte1 und Spalte2 nur gültige Werte (0..7 und 0..23) stehen, sonnst kann Mist passieren!

Definition im DB:

Test ARRAY[0..7,0..23] INT
 
kein IDT

Hi!
Da das Posting noch nicht so alt ist, noch eine kleine Korrektur:

Der IDT-Befehl im Listing muss hier weg!

Der IDT ist nur um vorzeichenhafte 16-Bit in vorzeichenhafte 32-Bit zu wandeln. (Der IDT-Befehl interpretiert das höchste der 16 Bits als Vorzeichen und rettet dieses Vorzeichen in das 32. Bit).

Der Fehler würde sich aber erst bei Arrays über 32 kByte Größe bemerkbar machen, da ab dann das oberste gesetzt ist.

grx
hr
:twisted:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi!
Da das Posting noch nicht so alt ist, noch eine kleine Korrektur:

Der IDT-Befehl im Listing muss hier weg!

Der IDT ist nur um vorzeichenhafte 16-Bit in vorzeichenhafte 32-Bit zu wandeln. (Der IDT-Befehl interpretiert das höchste der 16 Bits als Vorzeichen und rettet dieses Vorzeichen in das 32. Bit).

Der Fehler würde sich aber erst bei Arrays über 32 kByte Größe bemerkbar machen, da ab dann das oberste gesetzt ist.

grx
hr
:twisted:

Das verstehe ich nicht. ITD wandelt eine 16-Bit-Ganzzahl in eine 32-Bit-Ganzzahl. ADR_INT ist als INT definiert, also kann hier eigentlich nichts passieren. Das sollte aber eigentlich auch keine negative Zahl auftauchen. Selbst wenn, bleibt -1 trotzdem -1 und wird anschleißend mit SLD 3 in einen Pointer gewandelt. (Ich glaube, das funktioniert paradoxer Weise sogar, wir haben im Forum irgendwann mal darüber geschrieben. Was also wäre an IDT genau falsch. Die Frage wäre für mich eher, was passiert, wenn im Akku nach laden einer 16-Bit-Ganzzahl in den anderen 16 Bit noch irgendetwas drinsteht und das dann mit SLD32 3 nach links geschoben wird, anschließend in das AR1. Oder wird beim Laden einer 16-bit-Ganzzahl der Rest des Akkus mit 0 aufgefüllt? Dann kann man es ruhig weglassen.
 
IDT "schadet" hier tatsächlich nicht...

== Verhalten bei Laden von 16-Bit Werten ==
Beim Laden eines Bytes oder 16-Bit Wortes in den AKKU (32Bit) werden immer die oberen 16 Bits auf Null gesetzt. Hatte ich mal ausprobiert und auch irgendwann in der Doku gelesen.


== Zahlen mit Vorzeichen ==

IDT macht folgendes:

Beispiel 1:
0000 0000 0000 0000 1111 1111 1111 1111 <-- vor IDT ("-1" als 16Bit)
1111 1111 1111 1111 1111 1111 1111 1111 <-- nach IDT ("-1" als 32 Bit)

Beipiel 2:
0000 0000 0000 0000 1000 0000 0000 0001 <-- vor IDT ("-32767" als 16-Bit-Zahl)
1111 1111 1111 1111 1000 0000 0000 0001 <-- nach IDT
("-32767" als 32-Bit-Zahl)

Beipiel 3:
0000 0000 0000 0000 0000 0000 0000 0001 <-- vor IDT ("+1" als 16 Bit Zahl)
0000 0000 0000 0000 0000 0000 0000 0001 <-- nach IDT
("+1" als 32 Bit Zahl)

-> Wenn das 16.Bit "1" ist, werden alle oberen Bits auf "1" gesetzt, sonst auf "0".

IDT musst Du ausführen, wenn Du eine 16-Bit Zahl, welche mit Vorzeichen interpretiert werden soll, mit einer 32-Bit-Zahl mit Vorzeichen addieren/multiplizieren/.. willst.



== Adressen ==

Um mit den 16 Bit der Adresse die vollen 0 bis 64kByte nutzen zu können, werden Adressen ohne Vorzeichen verwendet.



Und das passiert, wenn Du IDT oberhalb von 32kByte verwendest:

Beipiel: Nach der Berechnung landen wir auf Adresse 32768 (entspricht -32768, wenn man das Vorzeichen interpretiert):
AKKU1= 0000 0000 0000 0000 1000 0000 0000 0000

Jetzt IDT:
AKKU1= 1111 1111 1111 1111 1000 0000 0000 0000

Jetzt SLD 3
AKKU1= 1111 1111 1111 1100 0000 0000 0000 0000

So wird es auch in den AR1 geladen:
AR1= 1111 1111 1111 1100 0000 0000 0000 0000
.... ssss ssss .... .aaa aaaa aaaa aaaa abbb (s=Speicherbereichselektor, a=Adresse, b=bit-selektor)

Die obersten Bits sind hier zwar falsch, aber die S7 ignoriert sie (glaube ich), wenn man mit wie in dem Code mit
L DBW [AR1, P#0.0];
den Wert lädt.

(Also auf gut deutsch: Ich habe mich geirrt, in diesem Code schadet IDT nicht :) )

Ohne "DB"-Angabe werden die oberen Bits als Speicherbereich-Selektor verwendet:

OD DW#16#87000000; // Speicherbereichkennung "DB"
L W [AR1, P#0.0];

In diesem Fall würde es nur noch ohne IDT funktionieren.

Viele Grüsse
hr
:twisted:



 
Zuletzt bearbeitet:
Ah, alles klar soweit, das leuchtet ein, dann kann ich aber in Zukunft auch das IDT an dieser Stelle weglassen, prima :p . Mir ist auch wieder eingefallen, woher das kam. Früher habe ich statt SLD3 SLW3 genutzt, was natürlich auch falsch ist, in den meißten Fällen aber funktioniert. Das hab ich dann durch SLD3 ersetzt, die einfache INT-Variable zur Berechnung einen Offset war aber nun mal überall so drin, also sicherheitshalber noch ein ITD, na ja :oops: , sowas kann auch schief gehen,in diesem Fall war es ebend nur nutzlos :ROFLMAO: .
 
Zurück
Oben