Step 7 S7 SCL indirekter Adressierung Merker - Fehler abfangen

trexer

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

ich möchte auf Merker zugreifen und mache das in SCL z.B. mit:
Code:
wert := DWORD_TO_REAL(MD[DB219.variable[j].byad]);  //Merker-Doppelword
wert := WORD_TO_INT(M[DB219.variable[j].byad,DB219.variable[j].bit]); //Merkerbit - Bool
wert := WORD_TO_INT(MW[DB219.variable[j].byad]); //Merker-Word
wenn jetzt für "byad" ein Wert der über dem Merkerbereich der SPS liegt gewählt wird geht diese in den Stop/Fehler.

Kann man das irgendwie abfangen? Natürlich könnte ich manuell prüfen ob die Adresse kleine als der Speicher der SPS ist. Ich würde das Programm aber gerne universell verwenden. Oder kann ich irgendwie in SCL abfragen wie die maximale Merker-Adresse lautet?

Danke für jeden Tip!
 
Zuletzt bearbeitet von einem Moderator:
Du kannst über eine SZL-Anfrage mit SZL-ID W#16#0114 die Speicherbereiche deiner CPU auslesen.
Für die Merkerbereiche als erstes mit SZL-Index 3 probieren, wenn das fehlschlägt dann mit SZL-Index 8 abfragen. Wie der Datensatz aufgebaut ist sollte (hoffentlich auch in den aktuellen) Handbüchern stehen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke Thomas für deine Antwort. Ich habe mich daran versucht und gesucht. Leider habe ich in keinem gefunden Handbuch etwas dazu gefunden. Aus Foren und Webseiten konnte ich dann das folgende zusammenschreiben:
Code:
VAR_TEMP   
  sfc51Data: STRUCT
    ID:BYTE;
    TYP:BYTE;
    NUM:INT;
    DBN:INT;
    PTR:DWORD;
END_STRUCT;

SSL_HEADER: STRUCT
    LENTHDR:    WORD;
    N_DR:        WORD;
  END_STRUCT ; 
END_VAR

...

    temp :=  RDSYSST(REQ := TRUE // IN: BOOL
              ,SZL_ID := W#16#0114 // IN: WORD
              ,INDEX := W#16#3 // IN: WORD
              ,BUSY := m0.0 // OUT: BOOL
              ,SZL_HEADER := SSL_HEADER // OUT: STRUCT
              ,DR := sfc51Data // OUT: ANY
              ); // INT

Ich erhalte:
Code:
ID    BYTE    B#16#0    B#16#1E        
TYP    BYTE    B#16#0    B#16#3C        
NUM    INT    0    7740        
DBN    INT    0    0        
PTR    DWORD    DW#16#0    DW#16#1E3C1E3C        
LENTHDR    WORD    W#16#0    W#16#1E3C        
N_DR    WORD    W#16#0    W#16#0000

Leider kann ich mit der Rückgabe nicht viel anfangen.... Ist das überhaupt so richtig?

Vielen Dank!
 
Ich persönlich mag keine absoluten Zugriffe, wie Du es mit dem DB219 machst.

Vorschlag:

So wie es aussieht, hast Du eine Struktur festgelegt. Diese würde ich als Array an die Schnittstelle legen und in SCL per CONST die Grenzen des Arrays deklarieren.
Der Compiler meckert dann, wenn die Variable an der Schnittstelle nicht die korrekte Länge hat:

Code:
CONST
    BEG := 1;
    END := 20;
END_CONST

VAR_INPUT
    iDATA : ARRAY[BEG..END] OF UDT1;
END_VAR

BEGIN


wert := DWORD_TO_REAL(MD[iDATA.variable[j].byad]);  //Merker-Doppelword
wert := WORD_TO_INT(M[iDATA.variable[j].byad,iDATA.variable[j].bit]); //Merkerbit - Bool
wert := WORD_TO_INT(MW[iDATA.variable[j].byad]); //Merker-Word

END
 
Probier mal mit dieser Funktion, der gibt die gleich alle Daten der CPU aus.
Es reicht die Funktion einmal z.B. bei Neustart der SPS aufzurufen.

Code:
FUNCTION_BLOCK "Leistungsdaten"
//
// Liest über SFC51 die Leistungsdaten der CPU aus
//

VAR_INPUT
    REQ : BOOL;     // Steigende Flanke startet eine Abfrage
END_VAR

