Pointer auf eine globale Periepherievariable bestimmen

Barnee

Level-1
Beiträge
71
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo

Ich bin auf der Suche nach einer Lösung, die mir einen Pointer auf eine globale Variable liefert. In einer Hochsprache, z.B. C, kann ich mir zur Laufzeit den Pointer auf eine Variable bestimmen lassen und kann, sofern mir die Struktur der benachbarten Elemente bekannt ist, den Pointer manipulieren und so auf diese benachbarten Elemente zugreifen. Jetzt hab ich aber nur STEP7 auf einer S7-400 zur Verfügung und da ist mir das nicht geläufig, ob das überhaupt geht, was ich mir vorstelle. :(

Ich habe in der Symboltabelle verschiedene Periepherieadressen symbolisiert, wie z.B. PAW 568, PAW 572, PAW 576 usw. Dahinter verbergen sich Displays, die über Profibus DP angesteuert werden sollen. Die Struktur, die sich hinter jeder Adresse verbirgt, ist z.B. jeweils 8 Byte breit und dient zur Aufnahme des darzustellenden Wertes und einiger Steuerinformationen. Jetzt möchte ich gerne einen FB (ggf. auch einen FC - bleibt sich gleich) schreiben, der als VAR_IN einen Bausteinparameter enthält, an den ich bei dem Aufruf dieses FB's z.B. den Aktualoperanden "PAW 568" anlegen kann. Im FB benötige ich nun eine Möglichkeit, den Pointer auf "PAW 568" bestimmen zu können, damit ich diesen manipulieren kann, um auch die anderen Bytes beschreiben zu können. Die Variante, die Adresse als INT-Konstante, z.B. 568, an einen Bausteinparameter zu legen, um dann mit der indirekten Adressierung zu arbeiten, würde zwar funktionieren, ist mir aber nicht elegant genug, da ich dann auf diese Weise den Vorzug der symbolischen Adressierung aufgeben würde. :shock: :shock: :shock:

Wäre die Anwendung des SFC 15 der richtige Weg? Das ganze soll auch noch, falls möglich, in SCL geschrieben werden, falls nicht, dann geht so was auch in AWL, ich hätte damit keine Probleme :lol: wird aber von der Seite des Kunden nicht so gerne gesehen.

Gruß Barnee
 
ANY-Pointer und AT-Anweisung

Hallo,

mit Hilfe der ANY-Pointer kannst du Datenfelder
eines beliebigen Typs adressieren. Aufbau siehe
S7-Hilfe.

Du brauchst dazu die Register-Adressierung über
AR1/AR2
Adressregister, in AWL:
- L P##ANY_IN
- LAR 1
- L B [AR1,P#0.0] //Zugriff
- ...
- L W [AR1,P#2.0] etc.

Vorsicht: AR2 wird in Instanzen vom System ver-
wendet, ohne dass du die Befahle siehst (du bist
hier schon sehr nahe am System!) Also unbedingt
vorher die Registerinhalte retten !!!!!!!

In SCL ist die AT-Anweisung sehr nützlich. damit
kannst du "typisierte Pointer" erzeugen, d.h. du
übergibt einen Zeiger auf die Startadresse und
kannst diesen Zeiger mit einer lokalen Strukur
überladen.

SFC 15 ist bei Zugriffen auf Profibus-Variablen
>8 Bit grundsätzlich angebracht, weil du sonst schon
bei einem Wort High- und Low-Byte aus zwei
unterschiedlichen Zyklen haben kannst.

Was bei Siemens leider nicht funktioniert, ist
die Definition von globalen Variablen in der
HW-Konfig, auf die du dann im Programm zu-
greifen kannst. Aber es ist allemal besser, sich
einen Pointer zu bauen, dann hast du auch
bessere Unterstützung durch die QVL.

Gruß G.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Barnee,

..Die Struktur, die sich hinter jeder Adresse verbirgt, ist z.B. jeweils 8 Byte breit..
Für diese Struktur würde ich zunächst einen UDT anlegen und diesen in einem DB für jeden dieser Busteilnehmer vereinbaren. Den UDT event. noch einmal in Ein- und Ausgänge strukturell unterteilen, um diese Teile später der SFC14/15 symbolisch übergeben zu können. Die Größe der Strukturen sollte mit den Adressbereichen der Teilnehmer (HW-Konfig) übereinstimmen.
Den selben UDT kann man dann als Bausteinparameter deklarieren und somit symbolisch auf die jeweiligen Daten zugreifen. Die Kommunikation erfolgt dann über SFC14/SFC15.

Eine Möglichkeit, über ANY-Pointer und indirekte Adressierung die Daten zu bearbeiten, jedoch trotzdem symbolisch darauf zu zu greifen, findest du hier. Das sieht zwar erst einmal umständlicher aus, ist aber möglicherweise reourcensparender als über Bausteinparameter-UDT.


Gruß, Onkel
 
Re: ANY-Pointer und AT-Anweisung

Noch ein Gast schrieb:
Hallo,

mit Hilfe der ANY-Pointer kannst du Datenfelder
eines beliebigen Typs adressieren. Aufbau siehe
S7-Hilfe.
.....
In SCL ist die AT-Anweisung sehr nützlich. damit
kannst du "typisierte Pointer" erzeugen, d.h. du
übergibt einen Zeiger auf die Startadresse und
kannst diesen Zeiger mit einer lokalen Strukur
überladen.

ANY-Zeiger sind mir jetzt auch schon in den Sinn gekommen.
Leider funktioniert die AT-Anweisung nur auf Lokalvariablen, wäre schön wenn es auch auf Eingangsvariablen anwendbar wäre, is aber nicht :cry:

OK, ich bin grad dabei, den FC zu basteln. Ich hab jetzt eine Eingangsvariable ADR vom Typ ANY. Im FC kopiere ich diese Eingangsvariable auf eine lokale Variable ADX gleichen Typs, SCL frißt das, müßte also gehen. Mit der AT-Anweisung hab ich eine neue Sicht namens ADP als Struktur über ADX gelegt und kann so die einzelnen Komponenten des ANY-Zeigers lesen. Die unteren 4 Bytes des ANY-Zeigers werden schlußendlich 3 bits nach rechts geschoben, wo bei ich anschließend in den untersten beiden Bytes die Anfangsadresse des Peripheriebereiches erhalte den ich beschreiben will. Mit dieser Anfangsadresse kann man dann entweder über indirekte Adressierung schreiben oder ich verwende je nach Anforderung an die Konsistenz den SFC 15. Es findet natürlich eine Typprüfung statt, die Einzelheiten hab ich aber hier nicht weiter dargestellt.

Wenn ich das getestet hab (wird aber eher Mitte nächster Woche sein) werd ich den Baustein ins Forum stellen.

Gruß Barnee
 
Ich würde dir in deinem Fall eher zur der Variante mit der UDT raten, da du in deinem FC/FB dann direkt mit den symbolischen Namen aus der UDT arbeiten kannst und nicht mit Zeigern (Any-Pointern) arbeiten mußt.
Das hilft vor Allem später, wenn du nach einiger Zeit an deinem Code ändern willst, ist jedenfalls meine Erfahrung dazu.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Onkel Dagobert schrieb:
Hallo Barnee,

..Die Struktur, die sich hinter jeder Adresse verbirgt, ist z.B. jeweils 8 Byte breit..
Für diese Struktur würde ich zunächst einen UDT anlegen und diesen in einem DB für jeden dieser Busteilnehmer vereinbaren. Den UDT event. noch einmal in Ein- und Ausgänge strukturell unterteilen, um diese Teile später der SFC14/15 symbolisch übergeben zu können. Die Größe der Strukturen sollte mit den Adressbereichen der Teilnehmer (HW-Konfig) übereinstimmen.
Den selben UDT kann man dann als Bausteinparameter deklarieren und somit symbolisch auf die jeweiligen Daten zugreifen. Die Kommunikation erfolgt dann über SFC14/SFC15.

Gruß, Onkel

Hallo Onkel Dagobert
Ich glaub, ich hab einen ganz guten Ansatz für die Problemlösung gefunden - siehe mein letztes Post. Die Sache mit dem UDT wäre sicher gut, wenn es damit nicht ein Problem in CFC geben würde, da CFC die Einbettung von Strukturen in übergeordnete Strukturen (ein DB ist schon mal grundsätzlich eine Struktur) nur bis zur 2. Ebene akzeptiert. Aus diesem Grund sind auch die FB's aus dem Drive ES nur bedingt in CFC anwendbar, da sind schon ein paar Klimmzüge notwendig - alles Kappes :cry: Drive ES generiert ja eine ähnliche von dir vorgeschlagene Struktur. Da aber bei einem umfangreichen Projekt eine Vorprojektierung notwendig ist - ich mach das immer unter Excel -, damit bei der HW-Konfig auch alles mit rechten Dingen zugeht, ist bei m ir der Bedarf von Drive ES nicht mehr gegeben. Ich hab Drive ES wieder aus dem Projekt herausgeworfen. Die Ansteuerung von Micromaster 440 mach ich mit eigenen Bausteinen. Es wird nur noch die Starter-Applikation verwendet.

Gruß Barnee
 
Hallo Barnee,

..Leider funktioniert die AT-Anweisung nur auf Lokalvariablen, wäre schön wenn es auch auf Eingangsvariablen anwendbar wäre, is aber nicht..
Wenn du einen FB verwenden würdest, müsste die AT-Anweisung auch auch auf Eingangsparameter vom Typ ANY anwendbar sein.


Gruß, Onkel
 
Code:
FUNCTION FC201 : VOID

TITLE = 'numeric display SIEBERT S102 with 4 digits'
//
//Comment:
//
VERSION : '1.0'
AUTHOR  : HL
NAME    : S1024
FAMILY  : YYY

//Data representation of S102 in SI16 mode
//  Byte 0   Byte 1   Byte 2   Byte 3
//+--------+--------+--------+--------+
//|76543210|76543210|76543210|76543210|
//+--------+--------+--------+--------+
// |||||||| RESERVED   MSB      LSB
// |||||||+---------------------------- DP0 (DP 2..0 see table 1)
// ||||||+----------------------------- DP1
// |||||+------------------------------ DP2
// ||||+------------------------------- RESERVED always set to 0
// |||+-------------------------------- RESERVED always set to 0
// ||+--------------------------------- FL (1 Flashing, 0 normal)
// |+---------------------------------- BL (1 Blanking, 0 normal)
// +----------------------------------- ST (1 Segment test, 0 normal)
//
//
//Table 1: Decimal dot
//----------------------
//  DP2  DP1  DP0  Meaning
//+----+----+----+--------  
//|  0 |  0 |  0 | No dp
//|  0 |  0 |  1 | dp at 2. digit
//|  0 |  1 |  0 | dp at 3. digit
//|  0 |  1 |  1 | dp at 4. digit

// Typical-Attribute
{
  S7_m_c:='false';
  S7_blockview:='big'
}
VAR_INPUT
    ADR     : ANY;
    PV_R    : REAL := 0;
    DPoint  : INT  := 0;
    SegTest : BOOL := false;
END_VAR

VAR_OUTPUT
    Error   : BOOL;
    Ernum   : INT;
END_VAR

VAR_TEMP
    ADP     : ANY;
    ADX AT ADP : STRUCT
        ID    : BYTE;
        TYP   : BYTE;
        CNT   : INT;
        DBN   : INT;
        PTR   : DWORD;
    END_STRUCT;
    by_0    : BYTE;
    by_1    : BYTE;
    val     : INT;
    padr    : INT;
END_VAR

BEGIN
  ADP   := ADR;

  IF (ADX.TYP <> B#16#04) THEN                                 // error if not from type of word
    Error := true;
    Ernum := -7;
    RETURN;
  END_IF;

  IF ((ADX.PTR AND DW#16#FF00_0000) <> DW#16#8000_0000) THEN   // error if not adressing the periphery
    Error := true;
    Ernum := -6;
    RETURN;
  END_IF;

  padr := DWORD_TO_INT(SHR (IN := ADX.PTR, N := 3));           // start adress

  Ernum := 0;
  by_0  := 0;
  by_1  := 0;

  IF SegTest THEN
    by_0 := B#16#80;
    val  := 0;
  END_IF;

  IF (PV_R < -32768) THEN
    Ernum := -5;
    val   := -32768;
  ELSIF (PV_R > 32767) THEN
    Ernum := -4;
    val   := -32768;
  ELSIF (PV_R < -999) THEN
    Ernum := -3;
  ELSIF (PV_R > 9999) THEN
    Ernum := -2;
  ELSE
    CASE DPoint OF
      0..3: by_0 := by_0 OR INT_TO_BYTE(DPoint);
    ELSE
      Ernum := -1;
    END_CASE;
  END_IF;

  IF (Ernum >= -3) THEN
    val := REAL_TO_INT (PV_R);
  END_IF;
  
  Error := Ernum < 0;

  PQB[padr    ] := by_0;
  PQB[padr + 1] := by_1;
  PQW[padr + 2] := INT_TO_WORD(val);

END_FUNCTION

Hier schon einmal meine Lösung - aber noch ungetestet. Das kommt erst nächste Woche, wenn ich im Büro die SPS aufbauen kann, zur Zeit wird unser Büro umgebaut, deshalb muß ich nach warten.

Gruß Barnee

PS. Die Anweisungen sind natürlich nach IEC in Englisch!!!!!
 
Zurück
Oben