Step 7 Impulsgeber auswerten (Wasserdurchfluß)

daxxar

Level-1
Beiträge
13
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo SPS Freunde,

ich befürchte ich begehe einen Denkfehler!

Ich habe einen Durchflusssensor.
Dieser liefert mir maximal 4 Impulse in der Minute, um 10 Liter Wasserdurchfluss anzuzeigen.

Die Idee war, dass ich 60Sekunden lang die Impulse zähle.
4 Impulse in 60 Sekunden = 10L/min
3 Impulse in 60 Sekunden = 7,5L/min
2 Impulse in 60 Sekunden = 5L/min
1 Impuls in 60Sekunden = 2,5L/min
0 = 0

Aber so aktualisiert sich meine Anzeige nur alle 60 Sekunden und zeigt den vergangenen Durchlauf an.

Also dachte ich, ich zähle 15 Sekunden hoch, und prüfe, ob in dieser Zeit ein Impuls gekommen ist. => 10L/min
Falls nicht, zähle ich weiter bis 30 Sekunden und prüfe noch einmal ob ein Impuls gekommen ist. => 5L/min
Falls nicht, zähle ich weiter bis 45 Sekunden ... usw.

Mich beschleicht das Gefühl, dass ich die Sache falsch angehe, und dass die Auswertung auch genauer funktionieren muss.

Hat jemand eine bessere / genauere / schneller Umsetzung?
 
Ja, das Problem kenn ich. Ich verwende nach langem umherprobieren mittlerweile die Differenzzeit zwischen 2 Impulsen.
Das Funktioniert nach meiner Erfahrung am besten. So bekommt man auch lange auseinanderliegende Impulse vernünfitg
in einen Durchfluß konvertiert. Leider ist das nicht ganz so trivial! Das fängt schon bei der Differenz der SysTime an. Diese
ist 31Bit, nicht 32 Bit, deswegen kann man nicht einfach eine Differenz bilden.

Schritt 1: man muss die Zeit zwischen 2 Impulsen ermitteln
Schritt 2: man muss aus der Differenzzeit den Fluß bestimmen
man muss das venünftig begrenzen (auf die Max. mögl. Zeitdifferenz) sonst zeigt das Blödsinn an.

ich verwende 3 Bausteine dafür:
1. Absolute Differenz der Systemzeit
2. Zeit zwischen 2 Impulsen bestimmen
3. Zeit => Durchfluss

hier der Code aller 3 FCs als AWL Quelle
Code:
FUNCTION "m7b_ABS_DIFF_S7SysTime" : VOID
TITLE =ABS_DIFF_S7SysTime : Differenz zweier S7SystemZeiten 31Bit-Werte
//Da die S7 Systemzeit mittels SFC64 "TIME_TCK" nur 31 Bit 0..2147483647 ms
//aufweist gibt es einen Fehler, wenn Zeitdifferenzen über eine Timerüberlauf
//ermittelt werden. Um dies zu verhindern muss die Systemzeit auf 32Bit erweitert 
//werden.
//
//Der Aufruf dieses FC ist für AWL vorgesehn, als Unconditioned Call
//
//L  #SysTime1
//L  #SysTime2
//UC FC 256
//T  #TimeDiff
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 13/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME        AENDERUNG
//--------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  FP_Signal : BOOL ;    //Flanke Signal
END_VAR
VAR_IN_OUT
  memByte : BYTE ;    
  memTime : TIME ;    
  out_DeltaTime : TIME ;    
END_VAR
VAR_TEMP
  SysTimer : TIME ;    
END_VAR
BEGIN
NETWORK
TITLE =die beiden Zeitwerte müssen bereits in den Akkus stehen

      SLD   1; // 1. Zeit in Akku 1 auf 32 Bit-Wert erweitern
      TAK   ; // Akkus tauschen
      SLD   1; // 2. Zeit auf 32 Bit-Wert erweitern
      -D    ; // Differenz bilden (=doppelte Differenz)
      SPPZ  pos; // If <0 THEN 
      NEGD  ; //             'Vorzeichen umkehren' 
pos:  SRD   1; // 32 Bit Korrektur wieder entferen TimeDiff nun in AKKU 1



END_FUNCTION

FUNCTION "m7b_DeltaTime" : VOID
TITLE =DeltaTime : Zeitdifferenz zwischen 2 Impulsen
//Ermittelt den Abstand zwischen 2 Impulsen.
//In io_DeltaTime wird der Abstand des letzten Impulses gespeichert.
//DSP_ActTimDiff zeigt die seit letztem Impuls aktuell vergangene Zeit
//MAX_timDiff = MAX(io_DeltaTime, DSP_TimeDiffAkt)
//
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 11/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME        AENDERUNG
//--------------------------------------------------------------------------------
//04/09/2017   S.Maag      RESET Eingang + einfrieren 1sec vor max Differenz
//
//16/01/2014   S.Maag      ENO=TRUE
//
//03/12/2013   S.Maag      SFC64 TimeTick Zeitdifferenz korrigiert
//                         da 31Bit, Fehler bei Überlauf. 
//                         jetzt Differenzber. mit FC256 "ABS_DIFF_S7SysTime"
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  FP_Signal : BOOL ;    //Flanke Signal
  RESET : BOOL ;    
