Step 7 Werte mit Pointer aus DB lesen und schreiben, nicht ganz klar

mzva

Level-1
Beiträge
144
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

wie schon in der Überschrift erwähnt möchte ich in einem FC via Zeiger Werte schreiben und lesen.
Anbei meine Versuche.
Versuch 1 funktioniert bis ich an das Ende des DB komme, letzter Zeigerwert stimmt dann nicht mehr?
Angenommen Startadresse ist 34, Zeiger past bis zum letzten Wert, bei diesem zeigt "er" dann auf 32???
Versuch 2 sollte doch auch funktionieren, oder?

Besten Dank schon im Voraus für die Hilfe.

Code:
//--- Datenbaustein öffnen
      L     #IN_DBNr
      T     #DB_open
      AUF   DB [#DB_open]

//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr                //Anfangsadresse sprich erster Wert
      SLD   3
      LAR1  
      T     #Zeiger_auf_Wert

// Messwert nach DB schreiben
      L     #Messwert_REAL              // hole umgewandelten Wert
      T     DBD [#Zeiger_auf_Wert]      // schreibe in DB

// Werte aus DB holen Versuch 1
      L     #Zeiger_auf_Wert            // hole Zeiger Wert
      INC   32                               // erhöhe um 4x8 Bit
      T     #Zeiger_auf_Wert            // schreibe Zeiger zurueck
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Min_Ein                 // schreibe in Temp Variable

// dies wiederholt sich 5x, dann letzter Wert lesen, funktioniert nicht

//10Byte entfernt vom Startwert, zeigt dann auf nicht plausiblen Wert?
      L     #Zeiger_auf_Wert
      INC   80
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #Offset_Fuehler



// Werte aus DB holen Versuch 2
      +AR1  P#4.0                       // erhoehe Zeiger um  4x8 Bit (naechste REAL Zahl)
      T     #Zeiger_auf_Wert            // schreibe auf Zeiger

      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Min_Ein                 // schreibe in Temp Variable
 
Hallo,
ab wo genau funktioniert das Ganze nicht mehr ?
Ist der DB groß genug ?

Unabhängig davon würde ich allerdings den Code auch etwas anders aufbauen (wegen der Pointer-Geschichte) :
Code:
// Werte aus DB holen Versuch 1
      L     #Zeiger_auf_Wert            // hole Zeiger Wert
[COLOR=#ff0000]      L p#4.0
      +D                                // erhöhe um 4x8 Bit
[/COLOR]      T     #Zeiger_auf_Wert            // schreibe Zeiger zurueck
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Min_Ein                 // schreibe in Temp Variable

// dies wiederholt sich 5x, dann letzter Wert lesen, funktioniert nicht

//10Byte entfernt vom Startwert, zeigt dann auf nicht plausiblen Wert?
      L     #Zeiger_auf_Wert
[COLOR=#ff0000]      L p#10.0
      + D
[/COLOR]      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #Offset_Fuehler

Ist "Zeiger_auf_Wert" ein Doppelwort ?

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ach ja ... diese Sequenz gefällt mir ganz und gar nicht ...
Code:
// Werte aus DB holen Versuch 2
       +AR1  P#4.0                       // erhoehe Zeiger um  4x8 Bit (naechste REAL Zahl)
       T     #Zeiger_auf_Wert            // schreibe auf Zeiger
Mit welchem Grundwert vom AR1 arbeitest du denn da ?

Gruß
Larry
 
Adressen sind 32-Bit-Werte, INC addiert nur auf die unteren 8 Bit.
Statt "INC 32" muß P#4.0 +D-addiert werden, statt "INC 80" muß P#10.0 +D-addiert werden.
Siehe Beitrag #2 von Larry

PS: Bei speicherindirekter Adressierung braucht man AR1 nicht, das LAR1 ist in dem gezeigten Code überflüssig.

Harald
 
Danke für die prompte Hilfe.

-->ab INC 80 funktioniert es nicht mehr.

"Zeiger_auf_Wert" ist als DINT deklariert.

Grundwert sollte, so dachte ich jedenfalls, mein Startwert als Input sein
Code:
//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr                //Anfangsadresse sprich erster Wert
      SLD   3
      LAR1  
      T     #Zeiger_auf_Wert
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Verstehe wohl das mit den AR nicht. Ich brauche dann das LAR1 nicht, den Zeiger mache ich ausschliesslich mit SLD3.

Code:
//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr                //Anfangsadresse sprich erster Wert
      SLD   3
      [COLOR=#ff0000]LAR1 [/COLOR] 
      T     #Zeiger_auf_Wert
 
Nein ... das AR1 brauchst du an dieser Stelle (WEIL du ja nur mit der Variablen arbeitest) nicht.
Der Befehl ist also hier überflüssig.

Gruß
Larry

Nachsatz :
Funktioniert denn dein Code jetzt (nach den von mir vorgeschlagenen Änderungen) ?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Verstehe wohl das mit den AR nicht. Ich brauche dann das LAR1 nicht, den Zeiger mache ich ausschliesslich mit SLD3.
In Step7 AWL gibt es "registerindirekte Adressierung" und "speicherindirekte Adressierung".
(siehe Hilfe zu AWL > Index > Indirekte Adressierung)

Bei der registerindirekten Adressierung werden die Adressregister AR1 und AR2 als Pointer benutzt. Diese Variante ist nicht so übersichtlich, kann aber ohne den Pointer zu ändern zusätzliche Offsets zum Pointer berechnen.

Bei der speicherindirekten Adressierung werden Speichervariablen (z.B. LD... oder MD...) als Pointer benutzt. Die Adressregister werden nicht verwendet. Diese Variante halte ich für sehr viel übersichtlicher (die Variablen können symbolische Namen haben) und es kann mit mehr als 2 Pointern ohne Umladen gearbeitet werden.

Das "SLD 3" wird bei beiden Varianten benötigt um aus einer Bytenummer eine Adresse im Pointerformat P#Byte.Bit zu machen.

Die beiden Varianten kann man gemischt verwenden, sie funktionieren unabhängig voneinander und beeinflussen sich nicht.

Harald
 
Guten Morgen zusammen,

die indirekte Adressierung funktioniert, aber nur wenn ich den FC einmal aufrufe.
Ich möchte den FC mehrmals aufrufen und mit verschiedenen Startwerten belegen.
Wo ist der "Haken"?

Gruss
 
Hallo,
das sollte schon machbar sein ... wie machst du es aktuell ? Wie sieht dein Baustein mittlerweile aus ?

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

rufe im OB1, ein FB auf, hier verwende ich den FC mehrmals.

Code:
// dies ist die STruktur im DB
-----------------------------
Test_AM    STRUCT        PEW300    
Istwert                             REAL    0.000000e+000       
Grenzwert_MinEin               REAL    -3.500000e+001    
Grenzwert_MinAus              REAL    -2.500000e+001    
Grenzwert_MaxEin              REAL    5.000000e+001      
Grenzwert_MaxAus             REAL    4.500000e+001     
Ersatzwert                        REAL    1.000000e+001    
Alarm                               BOOL    FALSE    /    
Alarm_Grenzwert_Min          BOOL    FALSE    /    
Alarm_Grenzwert_Max         BOOL    FALSE    /    
Grenzwert_Min_Meldezeit     INT    60    sec/    
Grenzwert_Max_Meldezeit    INT    60    sec/    
Offset_Fuehler                   REAL    0.000000e+000    K/  
   END_STRUCT  


// Mehrfachaufruf diese FC 

NW1
//--- Datenbaustein öffnen
      L     #IN_DBNr
      T     #DB_open
      AUF   DB [#DB_open]

//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr                //Anfangsadresse sprich erster Wert
      SLD   3
      T     #Zeiger_auf_Wert

// Werte aus DB holen
      L     #Zeiger_auf_Wert            // hole Zeiger Wert
      L     P#4.0                       // erhöhe um 4x8 Bit
      +D    
      T     #Zeiger_auf_Wert            // schreibe Zeiger zurueck
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Min_Ein                 // schreibe in Temp Variable

      L     #Zeiger_auf_Wert
      L     P#4.0
      +D    
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Min_Aus

      L     #Zeiger_auf_Wert
      L     P#4.0
      +D    
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Max_Ein

      L     #Zeiger_auf_Wert
      L     P#4.0
      +D    
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #GW_Max_Aus

      L     #Zeiger_auf_Wert
      L     P#4.0
      +D    
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #Ersatzwert

      L     #Zeiger_auf_Wert
      L     P#10.0
      +D    
      T     #Zeiger_auf_Wert
      L     DBD [#Zeiger_auf_Wert]      // hole gezeigten Wert
      T     #Offset_Fuehler

NW2
//Skalierung REAL, Offset miteinbeziehen
      L     #IN_PEW
      ITD   
      DTR   
      L     1.000000e+001
      /R    
      L     #Offset_Fuehler
      +R    
      T     #Messwert_REAL

NW3
//--- Pointer zurueck auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr                //Anfangsadresse sprich erster Wert
      SLD   3
      T     #Zeiger_auf_Wert


// Messwert nach DB schreiben
      L     #Messwert_REAL              // hole umgewandelten Wert
      T     DBD [#Zeiger_auf_Wert]      // schreibe in DB

// danach NW die Drahtbruch und Grenzwert auswerten
 
Hallo,

und was funktioniert nicht? Geht die CPU in Stop oder wie zeigt sich das "nicht funktionieren"?
Ich kann da noch nichts falsches entdecken.

Wie sieht die Deklaration des FB aus?
Wie sieht ein Aufruf der FC aus?
Wie übergibst Du die Startadresse der Struktur an #IN_Start_Nr?

Du könntest die Struktur vielleicht besser als ANY übergeben.
Oder noch besser als UDT an IN_OUT, dann brauchst Du keine indirekte Adressierung.

Tip: aus dem Baustein eine "Quelle generieren" und den Text dann hierher kopieren.

Harald
 
Wenn schon indirekte Adressierung, dann ist bei Deiner Aufgabe die registerindirekte Adressierung mit AR1 besser geeignet. Da sparst Du Dir das dauernde Ändern des Pointers. Du lädst die Anfangsadresse der Struktur in AR1 (anstatt in #Zeiger_auf_Wert) und greifst danach mit "L DBD [AR1,P#...]" auf die einzelnen Struktur-Variablen zu. Bei P#... gibst Du direkt den Offset zum Strukturanfang an, also z.B. [AR1, P#4.0], [AR1, P#8.0], [AR1, P#12.0], ...

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

es wird nicht auf den korrekten Istwert (falsche Position im DB) zurückgeschrieben und irgendwie kann ich den Offset Fuehler nicht mehr vom DB aus beschreiben bzw. anpassen.
Hab dann mal das lesen des Offset Fuehler auskommentiert, dann konnte ich wieder den Wert anpassen. Dachte ich lese nur aus dem DB?

Werde aber Montag auch mal die Version mit dem AR probieren und mich mal an deinen Vorschlag mit UDT machen.

Danke für die Mühe.

dies ist der Aufruf des FC im FB

Code:
FUNCTION_BLOCK FB 301
TITLE =
VERSION : 0.1


VAR_TEMP
  AM_Sm : BOOL ;    
  AM_GW_Min : BOOL ;    
  AM_GW_Max : BOOL ;    
END_VAR
BEGIN
NETWORK
TITLE =

      U     M     66.6; 
      =     L      1.0; 
      BLD   103; 
      U     M     66.7; 
      =     L      1.1; 
      BLD   103; 
      U     #AM_Sm; 
      =     L      1.2; 
      BLD   103; 
      CALL "Test_FC_AM" (
           IN_PEW                   := 111,
           IN_DBNr                  := 222,
           IN_Start_Nr              := L#0,
           IN_Netz_OK               := L      1.0,
           IN_Quitt                 := L      1.1,
           IN_Ersatzw_ein           := L      1.2,
           IN_Timer_Nr              := T    100,
           OUT_Sm                   := #AM_Sm,
           OUT_GW_Min               := #AM_GW_Min,
           OUT_GW_Max               := #AM_GW_Max);
      NOP   0; 
NETWORK
TITLE =

      U     M     66.6; 
      =     L      1.0; 
      BLD   103; 
      U     M     66.7; 
      =     L      1.1; 
      BLD   103; 
      U     #AM_Sm; 
      =     L      1.2; 
      BLD   103; 
      CALL "Test_FC_AM" (
           IN_PEW                   := 222,
           IN_DBNr                  := 222,
           IN_Start_Nr              := L#34,
           IN_Netz_OK               := L      1.0,
           IN_Quitt                 := L      1.1,
           IN_Ersatzw_ein           := L      1.2,
           IN_Timer_Nr              := T    101,
           OUT_Sm                   := #AM_Sm,
           OUT_GW_Min               := #AM_GW_Min,
           OUT_GW_Max               := #AM_GW_Max);
      NOP   0; 
NETWORK
TITLE =

      U     M     66.6; 
      =     L      1.0; 
      BLD   103; 
      U     M     66.7; 
      =     L      1.1; 
      BLD   103; 
      U     #AM_Sm; 
      =     L      1.2; 
      BLD   103; 
      CALL "Test_FC_AM" (
           IN_PEW                   := 333,
           IN_DBNr                  := 222,
           IN_Start_Nr              := L#68,
           IN_Netz_OK               := L      1.0,
           IN_Quitt                 := L      1.1,
           IN_Ersatzw_ein           := L      1.2,
           IN_Timer_Nr              := T    102,
           OUT_Sm                   := #AM_Sm,
           OUT_GW_Min               := #AM_GW_Min,
           OUT_GW_Max               := #AM_GW_Max);
      NOP   0; 
NETWORK
TITLE =

      U     M     66.6; 
      =     L      1.0; 
      BLD   103; 
      U     M     66.7; 
      =     L      1.1; 
      BLD   103; 
      U     #AM_Sm; 
      =     L      1.2; 
      BLD   103; 
      CALL "Test_FC_AM" (
           IN_PEW                   := 444,
           IN_DBNr                  := 222,
           IN_Start_Nr              := L#102,
           IN_Netz_OK               := L      1.0,
           IN_Quitt                 := L      1.1,
           IN_Ersatzw_ein           := L      1.2,
           IN_Timer_Nr              := T    103,
           OUT_Sm                   := #AM_Sm,
           OUT_GW_Min               := #AM_GW_Min,
           OUT_GW_Max               := #AM_GW_Max);
      NOP   0; 
END_FUNCTION_BLOCK

hier der komplette FC

Code:
FUNCTION "Test_FC_AM" : VOID
TITLE =
//Der FC301 überwacht den Analogwert (Fuehler PT100)im Toleranzbereich
//von -50 bis +300°C.
//Wird dieser Bereich verletzt, werden entsprechende Meldungen ausgegeben.
//Während eines Netzausfalles werden keine Störungsmeldungen erzeugt.
//
//Werte werden via Zeiger aus dem DB gelesen und geschrieben, DB angepasst.
//
//Timer muss uebergeben werden.
VERSION : 0.1


VAR_INPUT
  IN_PEW : INT ;    //Analoger Eingangswert
  IN_DBNr : INT ;    //Eingabe:DB Nummer Sensorik
  IN_Start_Nr : DINT ;    //Startadresse des ersten Wert
  IN_Netz_OK : BOOL ;    //Netz OK Meldung zur Fehlerunterdrückung
  IN_Quitt : BOOL ;    //Statische Meldungen quittieren
  IN_Ersatzw_ein : BOOL ;    //Freigabe der Aufschaltung Ersatzwert mit reset aller Störungen
  IN_Timer_Nr : TIMER ;    
END_VAR
VAR_OUTPUT
  OUT_Sm : BOOL ;    
  OUT_GW_Min : BOOL ;    
  OUT_GW_Max : BOOL ;    
END_VAR
VAR_TEMP
  Zeiger_auf_Wert : DINT ;    
  Realwert_Start_Adresse : DINT ;    
  Messwert_REAL : REAL ;    
  Messwert_INT : INT ;    
  DB_open : INT ;    
  GW_Min_Ein : REAL ;    
  GW_Min_Aus : REAL ;    
  GW_Max_Ein : REAL ;    
  GW_Max_Aus : REAL ;    
  Ersatzwert : REAL ;    
  Offset_Fuehler : REAL ;    
  test_int : INT ;    
  HmNull : BOOL ;    
  Sm_Drahtbr : BOOL ;    //Störung sofort: Messwert Drahtbruch
  Sm_Ueberlauf : BOOL ;    //Störung sofort: Messwert Überlauf
  Sm_sofort : BOOL ;    //Sammelstörung sofort: Messwert ist nicht plausibel ---> Funktionen sperren
  Sm_verzoegert : BOOL ;    
  test_am : BOOL ;    
END_VAR
BEGIN
NETWORK
TITLE =Messwert skalieren

//--- Datenbaustein öffnen
      L     #IN_DBNr; 
      T     #DB_open; 
      AUF   DB [#DB_open]; 

//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr; //Anfangsadresse sprich erster Wert
      SLD   3; 
      T     #Zeiger_auf_Wert; 

// Werte aus DB holen Versuch 1
      L     #Zeiger_auf_Wert; // hole Zeiger Wert
      L     P#4.0; // erhöhe um 4x8 Bit
      +D    ; 
      T     #Zeiger_auf_Wert; // schreibe Zeiger zurueck
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #GW_Min_Ein; // schreibe in Temp Variable

      L     #Zeiger_auf_Wert; 
      L     P#4.0; 
      +D    ; 
      T     #Zeiger_auf_Wert; 
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #GW_Min_Aus; 

      L     #Zeiger_auf_Wert; 
      L     P#4.0; 
      +D    ; 
      T     #Zeiger_auf_Wert; 
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #GW_Max_Ein; 

      L     #Zeiger_auf_Wert; 
      L     P#4.0; 
      +D    ; 
      T     #Zeiger_auf_Wert; 
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #GW_Max_Aus; 

      L     #Zeiger_auf_Wert; 
      L     P#4.0; 
      +D    ; 
      T     #Zeiger_auf_Wert; 
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #Ersatzwert; 

      L     #Zeiger_auf_Wert; 
      L     P#10.0; 
      +D    ; 
      T     #Zeiger_auf_Wert; 
      L     DBD [#Zeiger_auf_Wert]; // hole gezeigten Wert
      T     #Offset_Fuehler; 


NETWORK
TITLE =Messwert skalieren

// Skalierung Integer
      L     #IN_PEW; 
      L     10; 
      /I    ; 
      T     #Messwert_INT; 

//Skalierung REAL, Offset miteinbeziehen
      L     #IN_PEW; 
      ITD   ; 
      DTR   ; 
      L     1.000000e+001; 
      /R    ; 
      L     #Offset_Fuehler; 
      +R    ; 
      T     #Messwert_REAL; 

NETWORK
TITLE =
//via Zeiger die Werte aus dem DB lesen und schreiben
//angepasst auf die Struktur des DB
//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr; //Anfangsadresse sprich erster Wert
      SLD   3; 
      T     #Zeiger_auf_Wert; 


// Messwert nach DB schreiben
      L     #Messwert_REAL; // hole umgewandelten Wert
      T     DBD [#Zeiger_auf_Wert]; // schreibe in DB



NETWORK
TITLE =Grenzwert Min

      L     #Messwert_REAL; 
      L     #GW_Min_Ein; 
      <R    ; 
      S     #OUT_GW_Min; 

      L     #Messwert_REAL; 
      L     #GW_Min_Aus; 
      >R    ; 
      R     #OUT_GW_Min; 
NETWORK
TITLE =Grenzwert Max

      L     #Messwert_REAL; 
      L     #GW_Max_Ein; 
      >R    ; 
      S     #OUT_GW_Max; 

      L     #Messwert_REAL; 
      L     #GW_Max_Aus; 
      <R    ; 
      R     #OUT_GW_Max; 
NETWORK
TITLE =Überwachung auf Drahtbruch
//Bildung Nullmerker
      SET   ; 
      R     #HmNull; 


NETWORK
TITLE =Überwachung auf Drahtbruch
//Drahtbruch = Überlauf
      U     #HmNull; 
      =     #Sm_Drahtbr; 
NETWORK
TITLE =Überwachung auf Überlauf
//0   =     0 Einheiten
//300 =  3000 Einheiten
      U(    ; 
      L     #IN_PEW; 
      L     3000; 
      >=I   ; 
      )     ; 
      U     #IN_Netz_OK; 
      =     #Sm_Ueberlauf; 
NETWORK
TITLE =Sammelstörung sofort - Messwert nicht plausibel bzw. verwendbar
//Meldung für sofortige Reaktionen z.B.: Sperrung von Aggregaten bei Messfehlern
//auch ohne Netzspannung aktiv!
      O(    ; 
      L     #IN_PEW; 
      L     -500; 
      <=I   ; 
      )     ; 
      O(    ; 
      L     #IN_PEW; 
      L     3000; 
      >=I   ; 
      )     ; 
      =     #Sm_sofort; 
NETWORK
TITLE =Ausgabe einer verzögerten Analogwertsammelstörung

      U(    ; 
      O     #Sm_Drahtbr; 
      O     #Sm_Ueberlauf; 
      )     ; 
      UN    #IN_Ersatzw_ein; 
      L     S5T#5S; 
      SE    #IN_Timer_Nr; 
NETWORK
TITLE =Ausgabe der verzögerten Störung als statische Meldung
//Diese Störung ist zur Weiterverabeitung für Sammelstörung, Prozessleitsytem,
//Priotritätenerzeugung gedacht
      U     #IN_Quitt; 
      R     #Sm_verzoegert; 
      U     #IN_Timer_Nr; 
      S     #Sm_verzoegert; 
      U     #Sm_verzoegert; 
      =     #OUT_Sm; 
NETWORK
TITLE =


      L     0; 
      T     DBD [#Zeiger_auf_Wert]; 
NETWORK
TITLE =Bausteinende Normalbetrieb     --- Ersatzwertfreigabe ---

      UN    #IN_Ersatzw_ein; 
      BEB   ; 

NETWORK
TITLE =Ausgabe des skalierten Ersatzwertes als Messwert


      L     #Ersatzwert; 
      T     #Messwert_REAL; // Ersatzwert zum Real Out

      L     #Ersatzwert; 
      RND   ; 
      T     #Messwert_INT; // Ersatzwert zum Int Out

NETWORK
TITLE =Meldungen sperren
//Die Verzögerte Störung wird direkt am TON verriegelt, um bei Rückschaltung
//ohne Ersatzwert eine neu Störungsflanke zu erhalten.
      UN    #HmNull; 
      R     #Sm_Drahtbr; 
      R     #Sm_Ueberlauf; 
      R     #Sm_sofort; 
END_FUNCTION
 
Guten Morgen zusammen,

dieser Versuch funktioniert nun. Der FC macht nun bei mehrfachaufruf das gewollte.
Hab die registerindirekte Adressierung mit AR1 benutzt.
Besten Dank nochmal für die Hilfe.

Code:
FUNCTION "Test_FC_AM" : VOID
TITLE =
//Der FC301 überwacht den Analogwert (Fuehler PT100)im Toleranzbereich
//von -50 bis +300°C.
//Wird dieser Bereich verletzt, werden entsprechende Meldungen ausgegeben.
//Während eines Netzausfalles werden keine Störungsmeldungen erzeugt.
//
//Werte werden via Zeiger aus dem DB gelesen und geschrieben, DB angepasst.
//
//Timer muss uebergeben werden.
VERSION : 0.1


VAR_INPUT
  IN_PEW : INT ;    //Analoger Eingangswert
  IN_DBNr : INT ;    //Eingabe:DB Nummer Sensorik
  IN_Start_Nr : DINT ;    //Startadresse des ersten Wert
  IN_Netz_OK : BOOL ;    //Netz OK Meldung zur Fehlerunterdrückung
  IN_Quitt : BOOL ;    //Statische Meldungen quittieren
  IN_Ersatzw_ein : BOOL ;    //Freigabe der Aufschaltung Ersatzwert mit reset aller Störungen
  IN_Timer_Nr : TIMER ;    
END_VAR
VAR_OUTPUT
  OUT_Sm : BOOL ;    
  OUT_GW_Min : BOOL ;    
  OUT_GW_Max : BOOL ;    
END_VAR
VAR_TEMP
  Zeiger_auf_Wert : DINT ;    
  Realwert_Start_Adresse : DINT ;    
  Messwert_REAL : REAL ;    
  Messwert_INT : INT ;    
  DB_open : INT ;    
  GW_Min_Ein : REAL ;    
  GW_Min_Aus : REAL ;    
  GW_Max_Ein : REAL ;    
  GW_Max_Aus : REAL ;    
  Ersatzwert : REAL ;    
  Offset_Fuehler : REAL ;    
  test_int : INT ;    
  HmNull : BOOL ;    
  Sm_Drahtbr : BOOL ;    //Störung sofort: Messwert Drahtbruch
  Sm_Ueberlauf : BOOL ;    //Störung sofort: Messwert Überlauf
  Sm_sofort : BOOL ;    //Sammelstörung sofort: Messwert ist nicht plausibel ---> Funktionen sperren
  Sm_verzoegert : BOOL ;    
  test_am : BOOL ;    
END_VAR
BEGIN
NETWORK
TITLE =
//via Zeiger (registerindirekte Adressierung mit AR1)
//die Werte aus dem DB lesen und schreiben
//angepasst auf die Struktur des DB

//--- Datenbaustein öffnen
      L     #IN_DBNr; 
      T     #DB_open; 
      AUF   DB [#DB_open]; 

//--- Pointer auf die Anfangsadresse des Datenbausteinbereichs 
      L     #IN_Start_Nr; //Anfangsadresse sprich erster Wert
      SLD   3; //mit 8 multiplizieren, um Pointerformat im DBD zu erhalten
      LAR1  ; //Lade den Pointer von AKKU 1 in AR1

// ersten Werte holen, Startadresse +4
      L     DBD [AR1,P#4.0]; 
      T     #GW_Min_Ein; 

// zweiten Werte holen, Startadresse +8
      L     DBD [AR1,P#8.0]; 
      T     #GW_Min_Aus; 

// dritten Werte holen, Startadresse +12
      L     DBD [AR1,P#12.0]; 
      T     #GW_Max_Ein; 

// vierten Werte holen, Startadresse +16
      L     DBD [AR1,P#16.0]; 
      T     #GW_Max_Aus; 

// fuenften Werte holen, Startadresse +20
      L     DBD [AR1,P#20.0]; 
      T     #Ersatzwert; 

// sechsten Werte holen, Startadresse +30
      L     DBD [AR1,P#30.0]; 
      T     #Offset_Fuehler; 

NETWORK
TITLE =Messwert skalieren

// Skalierung Integer
      L     #IN_PEW; 
      L     10; 
      /I    ; 
      T     #Messwert_INT; 

//Skalierung REAL, Offset miteinbeziehen
      L     #IN_PEW; 
      ITD   ; 
      DTR   ; 
      L     1.000000e+001; 
      /R    ; 
      L     #Offset_Fuehler; 
      +R    ; 
      T     #Messwert_REAL; 

// schreibe Istwert in REAL nach Startadresse +0
      L     #Messwert_REAL; 
      T     DBD [AR1,P#0.0]; 

NETWORK
TITLE =Grenzwert Min

      L     #Messwert_REAL; 
      L     #GW_Min_Ein; 
      <R    ; 
      S     #OUT_GW_Min; 

      L     #Messwert_REAL; 
      L     #GW_Min_Aus; 
      >R    ; 
      R     #OUT_GW_Min; 
NETWORK
TITLE =Grenzwert Max

      L     #Messwert_REAL; 
      L     #GW_Max_Ein; 
      >R    ; 
      S     #OUT_GW_Max; 

      L     #Messwert_REAL; 
      L     #GW_Max_Aus; 
      <R    ; 
      R     #OUT_GW_Max; 
NETWORK
TITLE =Überwachung auf Drahtbruch
//Bildung Nullmerker
      SET   ; 
      R     #HmNull; 


NETWORK
TITLE =Überwachung auf Drahtbruch
//Drahtbruch = Überlauf
      U     #HmNull; 
      =     #Sm_Drahtbr; 
NETWORK
TITLE =Überwachung auf Überlauf
//0   =     0 Einheiten
//300 =  3000 Einheiten
      U(    ; 
      L     #IN_PEW; 
      L     3000; 
      >=I   ; 
      )     ; 
      U     #IN_Netz_OK; 
      =     #Sm_Ueberlauf; 
NETWORK
TITLE =Sammelstörung sofort - Messwert nicht plausibel bzw. verwendbar
//Meldung für sofortige Reaktionen z.B.: Sperrung von Aggregaten bei Messfehlern
//auch ohne Netzspannung aktiv!
      O(    ; 
      L     #IN_PEW; 
      L     -500; 
      <=I   ; 
      )     ; 
      O(    ; 
      L     #IN_PEW; 
      L     3000; 
      >=I   ; 
      )     ; 
      =     #Sm_sofort; 
NETWORK
TITLE =Ausgabe einer verzögerten Analogwertsammelstörung

      U(    ; 
      O     #Sm_Drahtbr; 
      O     #Sm_Ueberlauf; 
      )     ; 
      UN    #IN_Ersatzw_ein; 
      L     S5T#5S; 
      SE    #IN_Timer_Nr; 
NETWORK
TITLE =Ausgabe der verzögerten Störung als statische Meldung
//Diese Störung ist zur Weiterverabeitung für Sammelstörung, Prozessleitsytem,
//Priotritätenerzeugung gedacht
      U     #IN_Quitt; 
      R     #Sm_verzoegert; 
      U     #IN_Timer_Nr; 
      S     #Sm_verzoegert; 
      U     #Sm_verzoegert; 
      =     #OUT_Sm; 
NETWORK
TITLE =Bausteinende Normalbetrieb     --- Ersatzwertfreigabe ---

      UN    #IN_Ersatzw_ein; 
      BEB   ; 

NETWORK
TITLE =Ausgabe des skalierten Ersatzwertes als Messwert


      L     #Ersatzwert; 
      T     #Messwert_REAL; // Ersatzwert zum Real Out

      L     #Ersatzwert; 
      RND   ; 
      T     #Messwert_INT; // Ersatzwert zum Int Out

NETWORK
TITLE =Meldungen sperren
//Die Verzögerte Störung wird direkt am TON verriegelt, um bei Rückschaltung
//ohne Ersatzwert eine neu Störungsflanke zu erhalten.
      UN    #HmNull; 
      R     #Sm_Drahtbr; 
      R     #Sm_Ueberlauf; 
      R     #Sm_sofort; 
END_FUNCTION
 
Danke für die Erfolgs-Rückmeldung und den nützlichen Baustein.

Allerdings ist da noch eine Kleinigkeit:
#Sm_verzoegert ist in TEMP deklariert, Du benutzt ihn aber speichernd (S/R).

Der Inhalt von TEMP-Variablen ist beim Bausteineintritt unbestimmt solange man ihnen nichts zugewiesen hat, weil nach Verlassen des Bausteins bis zum nächsten Durchlauf andere Bausteine den Speicherplatz in TEMP benutzt und verändert haben können.
Du müsstest dem FC noch ein IN_OUT gönnen, oder die Adresse des äußeren Störmerkers mitteilen und den dann direkt indirekt setzen/rücksetzen.

Harald
 
Zurück
Oben