Indirekte Versorgung FC1 Add DT Time

roadrunner

Level-1
Beiträge
58
Reaktionspunkte
4
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

wie wird der Ret_Val Parameter hier (Date_and_Time) von aussen versorgt?

Code:
      CALL  "AD_DT_TM"
       T      :=#CDT
       D      :=#Zeitversch
       RET_VAL:=#CPU_Zeit

Muss man hier mit einem Hilfszeiger arbeiten ?
 
du musst in einem db ein var vom typ date_and_time anlegen

am retval sieht das dann so aus
"DB_DT".dt_add
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das "Date_and_Time"-Format besteht aus 8 Byte, Du jedoch nur max. 4 Byte (= 1 Doppelwort) direkt adressieren. Alle längeren Formate müssen über Hilfszeiger indirekt adressiert werden. In Deinem Fall bedeutet das einen Hilfszeiger vom Typ Date_and_Time anlegen. Wenn Du diesen bauteinübergreifend kopieren willst kannst Du, z. B. eine Variable vom Typ "Date_and_Time" in einem DB anlegen.
 
@ volker

Hallo,

so hab ich es im Moment.

Der Aufruf von diesem FC1 befindet sich in einem FC.

Wegen der Wiederverwendbarkeit möchte ich dem FC einen Parameter übergeben für den RET_VAL Parameter vom Typ DT.

Da der Parameter aber ein "zusammengesetzer Typ" ist geht das nicht direkt, oder?

Gruß
roadrunner
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielen Dank,

FB funktioniert.

Habe aber auch den FC mit Hilfszeigern probiert.