END_VAR
VAR_OUTPUT
  DSP_ActTimeDiff : TIME ;    //Anzeige aktuelle Zeitdifferenz seit letztem Ereignis
  MAX_timDiff : TIME ;    //Max(timDiff, io_DeltaTime)
END_VAR
VAR_IN_OUT
  memTime : TIME ;    
  io_DeltaTime : TIME ;    
END_VAR
VAR_TEMP
  SysTimer : TIME ;    
END_VAR
BEGIN
NETWORK
TITLE =

      SET   ; 
      SAVE  ; 
      CLR   ; 

NETWORK
TITLE =
//31Bit = 7F FF FF FF = 2147483647 - 1000ms = 2147482647 ms 
//1sec vor Ablauf der max Differenz den Differenzwert einfrieren bis neuer Impuls 
//kommt.
//Dies verhindert Überlauf der Zeitdifferenz uns somit eine Rückfall der 
//Differenzzeit auf 0 ohne neuen Impuls
      UN    #RESET; 
      SPB   do; 

      L     T#0MS; 
      T     #DSP_ActTimeDiff; 
      T     #MAX_timDiff; 
      SPA   ne2; 

do:   NOP   0; 
      CALL "TIME_TCK" (
           RET_VAL                  := #SysTimer);

      L     #DSP_ActTimeDiff; // Wenn max. Zeitdifferenz erreicht,
      L     L#2147482647; // dann Wert einfrieren und erst
      >=D   ; // nach neuem Impuls weiter
      SPB   ne2; // dadurch wird ein überlauf verhindert

      L     #SysTimer; 
      L     #memTime; 
      UC    "m7b_ABS_DIFF_S7SysTime"; // Absolute Zeitdifferenz S7-SystemTimer 31Bit
      T     #DSP_ActTimeDiff; 
      L     #io_DeltaTime; 
      UC    "m7a_SelectDINT>"; 
      T     #MAX_timDiff; 
ne2:  NOP   0; 
NETWORK
TITLE =Zeit Ereignis

      UN    #FP_Signal; 
      SPB   ne3; 

      L     #DSP_ActTimeDiff; 
      T     #io_DeltaTime; 

      L     L#0; 
      T     #DSP_ActTimeDiff; 

      L     #SysTimer; 
      T     #memTime; 

ne3:  NOP   0; 
NETWORK
TITLE =



END_FUNCTION

FUNCTION "m7t_RealPerTime" : VOID
TITLE =RealPerTime:  REAL * TimeBase / Time
//Verwendung: Umrechnung von Impulsmengen auf Menge/Zeit
//
//z.B. 1 Impuls von Mengenzähler = 100 L (Liter)
//
//mit FC255, die Zeitdifferenz zwischen 2 Impulsen erfassen,
//
//      CALL  "m7t_RealPerTime"
//       rREAL      := 100.0       // Liter pro Impuls
//       timTime    := DeltaTime   // Differenzzeit zwischen 2 Impulsen
//       timTimeBase:= T#1h        // ZeitBasis 1 Stunde
//       rOUT       := RESULT      // Ergebnis Durchfluss L/h
//
//ENO: TRUE if no Error; FALSE if Error (Divison by Zero, timTime=0)
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 11/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME       AENDERUNG
//--------------------------------------------------------------------------------
//04/09/2017   S.Maag    Minimum Check: if <Min then rOut = 0
//04.12.213    S.Maag    Overflow check + ENO = 'NoError'
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  rREAL : REAL ;    //Menge pro Impuls
  timTime : TIME ;    
  timTimeBase : TIME ;    
  rMinMessGrenze : REAL ;    //Minimum, wenn <, dann rOut =0
END_VAR
VAR_OUTPUT
  rOUT : REAL ;    
END_VAR
VAR_TEMP
  rVAL : REAL ;    
END_VAR
BEGIN
NETWORK
TITLE =

      SET   ; 
      SAVE  ; 
      CLR   ; 

NETWORK
TITLE =

      L     #timTimeBase; 
      DTR   ; 
      L     #timTime; 
      DTR   ; 
      /R    ; 
      U     OV; // If OverFlow THEN Err
      SPB   Err; 
      L     #rREAL; 
      *R    ; 
      T     #rVAL; // Save result in rVAL
      L     #rMinMessGrenze; // If <Min
      <R    ; 
      L     0.000000e+000; // Then rOut = 0
      SPB   save; 

      L     #rVAL; // Load stored result
      SPA   save; 

Err:  CLR   ; 
      SAVE  ; 
      L     0.000000e+000; 
save: T     #rOUT; 
END_FUNCTION
 
Ich würde die Zeit zwischen zwei Impulsen des Zählers messen. So kriegst Du mit jedem Impuls den aktuellen Durchfluss:

Durchfluss [l/min] = (2,5 l * 60 sec/min) / X sec

X sind die gemessenen Sekunden.
 
Ich würde beide Verfahren anwenden:
- die Dauer zwischen zwei aufeinander folgenden Impulsen auswerten, wenn nur selten Impulse kommen,
- die Anzahl Impulse in einem ZeitTakt zählen und auswerten, wenn die Impulse schnell aufeinander folgen.
Wohin man die UmschaltGrenze zwischen beiden Verfahren legt, dürfte Geschmackssache sein.

Ausserdem würde ich untersuchen, wie die Impulse aussehen.
Wenn bei gleichbleibendem Durchfluss die Impulse annähernd solange auf High verweilen, wie auf Low, dann könnte man die positiven und die negativen Flanken der Impulse auswerten, sprich 8 Flanken pro Umdrehung. Dann wird die Wartezeit bis zur nächsten ÄnderungsMeldung vom Geber etwas kürzer. ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
hier der Code aller 3 FCs als AWL Quelle
Code:
FUNCTION "m7b_ABS_DIFF_S7SysTime" : VOID
TITLE =ABS_DIFF_S7SysTime : Differenz zweier S7SystemZeiten 31Bit-Werte
//Da die S7 Systemzeit mittels SFC64 "TIME_TCK" nur 31 Bit 0..2147483647 ms
//aufweist gibt es einen Fehler, wenn Zeitdifferenzen über eine Timerüberlauf
//ermittelt werden. Um dies zu verhindern muss die Systemzeit auf 32Bit erweitert 
//werden.
//
//Der Aufruf dieses FC ist für AWL vorgesehn, als Unconditioned Call
//
//L  #SysTime1
//L  #SysTime2
//UC FC 256
//T  #TimeDiff
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 13/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME        AENDERUNG
//--------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  FP_Signal : BOOL ;    //Flanke Signal
END_VAR
VAR_IN_OUT
  memByte : BYTE ;    
  memTime : TIME ;    
  out_DeltaTime : TIME ;    
END_VAR
VAR_TEMP
  SysTimer : TIME ;    
END_VAR
BEGIN
NETWORK
TITLE =die beiden Zeitwerte müssen bereits in den Akkus stehen

      SLD   1; // 1. Zeit in Akku 1 auf 32 Bit-Wert erweitern
      TAK   ; // Akkus tauschen
      SLD   1; // 2. Zeit auf 32 Bit-Wert erweitern
      -D    ; // Differenz bilden (=doppelte Differenz)
      SPPZ  pos; // If <0 THEN 
      NEGD  ; //             'Vorzeichen umkehren' 
pos:  SRD   1; // 32 Bit Korrektur wieder entferen TimeDiff nun in AKKU 1



END_FUNCTION

FUNCTION "m7b_DeltaTime" : VOID
TITLE =DeltaTime : Zeitdifferenz zwischen 2 Impulsen
//Ermittelt den Abstand zwischen 2 Impulsen.
//In io_DeltaTime wird der Abstand des letzten Impulses gespeichert.
//DSP_ActTimDiff zeigt die seit letztem Impuls aktuell vergangene Zeit
//MAX_timDiff = MAX(io_DeltaTime, DSP_TimeDiffAkt)
//
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 11/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME        AENDERUNG
//--------------------------------------------------------------------------------
//04/09/2017   S.Maag      RESET Eingang + einfrieren 1sec vor max Differenz
//
//16/01/2014   S.Maag      ENO=TRUE
//
//03/12/2013   S.Maag      SFC64 TimeTick Zeitdifferenz korrigiert
//                         da 31Bit, Fehler bei Überlauf. 
//                         jetzt Differenzber. mit FC256 "ABS_DIFF_S7SysTime"
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  FP_Signal : BOOL ;    //Flanke Signal
  RESET : BOOL ;    
END_VAR
VAR_OUTPUT
  DSP_ActTimeDiff : TIME ;    //Anzeige aktuelle Zeitdifferenz seit letztem Ereignis
  MAX_timDiff : TIME ;    //Max(timDiff, io_DeltaTime)
END_VAR
VAR_IN_OUT
  memTime : TIME ;    
  io_DeltaTime : TIME ;    
END_VAR
VAR_TEMP
  SysTimer : TIME ;    
END_VAR
BEGIN
NETWORK
TITLE =

      SET   ; 
      SAVE  ; 
      CLR   ; 

NETWORK
TITLE =
//31Bit = 7F FF FF FF = 2147483647 - 1000ms = 2147482647 ms 
//1sec vor Ablauf der max Differenz den Differenzwert einfrieren bis neuer Impuls 
//kommt.
//Dies verhindert Überlauf der Zeitdifferenz uns somit eine Rückfall der 
//Differenzzeit auf 0 ohne neuen Impuls
      UN    #RESET; 
      SPB   do; 

      L     T#0MS; 
      T     #DSP_ActTimeDiff; 
      T     #MAX_timDiff; 
      SPA   ne2; 

do:   NOP   0; 
      CALL "TIME_TCK" (
           RET_VAL                  := #SysTimer);

      L     #DSP_ActTimeDiff; // Wenn max. Zeitdifferenz erreicht,
      L     L#2147482647; // dann Wert einfrieren und erst
      >=D   ; // nach neuem Impuls weiter
      SPB   ne2; // dadurch wird ein überlauf verhindert

      L     #SysTimer; 
      L     #memTime; 
      UC    "m7b_ABS_DIFF_S7SysTime"; // Absolute Zeitdifferenz S7-SystemTimer 31Bit
      T     #DSP_ActTimeDiff; 
      L     #io_DeltaTime; 
      UC    "m7a_SelectDINT>"; 
      T     #MAX_timDiff; 
ne2:  NOP   0; 
NETWORK
TITLE =Zeit Ereignis

      UN    #FP_Signal; 
      SPB   ne3; 

      L     #DSP_ActTimeDiff; 
      T     #io_DeltaTime; 

      L     L#0; 
      T     #DSP_ActTimeDiff; 

      L     #SysTimer; 
      T     #memTime; 

ne3:  NOP   0; 
NETWORK
TITLE =



END_FUNCTION

FUNCTION "m7t_RealPerTime" : VOID
TITLE =RealPerTime:  REAL * TimeBase / Time
//Verwendung: Umrechnung von Impulsmengen auf Menge/Zeit
//
//z.B. 1 Impuls von Mengenzähler = 100 L (Liter)
//
//mit FC255, die Zeitdifferenz zwischen 2 Impulsen erfassen,
//
//      CALL  "m7t_RealPerTime"
//       rREAL      := 100.0       // Liter pro Impuls
//       timTime    := DeltaTime   // Differenzzeit zwischen 2 Impulsen
//       timTimeBase:= T#1h        // ZeitBasis 1 Stunde
//       rOUT       := RESULT      // Ergebnis Durchfluss L/h
//
//ENO: TRUE if no Error; FALSE if Error (Divison by Zero, timTime=0)
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 11/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME       AENDERUNG
//--------------------------------------------------------------------------------
//04/09/2017   S.Maag    Minimum Check: if <Min then rOut = 0
//04.12.213    S.Maag    Overflow check + ENO = 'NoError'
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1


VAR_INPUT
  rREAL : REAL ;    //Menge pro Impuls
  timTime : TIME ;    
  timTimeBase : TIME ;    
  rMinMessGrenze : REAL ;    //Minimum, wenn <, dann rOut =0
END_VAR
VAR_OUTPUT
  rOUT : REAL ;    
END_VAR
VAR_TEMP
  rVAL : REAL ;    
END_VAR
BEGIN
NETWORK
TITLE =

      SET   ; 
      SAVE  ; 
      CLR   ; 

NETWORK
TITLE =

      L     #timTimeBase; 
      DTR   ; 
      L     #timTime; 
      DTR   ; 
      /R    ; 
      U     OV; // If OverFlow THEN Err
      SPB   Err; 
      L     #rREAL; 
      *R    ; 
      T     #rVAL; // Save result in rVAL
      L     #rMinMessGrenze; // If <Min
      <R    ; 
      L     0.000000e+000; // Then rOut = 0
      SPB   save; 

      L     #rVAL; // Load stored result
      SPA   save; 

Err:  CLR   ; 
      SAVE  ; 
      L     0.000000e+000; 
save: T     #rOUT; 
END_FUNCTION
Programmiert Ihr wirklich so in Euren SPS-Programmen? Dann wärt Ihr bei uns als Lieferant gekickt. Tut mir leid, aber Parameterübergabe über Akkus, sämtliche offiziell deklarierten Übergabeparameter sind Makulatur/ohne Funktion, Überlauf des TIME_TCK notdürftig umgehen anstatt sauber herausrechnen - das sieht mir ziemlich unprofessionell aus. Von welchem Steinzeit-Lehrbuch lernt man so zu programmieren? Und muß man das auch noch Anfängern empfehlen?

Harald
 
Für ein hoch aufgelöstes Meßergebnis ist es eigentlich immer so, daß man bei vielen Impulsen/Torzeit besser die Impulse zählt (Frequenzmessung) und bei viel Zeit zwischen den Impulsen besser die Zeit misst (Periodendauermessung). Wenn man die Zeit zwischen den Impulsen nicht hochaufgelöst messen kann, dann kann man die Meßzeiträume ineinander verschachteln, dann hat man einerseits den Vorteil der längeren Meßzeit für höhere Auflösung, und andererseits eine schnellere Anzeige-Aktualisierung, z.B. in einem Ringpuffer (Array mit 12 Werten) alle 5 Sekunden den Zählerstand einspeichern und die Differenz von jetzt zu 60s vorher bilden - dann erhält man alle 5s einen neuen 60s-Meßwert.

Harald
 
Programmiert Ihr wirklich so in Euren SPS-Programmen? Dann wärt Ihr bei uns als Lieferant gekickt. Tut mir leid, aber Parameterübergabe über Akkus, sämtliche offiziell deklarierten Übergabeparameter sind Makulatur/ohne Funktion, Überlauf des TIME_TCK notdürftig umgehen anstatt sauber herausrechnen - das sieht mir ziemlich unprofessionell aus. Von welchem Steinzeit-Lehrbuch lernt man so zu programmieren? Und muß man das auch noch Anfängern empfehlen?

@PN/DP
Danke für den Tipp! So programmieren wir natürlich normalerweise nicht!
Die Übergabeparameter sind völliger quatsch! Das war der Code aus der original Anlage, wo ich das zum ersten mal gemacht habe.
Wie die da rein gekommen sind ist nicht mehr nachvollziehbar. An der korrekten Funktion ändert das aber nichts!

Auch Pramaterübergabe über AKKU gibt es nur in ein paar ganz wenigen Ausnahmefällen, einer davon ist die Zeitdifferenz der Systemzeit.
Das benötigt man meist nur im AWL-Code, deshalb gibt's ne spezielle Version dafür, die keine Übergabeparameter hat.
Sonst leg ich speziell Wert drauf, dass soweit möglich alles in KOP/FUP übersetzbar ist!

Der Fehler war mir anscheinend schon 2016 aufgefallen und in der Library bereits beseitigt, hier nochmal die korrekte Version der
Funktion
Code:
FUNCTION "m7b_ABS_DIFF_S7SysTime" : VOID
TITLE =ABS_DIFF_S7SysTime : Differenz zweier S7SystemZeiten 31Bit-Werte
//Da die S7 Systemzeit mittels SFC64 "TIME_TCK" nur 31 Bit 0..2147483647 ms
//aufweist gibt es einen Fehler, wenn Zeitdifferenzen über eine Timerüberlauf
//ermittelt werden. Um dies zu verhindern muss die Systemzeit auf 32Bit erweitert 
//werden.
//
//Der Aufruf dieses FC ist für AWL vorgesehn, als Unconditioned Call
//
//L  #SysTime1
//L  #SysTime2
//UC FC 256
//T  #TimeDiff
//
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 13/2013
//INTERNET: www.maagic7.de
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME       AENDERUNG
//--------------------------------------------------------------------------------
//15.01.2016   S.Maag     Fälschlich vorhandene IO-Paramter entfernt
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1

BEGIN
NETWORK
TITLE =die beiden Zeitwerte müssen bereits in den Akkus stehen

      SLD   1; // 1. Zeit in Akku 1 auf 32 Bit-Wert erweitern
      TAK   ; // Akkus tauschen
      SLD   1; // 2. Zeit auf 32 Bit-Wert erweitern
      -D    ; // Differenz bilden (=doppelte Differenz)
      SPPZ  pos; // If <0 THEN 
      NEGD  ; //             'Vorzeichen umkehren' 
pos:  SRD   1; // 32 Bit Korrektur wieder entferen TimeDiff nun in AKKU 1

END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es fehlt nochwas, die Auswahl des größeren Wertes SelectDINT>

Nochmal info zu den UC Aufrufen mit Parameterübergabe in den Akkus!
Das ist extrem effektiv und macht prinzipiell auch Sinn.
Wie ihr seht ist der Bautsein von 2003; das war usrsprünglich dazu gedacht, alte S5 und erste S7
Programme, von AWL Enthusiasten geschrieben, zu vereinfachen. Mit den UC SelectDINT> und SelectDINT<, bringt man
extrem viele unübersichtliche Sprünge aus solchen Programmen.
Die IEC Library Funktion FC36 "SEL" ist dafür nicht die richtige Wahl!

Code:
FUNCTION "m7a_SelectDINT>" : VOID
TITLE =grösseren Wert [DINT] in Akku 1
//AUTOR: Stefan Maag, Dipl.-Ing. (FH) Elektrotechnik 
//DATUM: 4/2003
//
//AENDERUNGSVERMERKE:
//--------------------------------------------------------------------------------
//DATUM        NAME            AENDERUNG
//--------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------
//
//HINWEISE:
AUTHOR : 'S.Maag'
FAMILY : Maagic7
VERSION : 0.1

BEGIN
NETWORK
TITLE =grösseren Wert [DINT] in Akku 1

      <D    ; // Akku 2 < Akku 1
      BEB   ; // grösserer Wert bereits in Akku 1
      TAK   ; // Sonst Akkus tauschen

END_FUNCTION
 
Überlauf des TIME_TCK notdürftig umgehen anstatt sauber herausrechnen - das sieht mir ziemlich unprofessionell aus. Von welchem Steinzeit-Lehrbuch lernt man so zu programmieren? Und muß man das auch noch Anfängern empfehlen?

Das mit dem Überlauf des SystemTimers einer S7 sauber rauszurechen geht nicht so einfach wie man sich das vorstellt!

1. Der Systemtimer hat nur 31 Bit (also nur positive Werte), das mach auch Sinn!
Leider kann man aber absoulte differenzen nur suaber rausrechnen, wenn es volle 32 Bit sind.
TimeDiff = ABS(newTime - oldTime)

2. damit es nicht ganz so einfach wird hatten ein paar S7-CPUs einen Systemzeitfehler in der Firmware. Da war einfach vergessen das 32er Bit zu entfernen.
Diese CPUs bringen also negative Zeiten beim Überlauf raus.
Mit dem grundsätzlichen rausschieben des 32er Bits in der Differenzberechnung ist dieser Fehler bei der Differenzeitberechnung egal
 
Ich bin ja eher ein schlichtes Gemüt. Ich lasse diese Berechnungen immer in einem Regel OB laufen. Also zum Beispiel den OB35 mit 100ms. In diesem zähle ich dann die Durchläufe zwischen zwei Impulsen. Der Rest ist dann wie oben beschrieben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also zum Beispiel den OB35 mit 100ms. In diesem zähle ich dann die Durchläufe zwischen zwei Impulsen.
Das ist dann wohl eher was für Grobmotoriker und laaange Impulse ;)
Warum ohne Not eine derartige Verschlechterung der Auflösung und Genauigkeit und Risiko Impulse zu verpassen?

Harald
 
Das ist dann wohl eher was für Grobmotoriker und laaange Impulse ;)
Warum ohne Not eine derartige Verschlechterung der Auflösung und Genauigkeit und Risiko Impulse zu verpassen?