VAR_OUTPUT
    ERROR : BOOL;   // TRUE bei Fehler
    BUSY : BOOL;    // TRUE = Lesevorgang noch nicht abgeschlossen
    ANZ_PAE : DINT; // PAE (Anzahl in Byte), -1 wenn nicht verfügbar
    ANZ_PAA : DINT; // PAA (Anzahl in Byte), -1 wenn nicht verfügbar
    ANZ_M : DINT;   // Merker (Anzahl in Byte), -1 wenn nicht verfügbar
    ANZ_L : DINT;   // Lokaldaten (Anzahl in Byte), -1 wenn nicht verfügbar
    ANZ_T : INT;    // Zeiten (Anzahl), -1 wenn nicht verfügbar
    ANZ_Z : INT;    // Zähler (Anzahl), -1 wenn nicht verfügbar
END_VAR

VAR
    REQ_OLD : BOOL;
    STATE : INT;
    RDSYSST_REQ : BOOL;
    RDSYSST_BUSY : BOOL;
    RDSYSST_RETVAL : INT;
    DR : ARRAY[1..10] OF
        STRUCT     
        Index : WORD;
        Code : WORD;
        Anzahl : WORD;
        Reman : WORD;
    END_STRUCT;
    SZL_HEADER : STRUCT  
        LENTHDR : WORD;
        N_DR : WORD;
    END_STRUCT;
END_VAR

VAR_TEMP 
    i : INT;
BEGIN

CASE STATE OF
//************
//* Start
0:
RDSYSST_REQ := false;
BUSY := false;
IF REQ AND NOT REQ_OLD THEN
    ERROR := false;
    BUSY := true;
    STATE := 1;
END_IF;
//************
//* Vorhandenen Listen löschen     
1:
FOR i := 1 TO 10 DO
   DR[i].Index := 0;
   DR[i].code := 0;
   DR[i].Anzahl := 0;
   DR[i].Reman := 0;
END_FOR;
SZL_HEADER.LENTHDR := 0;
SZL_HEADER.N_DR := 0;

RDSYSST_REQ := true;
STATE := 2;

// Ergebnis SFC Aufruf auswerten
2:
IF NOT RDSYSST_BUSY THEN
    IF RDSYSST_RETVAL = 0 AND SZL_HEADER.LENTHDR = W#16#8 AND SZL_HEADER.N_DR <> 16#0 THEN // Erfolg
        STATE := 3;
    ELSE // Wenn SFC Aufruf mit Fehler, dann Ende mit Fehler
        ERROR := true;
        STATE := 0;
    END_IF;
END_IF;

// Bereiche prüfen und auswerten
3:
ANZ_PAE := -1;
ANZ_PAA := -1;
ANZ_M := -1;
ANZ_L := -1;
ANZ_T := -1;
ANZ_Z := -1;

IF WORD_TO_INT(SZL_HEADER.N_DR) > 10 THEN
    SZL_HEADER.N_DR := 10;
END_IF;

FOR i := 1 TO WORD_TO_INT(SZL_HEADER.N_DR) DO
    CASE WORD_TO_INT(DR[i].Index) OF
        1: ANZ_PAE := WORD_TO_DINT(DR[i].Anzahl);
        2: ANZ_PAA := WORD_TO_DINT(DR[i].Anzahl);
        3: ANZ_M := WORD_TO_DINT(DR[i].Anzahl) / 8; // Merker (Anzahl in Bit)
        4: ANZ_T := WORD_TO_INT(DR[i].Anzahl);
        5: ANZ_Z := WORD_TO_INT(DR[i].Anzahl);
        //6: Anzahl der Byte im logischen Adreßraum
        7: ANZ_L := WORD_TO_INT(DR[i].Anzahl);  // Ergebnis in Byte
        8: ANZ_M := WORD_TO_DINT(DR[i].Anzahl); // Merker (Anzahl in Byte)
        9: ANZ_L := WORD_TO_DINT(DR[i].Anzahl) * 1024; // Ergebnis in kByte
    END_CASE;
END_FOR;
STATE := 0;
    
END_CASE;

////////////////
RDSYSST_RETVAL := RDSYSST(
    REQ :=  RDSYSST_REQ,
    SZL_ID := 16#0014,
    INDEX := 16#0000,
    BUSY := RDSYSST_BUSY,
    SZL_HEADER := SZL_HEADER,
    DR := DR
);

REQ_OLD := REQ;
    
END_FUNCTION_BLOCK
 
wenn jetzt für "byad" ein Wert der über dem Merkerbereich der SPS liegt gewählt wird geht diese in den Stop/Fehler.

Kann man das irgendwie abfangen?
Du kannst (leere) OB121 und OB122 in die CPU laden, dann geht sie nicht mehr in Stop - die fehlerhaften Zugriffe werden aber im Diagnosepuffer eingetragen und die rote SF-LED leuchtet. Zusätzlich könnte man auch noch die Zugriffsfehler mit SFC36, SFC37 und SFC38 abfangen. Details siehe die Hilfe zu den OB und SFC.

Harald
 
Zurück
Oben