Code:
     CALL  "AD_DT_TM"
       T      :=#CDT(DT)
       D      :=#Zeitversch(Time)
       RET_VAL:=#CPU_Zeit(DT)
 
      TAR1  #tmp_AR1
      TAR2  #tmp_AR2
 
      L     P##systemzeit (Var_Input Typ any)
      LAR1
  
      L     P##tmp(Temp Variable Typ any)
      LAR2  
      L     D [AR1,P#0.0]
      T     LD [AR2,P#0.0]
      L     D [AR1,P#4.0]
      T     LD [AR2,P#4.0]
      L     W [AR1,P#8.0]
      T     LW [AR2,P#8.0]
 
      LAR1  #tmp_AR1
      LAR2  #tmp_AR2
 
      CALL  "BLKMOV"
       SRCBLK :=#CPU_Zeit(DT)
       RET_VAL:=#rv
       DSTBLK :=#tmp(Temp any)

Es funktioniert aber nur mit any als Input Variable, nicht mit DT.

Kann mir jemand erklären woran das liegt?

gruß
roadrunner
 
In FC DATE_AND_TIME-Parameter von IN nach TEMP und von TEMP nach OUT kopieren

Es funktioniert aber nur mit any als Input Variable, nicht mit DT.

Kann mir jemand erklären woran das liegt?
DATE_AND_TIME (DT) wird bei FC als 6-Byte-POINTER übergeben.

Hier mal ein Beispiel, wie man in einem FC DATE_AND_TIME-Parameter von IN nach TEMP und von TEMP nach OUT kopiert (blaue Schrift).
Außerdem der Aufruf des "AD_DT_TM" mit TEMP-DATE_AND_TIME.
(hier FC50)
Code:
FUNCTION "BT_LT_3" : VOID
TITLE =BT_LT_3: Convert base time to local time (Summertime/Wintertime)
//Ersatz für FC61 BT_LT aus der S7-Standard-Library auf S7-300, die keinen 
//Uhrzeitstatus besitzen (Im Uhrzeitstatus der CPU sind die Basiszeit sowie 
//die für den jeweiligen Ort geltende Zeitzone, eine Sommerzeit-Kennung sowie 
//eine Kennung für die Ankündigungsstunde hinterlegt und werden von der CPU 
//aktualisiert.) BT_LT_3 benutzt keinen Regel-DB.
//
//Typisches Szenario:
//Eine S7-300-CPU besitzt keinen Uhrzeitstatus, die CPU-Uhr ist nach der lokalen 
//Normalzeit (Winterzeit) gestellt und ggf. nach NTP-Verfahren synchronisiert.
//BT_LT_3 ermittelt, ob der am Eingang BT angegebene Zeitpunkt in der Sommerzeit 
//liegt und gibt am Ausgang LT die ggf. als Sommerzeit korrigierte lokale Uhrzeit 
//aus. BT muß ein gültiges DATE_AND_TIME inkl. Wochentag sein.
//
//BT_LT_3 berücksichtigt keine Zeitzone, sondern nur den Uhrzeit-Versatz in 
//der Sommerzeit. Die Sommerzeit gilt vom letzten Sonntag im März 02:00 BT 
//bis zum letzten Sonntag im Oktober 02:00 BT (03:00 ST).
//BT_LT_3 benutzt intern die folgende Funktion der S7-Standard-Library – 
//IEC Function Blocks: FC(1) AD_DT_TM
AUTHOR : PN_DP
FAMILY : TIMEFUNC
NAME : BT_LT_3
VERSION : 1.0

VAR_INPUT
  BT : DATE_AND_TIME ;       //Basiszeit (z.B. CPU-Clock)
END_VAR
VAR_OUTPUT
  LT : DATE_AND_TIME ;       //Lokalzeit
  SUMMER : BOOL ;            //Sommerzeitkennung (0: Winter / 1: Sommer)
END_VAR
VAR_TEMP
  AR1_Save : DWORD ;
  AR2_Save : DWORD ;
  tmpBT : DATE_AND_TIME ;
  tmpLT : DATE_AND_TIME ;
  DB_No : INT ;
  LT_Offset : TIME ;
  March : BOOL ;
END_VAR
BEGIN
[COLOR="Blue"]NETWORK
TITLE =Basiszeit von IN-Aktualparameter BT in TEMP kopieren
//DATE_AND_TIME (DT) wird bei FC als 6-Byte-POINTER übergeben und kann nicht 
//direkt weitergereicht werden. Deshalb IN.BT nach TEMP umkopieren.[/COLOR]

//Adressregister sichern
      TAR1  #AR1_Save;
      TAR2  #AR2_Save;

[COLOR="blue"]//Pointer auf IN-Aktualparameter BT erstellen
      L     P##BT;             // Adresse IN.BT
      LAR1  ;
      L     W [AR1,P#0.0];     // POINTER.DB_Nr
      T     #DB_No;
      L     D [AR1,P#2.0];     // POINTER.Bereichsadresse
      LAR1  ;                  // AR1: Adresse des IN-DT
      LAR2  P##tmpBT;          // AR2: Adresse des TEMP-DT

//DATE_AND_TIME (8 Byte) BT von IN nach TEMP kopieren
      AUF   DB [#DB_No];
      L     D [AR1,P#0.0];
      T     LD [AR2,P#0.0];
      L     D [AR1,P#4.0];
      T     LD [AR2,P#4.0];[/COLOR]

NETWORK
TITLE =Ermitteln ob Sommerzeit ist und Lokalzeit berechnen
//Die Sommerzeit gilt vom letzten Sonntag im März 02:00 BT 
//bis zum letzten Sonntag im Oktober 02:00 BT (03:00 ST)

//AR2: Pointer auf tmpBT

//Der letzte Sonntag im März bzw. Oktober kann auf 25. bis 31. fallen
//vor 25.03. ist Winterzeit
      L     LW [AR2,P#1.0];    // tmpBT.Monat (BCD) + Tag (BCD)
      L     DW#16#325;         // vor 25.03. ist WZ
      <I    ;
      SPB   WINZ;

//nach 31.10. ist Winterzeit
      POP   ;                  // tmpBT.Monat (BCD) + Tag (BCD)
      L     W#16#1031;         // nach 31.10. ist WZ
      >I    ;
      SPB   WINZ;

//nach 31.03. (= 01.04.) bis vor 25.10. (= 24.10.) ist Sommerzeit
      POP   ;                  // tmpBT.Monat (BCD) + Tag (BCD)
      L     W#16#331;          // bis 31.03. Umschaltwoche zu SZ
      <=I   ;
      =     #March;            // Umschaltwoche WZ zu SZ
      SPB   SPEZ;

      POP   ;                  // tmpBT.Monat (BCD) + Tag (BCD)
      L     W#16#1025;         // bis vor 25.10. ist SZ
      <I    ;
      SPB   SOMZ;

//hier nur noch 25.03.-31.03. und 25.10.-31.10.
//letzter Sonntag ?
SPEZ: L     LB [AR2,P#7.0];    // tmpBT.Wochentag 1=So ... 7=Sa
      UW    W#16#F;            // nur Bits .0-.3 (4 LSB)
      L     B#16#1;
      -I    ;                  // WoT: 0=So, 1=Mo, ... 6=Sa
      SPZ   SONN;              // jetzt ist der Umschalt-Sonntag
//Akku1: Wochentag 0=So ... 6=Sa
      L     LB [AR2,P#2.0];    // tmpBT.Tag (BCD)
      BTI   ;                  // Tag (INT)
      TAK   ;                  // Akku1: WoT, Akku2: Tag
      -I    ;
//Ergebnis 19..24 sind Tage vor Umschalt-Sonntag
      L     25;
      <I    ;
      SPBN  NACH;

//Vor Umschalt-Tag bzw. -Uhrzeit
VOR:  U     #March;
      SPB   WINZ;              // März: noch ist Winterzeit
      SPA   SOMZ;              // Okt.: noch ist Sommerzeit

//Nach Umschalt-Tag bzw. -Uhrzeit
NACH: U     #March;
      SPB   SOMZ;              // März: nun ist Sommerzeit
      SPA   WINZ;              // Okt.: nun ist Winterzeit

//es ist jetzt der Umschalt-Sonntag
SONN: L     LB [AR2,P#3.0];    // tmpBT.Stunde (BCD)
      L     B#16#2;            // vor 02:00 Uhr?
      <I    ;
      SPB   VOR;
      SPA   NACH;

//Signalisierung Sommerzeit oder Winterzeit
SOMZ: S     #SUMMER;
      L     T#1H;              // 1 Stunde Zeitdifferenz SZ-WZ
      SPA   TLTO;

WINZ: R     #SUMMER;
      L     T#0MS;             // Winterzeit ist Basiszeit

TLTO: T     #LT_Offset;

//Lokalzeit berechnen
      CALL "AD_DT_TM" (
           T       := #tmpBT,
           D       := #LT_Offset,
           RET_VAL := #tmpLT);

NETWORK
[COLOR="blue"]TITLE =Lokalzeit von TEMP in OUT-Aktualparameter LT kopieren
//DATE_AND_TIME (DT) wird bei FC als 6-Byte-POINTER übergeben, OUT kann nicht 
//direkt von anderen FC beschrieben werden. Deshalb mit TEMP-Kopie arbeiten.

//Pointer auf OUT-Aktualparameter LT erstellen
      L     P##LT;             // Adresse OUT.LT
      LAR1  ;
      L     W [AR1,P#0.0];     // POINTER.DB_Nr
      T     #DB_No;
      L     D [AR1,P#2.0];     // POINTER.Bereichsadresse
      LAR1  ;                  // AR1: Adresse des OUT-DT
      LAR2  P##tmpLT;          // AR2: Adresse des TEMP-DT

//DATE_AND_TIME (8 Byte) LT von TEMP nach OUT kopieren
      AUF   DB [#DB_No];
      L     LD [AR2,P#0.0];
      T     D [AR1,P#0.0];
      L     LD [AR2,P#4.0];
      T     D [AR1,P#4.0];[/COLOR]

//Adressregister wiederherstellen + BIE/ENO auf TRUE setzen
      LAR1  #AR1_Save;
      LAR2  #AR2_Save;
      SET   ;
      SAVE  ;

END_FUNCTION

Hier ein typischer Aufruf des Bausteins im OB1:
Code:
//copy current local date and time to OP-areapointer
      CALL  "BT_LT_3"                                 //FC50
       BT    :=#OB1_DATE_TIME
       LT    :="PLC->OP".AreaPointerDtPLC.DateTimePLC //P#DB102.DBX0.0 BYTE 8
       SUMMER:="Summertime"                           //M1.7

Harald
 
Vielen Dank,

das funktioniert natürlich ;)

Ist meine Version weiter oben mit SFC20 BLKMOV und any so weit auch richtig?

Gruß
roadrunner
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ich habs nicht im Detail geprüft, aber grundsätzlich funktioniert es mit dem BlockMove, der verschiebt ja nur und es ist ihm egal was darin steht!

Warum nimmst Du keinen FB und machst daraus eine Multiinstanz? Das wäre doch viel einfacher und übersichtlicher.
 
ich habs nicht im Detail geprüft, aber grundsätzlich funktioniert es mit dem BlockMove, der verschiebt ja nur und es ist ihm egal was darin steht!

Warum nimmst Du keinen FB und machst daraus eine Multiinstanz? Das wäre doch viel einfacher und übersichtlicher.

Das mit dem FB hab ich wie von dir oben vorgeschlagen schon getestet, funktioniert einwandfrei.
Es ging mir nur um die Verständnisfrage wie das auch mit einem FC klappen könnte.

Wie PN/DP geschrieben hat, funktionierte diese Version auch.

Vielen Dank an alle für die Informationen. *ACK*

Gruß
roadrunner
 
Ist meine Version weiter oben mit SFC20 BLKMOV und any so weit auch richtig?
Du hast zwar den Aktualwert des IN-Parameters #systemzeit (ANY) in eine lokale Variable #tmp (ANY) umkopiert um diese Adresse an den SFC20 übergeben zu können und scheinbar funktionierte Dein Vorgehen, es besteht aber folgende Gefahr:
Wenn der Aktualparameter am FC-IN-Parameter #systemzeit eine TEMP-Variable des aufrufenden Bausteins ist, dann funktioniert der SFC20 NICHT richtig, er wird im TEMP-Bereich Deines Bausteins herumschreiben, statt auf die Variable des aufrufenden Bausteins.

Es ist nicht möglich, POINTER oder ANY-Pointer auf TEMP-Variablen durch mehrere Bausteine durchzureichen, weil diese Adressen auf den Vorgänger-TEMP dann ungültig werden (der aufrufende Vorgänger wäre dann ja der Vor-Vorgänger!). Jeder aufgerufene FC muß den erhaltenen Pointer selbst auflösen und den Wert der "pointierten" Variable in eine andere lokale (oder globale) Variable umspeichern (Kopie) und dann einen neuen Pointer auf die neue Variable erstellen. Auch zu diesem Umspeichern kann kein weiterer Baustein aufgerufen werden (also auch kein SFC20!), der FC muß das umspeichern selber per bereichsübergreifender registerindirekter Adressierung tun. Deshalb geht sowas nur in AWL.

Von daher: Ich würde den SFC20 nicht benutzen, auch wenn es in dem Spezialfall funktioniert, wo der Aktualwert an #systemzeit eine DB-Adresse ist.

Harald
 
Zurück
Oben