Man muss natürlich seine Messtechnik und seine Anforderungen kennen. Wenn ich solche Berechnungen mache sind die Impulse meistens m³/h oder kW/h. Hier kommt vielleicht alle zwei Sekunden ein Impuls. Da reicht eine Auflösung von 100ms. Es hindert mich aber auch niemand, einen OB mit 10ms zu nehmen. Desweiteren, dient der Wert in der Regel nur zur Anzeige auf einem örtlichen Panel. In der Datenbank landen nur die gezählten Impulse und können dort auch beliebig ausgewertet werden.
 
Das mit dem Überlauf des SystemTimers einer S7 sauber rauszurechen geht nicht so einfach wie man sich das vorstellt!

1. Der Systemtimer hat nur 31 Bit (also nur positive Werte), das mach auch Sinn!
Leider kann man aber absoulte differenzen nur suaber rausrechnen, wenn es volle 32 Bit sind.
Quatsch. Das geht sogar noch einfacher als man sich vorstellt. Es ist genau dokumentiert wie sich der Wert bei Überlauf verhält, deshalb kann der Überlauf auch sehr leicht rausgerechnet werden.

(A) Für jeden Zählumfang (MaxZählWert + 1) gültige einfach verständliche Korrektur:
Wenn der aktuelle Wert (Wert2, EndeZeit) von TIME_TCK kleiner als der vorherige Wert (Wert1, AnfangsZeit) ist, dann gab es den Überlauf, dann wird die Differenz "ZeitDauer := EndeZeit - AnfangsZeit;" negativ, und dann muß man zur negativen Differenz einfach nur den Zählumfang (hier 2147483648 ) addieren (nennt man das Modulo-Addition? ;) )
Weil es als DINT den Wert +2147483648 nicht gibt, nehmen wir -2147483648 (Zweierkomplement läßt grüßen :cool: )
Code:
      L     #Zeit2         //jetzt oder EndeZeit
      L     #Zeit1         //vorher oder AnfangsZeit
      -D
      SPPZ  rslt
      +     L#-2147483648  //Zählumfang addieren
rslt: T     #ZeitDauer
Sowas ähnliches wie diese simple Lösung haben sich die Siemens-Beispiel-Programmierer wohl auch gedacht, allerdings mit falschen Werten korrigiert :roll:
z.B.:
Beispiel 1 Wie erfolgt in S7-SCL und in STEP 7 die Programmierung der numerischen Integration?
Der Korrekturwert 2147483.647 ist leicht falsch und kann außerdem gar nicht als Gleitpunktzahl dargestellt werden, was der SCL-Compiler ohne Warnung zu 2147484.0 rundet.

Beispiel 2 Wie kann die Zeit gemessen werden?
Hier wird der Überlauf fast korrekt korrigiert, der Korrekturwert 2147483647 ist allerdings leicht falsch (das fällt aber bei der Menge weiterer Stümpereien fast gar nicht mehr auf)

Beispiel 3 Wie berechnen Sie in STEP 7 V5.x die Laufzeit eines Endgerätes (z.B. Pumpe)?
Hier wird ebenfalls der falsche Korrekturwert verwendet. Auf 1ms kommt es anscheinend nicht drauf an... Erstaunlich an wievielen Stellen im Internet und hier im SPS-Forum man diese falsche Korrektur findet ... Testen die alle nicht und schreiben nur ungeprüft voneinander ab?


(B) Speziell für den Zählumfang des SFC64 TIME_TCK (0..2147483647) kann man auch einfach kurz und knackig von der Differenz das Vorzeichen entfernen (immer auf 0 setzen) und fertig :cool: (Erklärung dazu)
Code:
      L     #Zeit2         //jetzt oder EndeZeit
      L     #Zeit1         //vorher oder AnfangsZeit
      -D
      SLD   1
      SRD   1
      T     #ZeitDauer


2. damit es nicht ganz so einfach wird hatten ein paar S7-CPUs einen Systemzeitfehler in der Firmware. Da war einfach vergessen das 32er Bit zu entfernen.
Diese CPUs bringen also negative Zeiten beim Überlauf raus.
Mit dem grundsätzlichen rausschieben des 32er Bits in der Differenzberechnung ist dieser Fehler bei der Differenzeitberechnung egal
Von einem solchen Firmwarefehler habe ich noch nie gehört. Ich kenne nur den einen offiziellen Fehler, wo das L-Word und das H-Word nicht konsistent vom selben Zählerstand stammten und deshalb Sprünge im Wert vorkamen. Das Vorzeichen war dabei nicht betroffen, entfernen des Vorzeichens hilft deshalb da auch nicht. (Diesen Firmwarefehler kann man umgehen, indem man TIME_TCK zwei bis dreimal nacheinander abfragt bis zweimal der gleiche Wert geliefert wird.)
Warum erhalten Sie bei der S7-300 und C7 beim Lesen der Systemzeit mit der SFC 64 "TIME_TCK" nicht korrekte Werte?

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Beispiel für eine sehr genaue auf 1ms aufgelöste Zeitmessung mit Prozessalarm OB40 und SFC64 TIME_TCK (hier: Dauer eines 1-Signals, man kann so auch ganz einfach die Zeit nur zwischen steigenden Flanken messen = Impulsabstand)
Hier ein Beispiel für eine Zeitmessung im OB40 (Dauer eines 1-Signals) Dazu löst der E124.0 bei steigender und fallender Flanke einen Prozessalarm (den OB40) aus:
Code:
//OB40: Zeitmessung E124.0
      L     #OB40_IO_FLAG
      L     B#16#54                     //Eingangsbaugruppe PE...
      <>I
      SPB   ENDE

      L     #OB40_MDL_ADDR
      L     124                         //E 124
      <>I
      SPB   ENDE

      L     #OB40_POINT_ADDR
      UD    DW#16#1                     //E124.0 hat OB40 ausgelöst?
      SPZ   ENDE

//E124.0 hat OB40 ausgelöst ...
      L     PEW  124
      UW    W#16#100                    //2#00000001_00000000 E124.0
      U     <>0                         //... und ist jetzt 1 ?
      =     #FP                         //steigende Flanke

      CALL  "TIME_TCK"                  //SFC64 Systemzeit lesen
       RET_VAL:=#TIME_TCK

      L     #TIME_TCK                   //0 bis max. 2.147.483.647 ms
      U     #FP                         //steigende Flanke?
      SPBN  MDIF
      T     "Time_Start_ms"             //Anfangszeit merken (z.B. in einem MD... oder DBx.DBDy)
MDIF: L     "Time_Start_ms"
      -D
      SPPZ  MTIM                        //TIME_TCK Überlauf?
      +     L#-2147483648               //= DW#16#80000000
MTIM: T     "Time_ms"                   //Zeitdauer (z.B. MD... oder DBx.DBDy)

ENDE: SET

Harald
 
@PN/DP

Von einem solchen Firmwarefehler habe ich noch nie gehört. Ich kenne nur den einen offiziellen Fehler, wo das L-Word und das H-Word nicht konsistent vom selben Zählerstand stammten und deshalb Sprünge im Wert vorkamen. Das Vorzeichen war dabei nicht betroffen, entfernen des Vorzeichens hilft deshalb da auch nicht. (Diesen Firmwarefehler kann man umgehen, indem man TIME_TCK zwei bis dreimal nacheinander abfragt bis zweimal der gleiche Wert geliefert wird.)
Warum erhalten Sie bei der S7-300 und C7 beim Lesen der Systemzeit mit der SFC 64 "TIME_TCK" nicht korrekte Werte?

Das gleitet zwar jetzt vom eigentlichen Thema etwas ab, aber ich hab das mit dem Timer-Fehler bei Siemens nochmals nachgesehen.
Ich glaub fast, dass bei uns der Fehler nur falsch interpretiert wurde! Als Maßnahme wurde einfach kein Systemtimer mehr verwendet.
Ich hab das dann später so rausgerechnet, dass es egal ist, ob 31 oder 32 bit im Zähler stehen, damit gabs keine Probleme.
Dass lief dann aber alles auf neueren CPUs.
Den ganz alten CPUs trau ich eh nicht mehr weiter über den Weg als Merker =/S/R und Datenbausteine lesen schreiben.
Somit ist das dann nicht weiter aufgefallen, dass das bei diesen CPU's mit der 31Bit Korrektur auch nicht funktionieren würde.

Zitat von der Siemens Seite
All the CPUs of the S7-300 and all C7 devices are affected by this.

There is no update option for devices with firmware version V1.x.
  • For all versions of C7-621, 623, 624, 626, 633 and 634

  • For CPU 312IFM, CPU 313, CPU 314, CPU 314IFM, CPU 315, CPU 315F, CPU 315-2DP and CPU 316-2DP
The behavior does not occur in devices with firmware versions higher than V2.x.

Auffällig ist, dass es nur bei den CPUs mit der Firmware Version 1 auftritt. Diese haben meiner Erkenntnis nach
eine Hardwareversion 1. Und diese CPUs haben noch viel mehr Fehler. z.B. geht da der Temporär Stack überhaupt nicht,
Status im Step7 wird falsch angezeigt, VKE=1 wird unter bestimmten Umständen einfach nicht zugewiesen.

Ich hab noch einige Maschinen mit den CPU 316 mit HW1 im Einsatz. Auf denen läuft definitiv vieles nicht, was auf
aktuellen CPUs prima funktioniert! Da wirst du wahnsinnig!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
OB40 Zeitmessung mit SFC64 KOP/FUP

OK, ich habe den AWL-Code von #15 so angepasst, daß er in KOP und FUP angezeigt werden kann. Den Code in eine AWL-Quelle kopieren + speichern + übersetzen, dann kann der entstandene OB40 in KOP und FUP angezeigt werden.
Code:
ORGANIZATION_BLOCK OB40
TITLE = "Hardware Interrupt"
AUTHOR : PN_DP
VERSION : 0.1

VAR_TEMP
  OB40_EV_CLASS : BYTE ;  //Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
  OB40_STRT_INF : BYTE ;  //16#41 (OB 40 has started)
  OB40_PRIORITY : BYTE ;  //Priority of OB Execution
  OB40_OB_NUMBR : BYTE ;  //40 (Organization block 40, OB40)
  OB40_RESERVED_1 : BYTE ;  //Reserved for system
  OB40_IO_FLAG : BYTE ;  //16#54 (input module), 16#55 (output module)
  OB40_MDL_ADDR : WORD ;  //Base address of module initiating interrupt
  OB40_POINT_ADDR : DWORD ;  //Interrupt status of the module
  OB40_DATE_TIME : DATE_AND_TIME ;  //Date and time OB40 started
  temp_DW : DWORD ;
  temp_TIME : TIME ;
  FP : BOOL ;
END_VAR
BEGIN
NETWORK
TITLE =OB40: Zeitmessung E124.0 - Eingangsbaugruppe PE...?

      L     #OB40_IO_FLAG; 
      L     B#16#54; 
      <>I   ; 
      SPB   ENDE; 
NETWORK
TITLE =E124 ?

      L     #OB40_MDL_ADDR; 
      L     124; 
      <>I   ; 
      SPB   ENDE; 
NETWORK
TITLE =E124.0 hat OB40 ausgelöst?

      L     #OB40_POINT_ADDR; 
      L     DW#16#1; 
      UD    ; 
      T     #temp_DW; 
      NOP   0; 
NETWORK
TITLE =Nein, war anderer Eingang der Baugruppe

      U     ==0; 
      SPB   ENDE; 
NETWORK
TITLE =E124.0 hat OB40 ausgelöst, ist der jetzt 1 oder 0?
//steigende oder fallend Flanke?
      L     PEW  124; 
      L     W#16#100; 
      UW    ; 
      T     #temp_DW; 
      NOP   0; 
NETWORK
TITLE =

      U     <>0; 
      =     #FP; 
NETWORK
TITLE =Mit SFC64 Systemzeitgeber lesen

      CALL "TIME_TCK" (
       RET_VAL := #temp_TIME);
      NOP   0; 
NETWORK
TITLE =Anfangszeitpunkt merken (z.B. in einem MD... oder DBx.DBDy)
//bei steigender Flanke
//Time_Start_ms : MD40 : TIME
      U     #FP; 
      SPBNB _001; 
      L     #temp_TIME; 
      T     "Time_Start_ms"; 
_001: NOP   0; 
NETWORK
TITLE =Zeitdauer = Jetzt - Anfangszeit

      L     #temp_TIME; 
      L     "Time_Start_ms"; 
      -D    ; 
      T     #temp_TIME; 
      NOP   0; 
NETWORK
TITLE =TIME_TCK Überlauf korrigieren durch Löschen Bit 31
//und Zeitdauer speichern (z.B. in einem MD... oder DBx.DBDy)
//Time_ms : MD44 : TIME
      L     #temp_TIME; 
      L     DW#16#7FFFFFFF; 
      UD    ; 
      T     "Time_ms"; 
      NOP   0; 
NETWORK
TITLE =(irgendwas, Sprungmarke darf nicht alleine stehen)

ENDE: U     #FP; 
      =     #FP; 
END_ORGANIZATION_BLOCK

PS: erst hatte ich gar keine Lust zur KOP/FUP-Variante, weil das früher wegen der Typprüfung in KOP/FUP nur sehr umständlich mit vielen zusätzlichen MOVE möglich gewesen wäre. Seit aber Siemens in Step7 V5.5 die KOP/FUP-Typprüfung zwangs-abgeschafft hat, geht das auch in KOP/FUP ziemlich übersichtlich. Man könnte nun auch noch die Netzwerke 3+4 und 5+6 zusammenfassen für "kürzeres" KOP/FUP, doch dann wird der AWL-Code unschöner und der erzeugte Baustein 10% größer.

PPS: falls jemand den Code so in TIA verwenden will und TIA meckert irgendwo, dann ist mir das egal - ich werde das nicht nochmal umschreiben. Wer solche Zeitmessung in TIA machen will, sollte SCL verwenden. (Vielleicht findet sich ja jemand, der die paar Anweisungen in SCL umsetzt und für alle hier postet?)

Harald
 

Anhänge

  • OB40_Zeitmessung_mit_SFC64.awl.txt
    2,4 KB · Aufrufe: 24
Zurück
Oben