Step 7 FM 450-1, Counter, Frequenzmessung, Drehzahlmessung, Geschwindigkeitsmessung

rolfed

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

in unserem Unternehmen haben wir eine Förderbahn bei der wir die Geschwindigkeit mithilfe einer Walze messen.
Auf der Walze ist ein Inkrementalgeber mit 1000 Impulse / Umdrehung befestigt. Die Impulse werden auf die Zählerkarte FM 450-1 übergeben.
Bei der Messung der Geschwindigkeit zwischen 0 m/min und 70 m/min haben wir einer Abweichung von +-2%. Schlupf können wir ausschließen.

Meine Vermutung ist, dass es an einer zu großen Zykluszeit liegt. Das Programm ist ziemlich umfangreich und hat eine Zykluszeit von 61ms.
Falls jemand noch eine andere Vermutung oder eine andere Lösung für die Geschwindigkeitsmessung hat und mich aufklären kann, wäre ich sehr dankbar.

Datei von filehorst.de laden

Hier ist ein Ausschnitt aus dem Programm
Code:
TYPE UDT 1




  STRUCT     
   AR1_BUFFER : DWORD ;    // AR1 buffer (FC internal use)
   FP : BYTE ;    // flag byte (FC internal use)
   RESERVED : BYTE ;    // reserved for FC use
   MOD_ADR : WORD ;    // module adress (write user)
   CH_ADR : DWORD ;    // channel adress (write user)
   U_D_LGTH : BYTE ;    // user data length (write user)
   A_BYTE_0 : BYTE ;    // reserved
   LOAD_VAL : DINT ;    // new load value (write user)
   CMP_V1 : DINT ;    // new comparator value 1 (write user)
   CMP_V2 : DINT ;    // new comparator value 2 (write user)
   A_BIT0_0 : BOOL ;    // reserved
   TFB : BOOL ;    // test free (internal use)
   A_BIT0_2 : BOOL ;    // reserved
   A_BIT0_3 : BOOL ;    // reserved
   A_BIT0_4 : BOOL ;    // reserved
   A_BIT0_5 : BOOL ;    // reserved
   A_BIT0_6 : BOOL ;    // reserved
   A_BIT0_7 : BOOL ;    // reserved
   ENSET_UP : BOOL ;    // enable set in direction up (=forward) (write user)
   ENSET_DN : BOOL ;    // enable set in direction down (= backward) (write user)
   A_BIT1_2 : BOOL ;    // reserved
   A_BIT1_3 : BOOL ;    // reserved
   A_BIT1_4 : BOOL ;    // reserved
   A_BIT1_5 : BOOL ;    // reserved
   A_BIT1_6 : BOOL ;    // reserved
   A_BIT1_7 : BOOL ;    // reserved
   CTRL_DQ0 : BOOL ;    // control digital output DQ0 (write user)
   CTRL_DQ1 : BOOL ;    // control digital output DQ1 (write user)
   A_BIT2_2 : BOOL ;    // reserved
   A_BIT2_3 : BOOL ;    // reserved
   A_BIT2_4 : BOOL ;    // reserved
   A_BIT2_5 : BOOL ;    // reserved
   A_BIT2_6 : BOOL ;    // reserved
   A_BIT2_7 : BOOL ;    // reserved
   A_BIT3_0 : BOOL ;    // reserved
   A_BIT3_1 : BOOL ;    // reserved
   A_BIT3_2 : BOOL ;    // reserved
   A_BIT3_3 : BOOL ;    // reserved
   A_BIT3_4 : BOOL ;    // reserved
   A_BIT3_5 : BOOL ;    // reserved
   A_BIT3_6 : BOOL ;    // reserved
   A_BIT3_7 : BOOL ;    // reserved
   LATCH_LOAD : DINT ;    // actual latch or load value (read user)
   ACT_CNTV : DINT ;    // actual counter value (read user)
   DA_ERR_W : WORD ;    // data error word (read user)
   OT_ERR_B : BYTE ;    // operator error byte (read user)
   E_BIT0_0 : BOOL ;    // reserved
   STS_TFB : BOOL ;    // status test free bit (internal use)
   E_BIT0_2 : BOOL ;    // reserved    
   E_BIT0_3 : BOOL ;    // reserved
   DATA_ERR : BOOL ;    // data error bit (read user)
   E_BIT0_5 : BOOL ;    // reserved
   E_BIT0_6 : BOOL ;    // reserved
   PARA : BOOL ;    // module parametrized (read user)
   E_BYTE_0 : BYTE ;    // reserved
   STS_RUN : BOOL ;    // status counter is running (read user)
   STS_DIR : BOOL ;    // status of the counter direction bit (read user)
   STS_ZERO : BOOL ;    // status of the counter zero crossing bit (read user)
   STS_OFLW : BOOL ;    // status counter passed the overflow value (read user)
   STS_UFLW : BOOL ;    // status counter passed the underflow value (read user)
   STS_SYNC : BOOL ;    // status counter is synchronized (read user)
   STS_GATE : BOOL ;    // status of the internal gate (read user)
   STS_SW_G : BOOL ;    // status of the software gate (read user)
   STS_SET : BOOL ;    // status digital input SET (read user)
   E_BIT2_1 : BOOL ;    // reserved
   STS_STA : BOOL ;    // status of the digital input start (read user)
   STS_STP : BOOL ;    // status of the digital input stop (read user)
   STS_CMP1 : BOOL ;    // status of the comparator output 1 (read user)
   STS_CMP2 : BOOL ;    // status of the comparator output 2 (read user)
   E_BIT2_6 : BOOL ;    // reserved
   E_BIT2_7 : BOOL ;    // reserved
   E_BIT3_0 : BOOL ;    // reserved
   E_BIT3_1 : BOOL ;    // reserved
   E_BIT3_2 : BOOL ;    // reserved
   E_BIT3_3 : BOOL ;    // reserved
   E_BIT3_4 : BOOL ;    // reserved
   E_BIT3_5 : BOOL ;    // reserved
   E_BIT3_6 : BOOL ;    // reserved
   E_BIT3_7 : BOOL ;    // reserved
   ACT_CMP1 : DINT ;    // actual comparator value 1 (read user)
   ACT_CMP2 : DINT ;    // actual comparator value 2 (read user)
   MDL_DEFECT : BOOL ;    // module defective 
   INT_FAULT : BOOL ;    // internal fault
   EXT_FAULT : BOOL ;    // external fault
   PNT_INFO : BOOL ;    // point information
   EXT_VOLTAGE : BOOL ;    // external voltage low
   FLD_CONNCTR : BOOL ;    // field wiring connector missing
   NO_CONFIG : BOOL ;    // module has no configuration data
   CONFIG_ERR : BOOL ;    // module has configuration error
   MDL_TYPE : BYTE ;    // Type of module
   SUB_MDL_ERR : BOOL ;    // Sub-Module is missing or has error
   COMM_FAULT : BOOL ;    // communication fault
   MDL_STOP : BOOL ;    // module is stopped
   WTCH_DOG_FLT : BOOL ;    // watch dog timer stopped module
   INT_PS_FLT : BOOL ;    // internal power supply fault
   PRIM_BATT_FLT : BOOL ;    // primary battery is in fault
   BCKUP_BATT_FLT : BOOL ;    // backup battary is in fault
   RESERVED_2 : BOOL ;    // reserved for system
   RACK_FLT : BOOL ;    // rack fault, only for bus interface module
   PROC_FLT : BOOL ;    // processor fault
   EPROM_FLT : BOOL ;    // EPROM fault
   RAM_FLT : BOOL ;    // RAM fault
   ADU_FLT : BOOL ;    // ADU fault
   FUSE_FLT : BOOL ;    // fuse fault
   HW_INTR_FLT : BOOL ;    // hardware interrupt input in fault
   RESERVED_3 : BOOL ;    // reserved for system
   CH_TYPE : BYTE ;    // channel type
   LGTH_DIA : BYTE ;    // length of diagnostics data per channel
   CH_NO : BYTE ;    // channel number (numero)
   GRP_ERR1 : BOOL ;    // group error channel 1
   GRP_ERR2 : BOOL ;    // group error channel 2
   D_BIT7_2 : BOOL ;    // DS1 byte 7 bit 2
   D_BIT7_3 : BOOL ;    // DS1 byte 7 bit 3
   D_BIT7_4 : BOOL ;    // DS1 byte 7 bit 4
   D_BIT7_5 : BOOL ;    // DS1 byte 7 bit 5
   D_BIT7_6 : BOOL ;    // DS1 byte 7 bit 6
   D_BIT7_7 : BOOL ;    // DS1 byte 7 bit 7
   CH1_SIGA : BOOL ;    // channel 1, signal A malfunction
   CH1_SIGB : BOOL ;    // channel 1, signal B malfunction
   CH1_SIGZ : BOOL ;    // channel 1, signal Zero mark malfunction
   CH1_BETW : BOOL ;    // channel 1, malfunction between channels
   CH1_5V2 : BOOL ;    // channel 1, malfunction of encoder supply voltage 5.2V
   D_BIT8_5 : BOOL ;    // DS1 byte 8 bit 5
   D_BIT8_6 : BOOL ;    // DS1 byte 8 bit 6
   D_BIT8_7 : BOOL ;    // DS1 byte 8 bit 7
   D_BYTE9 : BYTE ;    // DS1 byte 9
   CH2_SIGA : BOOL ;    // channel 2, signal A malfunction
   CH2_SIGB : BOOL ;    // channel 2, signal B malfunction
   CH2_SIGZ : BOOL ;    // channel 2, signal Zero mark malfunction
   CH2_BETW : BOOL ;    // channel 2, malfunction between channels
   CH2_5V2 : BOOL ;    // channel 2, malfunction of encoder supply voltage 5.2V
   D_BIT10_5 : BOOL ;    // DS1 byte 10 bit 5
   D_BIT10_6 : BOOL ;    // DS1 byte 10 bit 6
   D_BIT10_7 : BOOL ;    // DS1 byte 10 bit 7
   D_BYTE11 : BYTE ;    // DS1 byte 11
   D_BYTE12 : BYTE ;    // DS1 byte 12
   D_BYTE13 : BYTE ;    // DS1 byte 13
   D_BYTE14 : BYTE ;    // DS1 byte 14
   D_BYTE15 : BYTE ;    // DS1 byte 15
  END_STRUCT ;    
END_TYPE


DATA_BLOCK DB 455
TITLE =
VERSION : 0.1


 UDT 1
BEGIN
   AR1_BUFFER := DW#16#0; 
   FP := B#16#0; 
   RESERVED := B#16#0; 
   MOD_ADR := W#16#0; 
   CH_ADR := DW#16#0; 
   U_D_LGTH := B#16#0; 
   A_BYTE_0 := B#16#0; 
   LOAD_VAL := L#0; 
   CMP_V1 := L#0; 
   CMP_V2 := L#0; 
   A_BIT0_0 := FALSE; 
   TFB := FALSE; 
   A_BIT0_2 := FALSE; 
   A_BIT0_3 := FALSE; 
   A_BIT0_4 := FALSE; 
   A_BIT0_5 := FALSE; 
   A_BIT0_6 := FALSE; 
   A_BIT0_7 := FALSE; 
   ENSET_UP := FALSE; 
   ENSET_DN := FALSE; 
   A_BIT1_2 := FALSE; 
   A_BIT1_3 := FALSE; 
   A_BIT1_4 := FALSE; 
   A_BIT1_5 := FALSE; 
   A_BIT1_6 := FALSE; 
   A_BIT1_7 := FALSE; 
   CTRL_DQ0 := FALSE; 
   CTRL_DQ1 := FALSE; 
   A_BIT2_2 := FALSE; 
   A_BIT2_3 := FALSE; 
   A_BIT2_4 := FALSE; 
   A_BIT2_5 := FALSE; 
   A_BIT2_6 := FALSE; 
   A_BIT2_7 := FALSE; 
   A_BIT3_0 := FALSE; 
   A_BIT3_1 := FALSE; 
   A_BIT3_2 := FALSE; 
   A_BIT3_3 := FALSE; 
   A_BIT3_4 := FALSE; 
   A_BIT3_5 := FALSE; 
   A_BIT3_6 := FALSE; 
   A_BIT3_7 := FALSE; 
   LATCH_LOAD := L#0; 
   ACT_CNTV := L#0; 
   DA_ERR_W := W#16#0; 
   OT_ERR_B := B#16#0; 
   E_BIT0_0 := FALSE; 
   STS_TFB := FALSE; 
   E_BIT0_2 := FALSE; 
   E_BIT0_3 := FALSE; 
   DATA_ERR := FALSE; 
   E_BIT0_5 := FALSE; 
   E_BIT0_6 := FALSE; 
   PARA := FALSE; 
   E_BYTE_0 := B#16#0; 
   STS_RUN := FALSE; 
   STS_DIR := FALSE; 
   STS_ZERO := FALSE; 
   STS_OFLW := FALSE; 
   STS_UFLW := FALSE; 
   STS_SYNC := FALSE; 
   STS_GATE := FALSE; 
   STS_SW_G := FALSE; 
   STS_SET := FALSE; 
   E_BIT2_1 := FALSE; 
   STS_STA := FALSE; 
   STS_STP := FALSE; 
   STS_CMP1 := FALSE; 
   STS_CMP2 := FALSE; 
   E_BIT2_6 := FALSE; 
   E_BIT2_7 := FALSE; 
   E_BIT3_0 := FALSE; 
   E_BIT3_1 := FALSE; 
   E_BIT3_2 := FALSE; 
   E_BIT3_3 := FALSE; 
   E_BIT3_4 := FALSE; 
   E_BIT3_5 := FALSE; 
   E_BIT3_6 := FALSE; 
   E_BIT3_7 := FALSE; 
   ACT_CMP1 := L#0; 
   ACT_CMP2 := L#0; 
   MDL_DEFECT := FALSE; 
   INT_FAULT := FALSE; 
   EXT_FAULT := FALSE; 
   PNT_INFO := FALSE; 
   EXT_VOLTAGE := FALSE; 
   FLD_CONNCTR := FALSE; 
   NO_CONFIG := FALSE; 
   CONFIG_ERR := FALSE; 
   MDL_TYPE := B#16#0; 
   SUB_MDL_ERR := FALSE; 
   COMM_FAULT := FALSE; 
   MDL_STOP := FALSE; 
   WTCH_DOG_FLT := FALSE; 
   INT_PS_FLT := FALSE; 
   PRIM_BATT_FLT := FALSE; 
   BCKUP_BATT_FLT := FALSE; 
   RESERVED_2 := FALSE; 
   RACK_FLT := FALSE; 
   PROC_FLT := FALSE; 
   EPROM_FLT := FALSE; 
   RAM_FLT := FALSE; 
   ADU_FLT := FALSE; 
   FUSE_FLT := FALSE; 
   HW_INTR_FLT := FALSE; 
   RESERVED_3 := FALSE; 
   CH_TYPE := B#16#0; 
   LGTH_DIA := B#16#0; 
   CH_NO := B#16#0; 
   GRP_ERR1 := FALSE; 
   GRP_ERR2 := FALSE; 
   D_BIT7_2 := FALSE; 
   D_BIT7_3 := FALSE; 
   D_BIT7_4 := FALSE; 
   D_BIT7_5 := FALSE; 
   D_BIT7_6 := FALSE; 
   D_BIT7_7 := FALSE; 
   CH1_SIGA := FALSE; 
   CH1_SIGB := FALSE; 
   CH1_SIGZ := FALSE; 
   CH1_BETW := FALSE; 
   CH1_5V2 := FALSE; 
   D_BIT8_5 := FALSE; 
   D_BIT8_6 := FALSE; 
   D_BIT8_7 := FALSE; 
   D_BYTE9 := B#16#0; 
   CH2_SIGA := FALSE; 
   CH2_SIGB := FALSE; 
   CH2_SIGZ := FALSE; 
   CH2_BETW := FALSE; 
   CH2_5V2 := FALSE; 
   D_BIT10_5 := FALSE; 
   D_BIT10_6 := FALSE; 
   D_BIT10_7 := FALSE; 
   D_BYTE11 := B#16#0; 
   D_BYTE12 := B#16#0; 
   D_BYTE13 := B#16#0; 
   D_BYTE14 := B#16#0; 
   D_BYTE15 := B#16#0; 
END_DATA_BLOCK


DATA_BLOCK DB 456
TITLE =
VERSION : 0.1


 UDT 1
BEGIN
   AR1_BUFFER := DW#16#0; 
   FP := B#16#0; 
   RESERVED := B#16#0; 
   MOD_ADR := W#16#0; 
   CH_ADR := DW#16#0; 
   U_D_LGTH := B#16#0; 
   A_BYTE_0 := B#16#0; 
   LOAD_VAL := L#0; 
   CMP_V1 := L#0; 
   CMP_V2 := L#0; 
   A_BIT0_0 := FALSE; 
   TFB := FALSE; 
   A_BIT0_2 := FALSE; 
   A_BIT0_3 := FALSE; 
   A_BIT0_4 := FALSE; 
   A_BIT0_5 := FALSE; 
   A_BIT0_6 := FALSE; 
   A_BIT0_7 := FALSE; 
   ENSET_UP := FALSE; 
   ENSET_DN := FALSE; 
   A_BIT1_2 := FALSE; 
   A_BIT1_3 := FALSE; 
   A_BIT1_4 := FALSE; 
   A_BIT1_5 := FALSE; 
   A_BIT1_6 := FALSE; 
   A_BIT1_7 := FALSE; 
   CTRL_DQ0 := FALSE; 
   CTRL_DQ1 := FALSE; 
   A_BIT2_2 := FALSE; 
   A_BIT2_3 := FALSE; 
   A_BIT2_4 := FALSE; 
   A_BIT2_5 := FALSE; 
   A_BIT2_6 := FALSE; 
   A_BIT2_7 := FALSE; 
   A_BIT3_0 := FALSE; 
   A_BIT3_1 := FALSE; 
   A_BIT3_2 := FALSE; 
   A_BIT3_3 := FALSE; 
   A_BIT3_4 := FALSE; 
   A_BIT3_5 := FALSE; 
   A_BIT3_6 := FALSE; 
   A_BIT3_7 := FALSE; 
   LATCH_LOAD := L#0; 
   ACT_CNTV := L#0; 
   DA_ERR_W := W#16#0; 
   OT_ERR_B := B#16#0; 
   E_BIT0_0 := FALSE; 
   STS_TFB := FALSE; 
   E_BIT0_2 := FALSE; 
   E_BIT0_3 := FALSE; 
   DATA_ERR := FALSE; 
   E_BIT0_5 := FALSE; 
   E_BIT0_6 := FALSE; 
   PARA := FALSE; 
   E_BYTE_0 := B#16#0; 
   STS_RUN := FALSE; 
   STS_DIR := FALSE; 
   STS_ZERO := FALSE; 
   STS_OFLW := FALSE; 
   STS_UFLW := FALSE; 
   STS_SYNC := FALSE; 
   STS_GATE := FALSE; 
   STS_SW_G := FALSE; 
   STS_SET := FALSE; 
   E_BIT2_1 := FALSE; 
   STS_STA := FALSE; 
   STS_STP := FALSE; 
   STS_CMP1 := FALSE; 
   STS_CMP2 := FALSE; 
   E_BIT2_6 := FALSE; 
   E_BIT2_7 := FALSE; 
   E_BIT3_0 := FALSE; 
   E_BIT3_1 := FALSE; 
   E_BIT3_2 := FALSE; 
   E_BIT3_3 := FALSE; 
   E_BIT3_4 := FALSE; 
   E_BIT3_5 := FALSE; 
   E_BIT3_6 := FALSE; 
   E_BIT3_7 := FALSE; 
   ACT_CMP1 := L#0; 
   ACT_CMP2 := L#0; 
   MDL_DEFECT := FALSE; 
   INT_FAULT := FALSE; 
   EXT_FAULT := FALSE; 
   PNT_INFO := FALSE; 
   EXT_VOLTAGE := FALSE; 
   FLD_CONNCTR := FALSE; 
   NO_CONFIG := FALSE; 
   CONFIG_ERR := FALSE; 
   MDL_TYPE := B#16#0; 
   SUB_MDL_ERR := FALSE; 
   COMM_FAULT := FALSE; 
   MDL_STOP := FALSE; 
   WTCH_DOG_FLT := FALSE; 
   INT_PS_FLT := FALSE; 
   PRIM_BATT_FLT := FALSE; 
   BCKUP_BATT_FLT := FALSE; 
   RESERVED_2 := FALSE; 
   RACK_FLT := FALSE; 
   PROC_FLT := FALSE; 
   EPROM_FLT := FALSE; 
   RAM_FLT := FALSE; 
   ADU_FLT := FALSE; 
   FUSE_FLT := FALSE; 
   HW_INTR_FLT := FALSE; 
   RESERVED_3 := FALSE; 
   CH_TYPE := B#16#0; 
   LGTH_DIA := B#16#0; 
   CH_NO := B#16#0; 
   GRP_ERR1 := FALSE; 
   GRP_ERR2 := FALSE; 
   D_BIT7_2 := FALSE; 
   D_BIT7_3 := FALSE; 
   D_BIT7_4 := FALSE; 
   D_BIT7_5 := FALSE; 
   D_BIT7_6 := FALSE; 
   D_BIT7_7 := FALSE; 
   CH1_SIGA := FALSE; 
   CH1_SIGB := FALSE; 
   CH1_SIGZ := FALSE; 
   CH1_BETW := FALSE; 
   CH1_5V2 := FALSE; 
   D_BIT8_5 := FALSE; 
   D_BIT8_6 := FALSE; 
   D_BIT8_7 := FALSE; 
   D_BYTE9 := B#16#0; 
   CH2_SIGA := FALSE; 
   CH2_SIGB := FALSE; 
   CH2_SIGZ := FALSE; 
   CH2_BETW := FALSE; 
   CH2_5V2 := FALSE; 
   D_BIT10_5 := FALSE; 
   D_BIT10_6 := FALSE; 
   D_BIT10_7 := FALSE; 
   D_BYTE11 := B#16#0; 
   D_BYTE12 := B#16#0; 
   D_BYTE13 := B#16#0; 
   D_BYTE14 := B#16#0; 
   D_BYTE15 := B#16#0; 
END_DATA_BLOCK


FUNCTION FC 450 : VOID
TITLE =COUNTER MODULE CONTROL 
AUTHOR : FM
FAMILY : FM_CNT_1
NAME : CNT_CTRL
VERSION : 3.0




VAR_INPUT
  DB_NO : INT ;    // module datablock number
  SW_GATE : BOOL ;    // software gate
  GATE_STP : BOOL ;    // gate stop
  OT_ERR_A : BOOL ;    // operator error acknowledge
END_VAR
VAR_OUTPUT
  OT_ERR : BOOL ;    // operator error
END_VAR
VAR_IN_OUT
  L_DIRECT : BOOL ;    // load direct
  L_PREPAR : BOOL ;    // load prepared
  T_CMP_V1 : BOOL ;    // transfer comparator value 1
  T_CMP_V2 : BOOL ;    // transfer comparator value 2
  RES_SYNC : BOOL ;    // reset synchronisation bit
  RES_ZERO : BOOL ;    // reset zero crossing bit
END_VAR
VAR_TEMP
  dbnr : WORD ;    // DB-Nr. als Lokaldatum
  rett_dbnr : WORD ;    // Nummer des DB, der beim Aufruf des FC gerade offen war (von AWL benutzt)
END_VAR
BEGIN
NETWORK
TITLE =
// Zuordnung Parameter <==> DB Bit
//
// OT_ERR_A  =  A_BIT0_3          Bedienfehler quittieren
// NEUSTQ    =  A_BIT0_6          Neustart quittieren
// GATE_STP  =  A_BIT1_2          Torstopp
// SW_GATE   =  A_BIT1_3          SW-Tor Start/Stopp
// L_DIRECT  =  A_BIT3_0          Zähler mit Loadwert laden
// L_PREPAR  =  A_BIT3_1          Loadwert ins Loadregister
// T_CMP_V1  =  A_BIT3_2          Vergleichswert 2 übernehmen
// T_CMP_V2  =  A_BIT3_3          Vergleichswert 1 übernehmen
// RES_SYNC  =  A_BIT3_4          Synchronisationsbit rücksetzen
// RES_ZERO  =  A_BIT3_5          Nulldurchgangsbit rücksetzen
// OT_ERR    =  E_BIT0_3          Bedienfehler      
// FM-NEUSTQ =  E_BIT0_5          FM-Neustart quittiert
// FM-NEUST  =  E_BIT0_6          FM-Neustart
//              E_BIT3_0          Loadwert in Zähler übernommen
//              E_BIT3_1          Loadwert ins Loadregister übernommen
//              E_BIT3_2          Vergleichswert 1 übernommen
//              E_BIT3_3          Vergleichswert 2 übernommen
//              E_BIT3_4          Synchronisationsbit gelöscht
//              E_BIT3_5          Nulldurchgangsbit gelöscht
//
//
// ************************************************************************
// Rueckmeldungen in der Instanz durch Lesen von der FM aktualisieren
// ************************************************************************
      SET   ; 
      SAVE  ; // BIE fest auf 1 !!!


      L     #DB_NO; // Übergebene Nummer in dbnr zwischenspeichern
      T     #dbnr; 
      L     DBNO; // Lade Nummer Global-DB in AKKU 1
      T     #rett_dbnr; // und rette sie in rett_dbnr


      AUF   DB [#dbnr]; // öffne Kanal-DB mit übergebener Nummer


      TAR1  DBD    0; // Adressregister 1 retten


      L     DBD    8; // (CH_ADR) Kanalanfangsadresse 
      LAR1  ; // in das Adressregister 1


      L     PED [AR1,P#8.0]; // Datenfehler, Bedienfehler und Koordinierungsbyte
      T     DBD   38; 


      U     DBX   41.6; // FM-NEUST   (E_BIT0_6)
      UN    DBX   41.5; // FM-NEUSTQ  (E_BIT0_5)
      =     DBX   26.6; // NEUSTQ     (A_BIT0_6)
      SPBN  OK; // Kein Neustart


      L     DW#16#40000000; // Koordinierungsbyte schreiben
      T     PAD [AR1,P#12.0]; // und Steuerbits löschen
      L     B#16#0; 
      T     DBB    4; // (FP) Flankenmerker löschen
      SPA   END; // und Baustein verlassen




OK:   L     PED [AR1,P#0.0]; // (ACT_LOAD) Loadwert in die Instanz
      T     DBD   30; 
      L     PED [AR1,P#4.0]; // (ACT_CNTV) Zaehlstand in die Instanz
      T     DBD   34; 
      L     PED [AR1,P#12.0]; // Reserve und Statusbytes
      T     DBD   42; 


      L     DBB   12; // (U_D_LGTH) 16 : S7-300, 32 : S7-400
      L     B#16#20; 
      <I    ; // Wenn kleiner : Keine Vergleichswerte lesen
      SPB   L1; 


      L     PED [AR1,P#16.0]; // Aktueller Vergleichswert 1
      T     DBD   46; // (ACT_CMP1)      
      L     PED [AR1,P#20.0]; // Aktueller Vergleichswert 2
      T     DBD   50; // (ACT_CMP2)


//      ***********************************************************************
//      FB-Steuer-Parameter Bitweise in den Instanz-Datenbaustein übertragen
//      ***********************************************************************




// Zähler mit Loadwert laden


L1:   U     #L_DIRECT; // FB-Parameter einlesen
      FP    DBX    4.0; // 1. Anstoß
      S     DBX   29.0; // (A_BIT3_0) Steuernsignal setzen


      U     DBX   45.0; // (E_BIT3_0) Rückmeldung erhalten
      R     DBX   29.0; // (A_BIT3_0) Steuersignal löschen


      UN    DBX   45.0; // (E_BIT3_0) Bearbeitung fertig      
      UN    DBX   29.0; // (A_BIT3_0)
      R     #L_DIRECT; // FB-Parameter löschen
      R     DBX    4.0; // Merker 1. Anstoß löschen


// Loadwert ins Loadregister


      U     #L_PREPAR; // FB-Parameter einlesen
      FP    DBX    4.1; // 1. Anstoß
      S     DBX   29.1; // (A_BIT3_1) Steuernsignal setzen


      U     DBX   45.1; // (E_BIT3_1) Rückmeldung erhalten
      R     DBX   29.1; // (A_BIT3_1) Steuersignal löschen


      UN    DBX   45.1; // (E_BIT3_1) Bearbeitung fertig      
      UN    DBX   29.1; // (A_BIT3_1)
      R     #L_PREPAR; // FB-Parameter löschen
      R     DBX    4.1; // Merker 1. Anstoß löschen


// Vergleichswert 1 übernehmen


      U     #T_CMP_V1; // FB-Parameter einlesen
      FP    DBX    4.2; // 1. Anstoß
      S     DBX   29.2; // (A_BIT3_2) Steuernsignal setzen


      U     DBX   45.2; // (E_BIT3_2) Rückmeldung erhalten
      R     DBX   29.2; // (A_BIT3_2) Steuersignal löschen


      UN    DBX   45.2; // (E_BIT3_2) Bearbeitung fertig      
      UN    DBX   29.2; // (A_BIT3_2)
      R     #T_CMP_V1; // FB-Parameter löschen
      R     DBX    4.2; // Merker 1. Anstoß löschen


// Vergleichswert 2 übernehmen


      U     #T_CMP_V2; // FB-Parameter einlesen
      FP    DBX    4.3; // 1. Anstoß
      S     DBX   29.3; // (A_BIT3_3) Steuernsignal setzen


      U     DBX   45.3; // (E_BIT3_3) Rückmeldung erhalten
      R     DBX   29.3; // (A_BIT3_3) Steuersignal löschen


      UN    DBX   45.3; // (E_BIT3_3) Bearbeitung fertig      
      UN    DBX   29.3; // (A_BIT3_3)
      R     #T_CMP_V2; // FB-Parameter löschen
      R     DBX    4.3; // Merker 1. Anstoß löschen


// Synchronisationsbit rücksetzen


      U     #RES_SYNC; // FB-Parameter einlesen
      FP    DBX    4.4; // 1. Anstoß
      S     DBX   29.4; // (A_BIT3_4) Steuernsignal setzen


      U     DBX   45.4; // (E_BIT3_4) Rückmeldung erhalten
      R     DBX   29.4; // (A_BIT3_4) Steuersignal löschen


      UN    DBX   45.4; // (E_BIT3_4) Bearbeitung fertig      
      UN    DBX   29.4; // (A_BIT3_4)
      R     #RES_SYNC; // FB-Parameter löschen
      R     DBX    4.4; // Merker 1. Anstoß löschen




// Nulldurchgangsbit rücksetzen


      U     #RES_ZERO; // FB-Parameter einlesen
      FP    DBX    4.5; // 1. Anstoß
      S     DBX   29.5; // (A_BIT3_5) Steuernsignal setzen


      U     DBX   45.5; // (E_BIT3_5) Rückmeldung erhalten
      R     DBX   29.5; // (A_BIT3_5) Steuersignal löschen


      UN    DBX   45.5; // (E_BIT3_5) Bearbeitung fertig      
      UN    DBX   29.5; // (A_BIT3_5)
      R     #RES_ZERO; // FB-Parameter löschen
      R     DBX    4.5; // Merker 1. Anstoß löschen




// Tor Steuerung


      U     #GATE_STP; // Torstopp
      =     DBX   27.2; // (A_BIT1_2) Steuern Zähler 


      U     #SW_GATE; // SW-Tor Start/Stopp
      =     DBX   27.3; // (A_BIT1_3) Steuern Zähler 


// Bedienfehler Bearbeitung


      U     DBX   41.3; // (E_BIT0_3) Status Bedienfehler
      =     #OT_ERR; // am FB-Parameter mitteilen


      U     #OT_ERR_A; // Fehler quittieren
      =     DBX   26.3; // (A_BIT0_3)




// ************************************************************************
// Der Load- und die Vergleichswerte zur FM transferieren 
// ************************************************************************




      L     DBD   14; // (LOAD_VAL) Loadwert in Steuerschnittstelle
      T     PAD [AR1,P#0.0]; 
      L     DBD   18; // (CMP_V1) Vergleichswert 1 in Steuerschnittstelle
      T     PAD [AR1,P#4.0]; 
      L     DBD   22; // (CMP_V2) Vergleichswert 2 in Steuerschnittstelle
      T     PAD [AR1,P#8.0]; 




// ************************************************************************
// Das Koordinierungs- und die Steuerbytes zur FM transferieren
// ************************************************************************


      L     DBD   26; // Doppelwort mit den Koord.- und Steuerbytes
      T     PAD [AR1,P#12.0]; 






END:  LAR1  DBD    0; // Adressregister 1 laden


      AUF   DB [#rett_dbnr]; // alten vor Aufruf geöffneten DB wieder öffnen


      BE    ; 


END_FUNCTION


FUNCTION FC 1 : VOID
TITLE =Allgemeine Funktionen
AUTHOR : EMPGK
FAMILY : ALLGFKT
NAME : AUFALLG
VERSION : 0.1


BEGIN
NETWORK
TITLE =Null-Merker


      U     "M1.0"; 
      R     "M1.0"; 
NETWORK
TITLE =Eins-Merker


      UN    "M1.1"; 
      S     "M1.1"; 
END_FUNCTION


FUNCTION_BLOCK FB 450
TITLE =
// 
AUTHOR : 'EMP/SZ'
VERSION : 0.1




VAR
  TOR_STOP : BOOL ;    //TOR stoppen
  FEHL_QUIT : BOOL ;    //Bedienfehler quittieren
  BEDIEN_FEHLER : BOOL ;    //Bedienfehler aufgetreten
  LADE_INDIREKT : BOOL ;    //Neuen Zählerwert vorbereiten
  VERGL1_LADEN : BOOL ;    //Neuen Vergleichswert 1 laden
  VERGL2_LADEN : BOOL ;    //Neuen Vergleichswert 2 laden
  RES_SYNCHRO : BOOL ;    //Statusbit Synchronisation löschen
  RES_NULL : BOOL ;    //Statusbit Nulldurchgang löschen
  TP_1 : "TP";    
  Q_1 : BOOL ;    
  P_1 : BOOL ;    
  N_1 : BOOL ;    
  Anfang : DINT ;    //Zählerstand für Geschwindigkeit
  Ende : DINT ;    //Zählerstand für Geschwindigkeit
  FP_L_DIREKT_Zaeler : BOOL ;    
  LADE_DIREKT_Zaeler : BOOL ;    
  Frequenz : DINT ;    
  Drehzahl : DINT ;    
  Material_Geschw : REAL ;    //Statischer <merker <maschinengeschwinigkeit
END_VAR
VAR_TEMP
  t_Real : REAL ;    
  t_Time : TIME ;    
  t_Dint : DINT ;    
END_VAR
BEGIN
NETWORK
TITLE =Störung Zähler Quittieren


      U     "E0.0"; 
      =     #FEHL_QUIT; 






NETWORK
TITLE =Impuls 1s


      UN    #Q_1; 
      =     L     12.0; 
      BLD   103; 
      CALL #TP_1 (
           IN                       := L     12.0,
           PT                       := T#1S,
           Q                        := #Q_1,
           ET                       := #t_Time);
      NOP   0; 
NETWORK
TITLE =Anstoß der Funktion "Direktes Laden" in Adresse "952"
//Der Zähler wird auf Null zurückgesetzt.
//DB451.DBD14 = 0  (load value)
      U     "E0.1"; 
      FP    #FP_L_DIREKT_Zaeler; 
      =     #LADE_DIREKT_Zaeler; 
NETWORK
TITLE =Zählerbaugruppe Adresse "952" Kanal-1 Geschwindigkeit


      U     "M1.1"; 
      =     L     12.0; 
      BLD   103; 
      U     #TOR_STOP; 
      =     L     12.1; 
      BLD   103; 
      U     #FEHL_QUIT; 
      =     L     12.2; 
      BLD   103; 
      CALL FC   450 (
           DB_NO                    := 455,
           SW_GATE                  := L     12.0,
           GATE_STP                 := L     12.1,
           OT_ERR_A                 := L     12.2,
           OT_ERR                   := #BEDIEN_FEHLER,
           L_DIRECT                 := #LADE_DIREKT_Zaeler,
           L_PREPAR                 := #LADE_INDIREKT,
           T_CMP_V1                 := #VERGL1_LADEN,
           T_CMP_V2                 := #VERGL2_LADEN,
           RES_SYNC                 := #RES_SYNCHRO,
           RES_ZERO                 := #RES_NULL);
      NOP   0; 
NETWORK
TITLE =


      U     #Q_1; 
      FP    #P_1; 
      SPBNB _001; 
      L     DB455.DBD   34; 
      T     #Anfang; 
_001: NOP   0; 
NETWORK
TITLE =Frequenz 1/s


      U(    ; 
      U     #Q_1; 
      FN    #N_1; 
      SPBNB _002; 
      L     DB455.DBD   34; 
      T     #Ende; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
_002: U     BIE; 
      )     ; 
      SPBNB _003; 
      L     #Ende; 
      L     #Anfang; 
      -D    ; 
      T     #Frequenz; 
_003: NOP   0; 
NETWORK
TITLE =Drehzahl U/min
//Inkremental Geber 1000Imp/U ---> U/min = f x 60 /1000
      U(    ; 
      L     #Frequenz; 
      L     L#60; 
      *D    ; 
      T     #t_Dint; 
      UN    OV; 
      SAVE  ; 
      CLR   ; 
      U     BIE; 
      )     ; 
      SPBNB _004; 
      L     #t_Dint; 
      L     L#1000; 
      /D    ; 
      T     #Drehzahl; 
_004: NOP   0; 
NETWORK
TITLE =Material Geschwindigkeit m/min
// Walzenumfang = 245,0 mm 
//m/min = D x 0.245
      U(    ; 
      L     #Drehzahl; 
      DTR   ; 
      T     #t_Real; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
      U     BIE; 
      )     ; 
      SPBNB _005; 
      L     #t_Real; 
      L     2.450000e-001; 
      *R    ; 
      T     #Material_Geschw; 
_005: NOP   0; 
NETWORK
TITLE =Zählerbaugruppe Adresse "952" Kanal-2 Reserve


      U     "M1.0"; 
      =     L     12.0; 
      BLD   103; 
      U     #TOR_STOP; 
      =     L     12.1; 
      BLD   103; 
      U     #FEHL_QUIT; 
      =     L     12.2; 
      BLD   103; 
      CALL FC   450 (
           DB_NO                    := 456,
           SW_GATE                  := L     12.0,
           GATE_STP                 := L     12.1,
           OT_ERR_A                 := L     12.2,
           OT_ERR                   := #BEDIEN_FEHLER,
           L_DIRECT                 := "M1.0",
           L_PREPAR                 := #LADE_INDIREKT,
           T_CMP_V1                 := #VERGL1_LADEN,
           T_CMP_V2                 := #VERGL2_LADEN,
           RES_SYNC                 := #RES_SYNCHRO,
           RES_ZERO                 := #RES_NULL);
      NOP   0; 
END_FUNCTION_BLOCK


DATA_BLOCK DB 450
TITLE =
AUTHOR : 'EMP/SZ'
VERSION : 0.0


 FB 450
BEGIN
   TOR_STOP := FALSE; 
   FEHL_QUIT := FALSE; 
   BEDIEN_FEHLER := FALSE; 
   LADE_INDIREKT := FALSE; 
   VERGL1_LADEN := FALSE; 
   VERGL2_LADEN := FALSE; 
   RES_SYNCHRO := FALSE; 
   RES_NULL := FALSE; 
   TP_1.IN := FALSE; 
   TP_1.PT := T#0MS; 
   TP_1.Q := FALSE; 
   TP_1.ET := T#0MS; 
   TP_1.STATE := B#16#0; 
   TP_1.STIME := T#0MS; 
   TP_1.ATIME := T#0MS; 
   Q_1 := FALSE; 
   P_1 := FALSE; 
   N_1 := FALSE; 
   Anfang := L#0; 
   Ende := L#0; 
   FP_L_DIREKT_Zaeler := FALSE; 
   LADE_DIREKT_Zaeler := FALSE; 
   Frequenz := L#0; 
   Drehzahl := L#0; 
   Material_Geschw := 0.000000e+000; 
END_DATA_BLOCK


ORGANIZATION_BLOCK OB 1
TITLE = "Main Program Sweep (Cycle)"
VERSION : 0.1




VAR_TEMP
  OB1_EV_CLASS : BYTE ;    //Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
  OB1_SCAN_1 : BYTE ;    //1 (Cold restart scan 1 of OB 1), 3 (Scan 2-n of OB 1)
  OB1_PRIORITY : BYTE ;    //Priority of OB Execution
  OB1_OB_NUMBR : BYTE ;    //1 (Organization block 1, OB1)
  OB1_RESERVED_1 : BYTE ;    //Reserved for system
  OB1_RESERVED_2 : BYTE ;    //Reserved for system
  OB1_PREV_CYCLE : INT ;    //Cycle time of previous OB1 scan (milliseconds)
  OB1_MIN_CYCLE : INT ;    //Minimum cycle time of OB1 (milliseconds)
  OB1_MAX_CYCLE : INT ;    //Maximum cycle time of OB1 (milliseconds)
  OB1_DATE_TIME : DATE_AND_TIME ;    //Date and time OB1 started
END_VAR
BEGIN
NETWORK
TITLE =Allgemeine Programmfunktionen


      CALL FC     1 ;








NETWORK
TITLE =Zählerkarte und Anzeigen vor ORT (PROFIBUS)


      CALL FB   450 , DB   450 ;






END_ORGANIZATION_BLOCK


ORGANIZATION_BLOCK OB 100
TITLE = "Complete Restart"
VERSION : 0.1




VAR_TEMP
  OB100_EV_CLASS : BYTE ;    //16#13, Event class 1, Entering event state, Event logged in diagnostic buffer
  OB100_STRTUP : BYTE ;    //16#81/82/83/84 Method of startup
  OB100_PRIORITY : BYTE ;    //Priority of OB Execution
  OB100_OB_NUMBR : BYTE ;    //100 (Organization block 100, OB100)
  OB100_RESERVED_1 : BYTE ;    //Reserved for system
  OB100_RESERVED_2 : BYTE ;    //Reserved for system
  OB100_STOP : WORD ;    //Event that caused CPU to stop (16#4xxx)
  OB100_STRT_INFO : DWORD ;    //Information on how system started
  OB100_DATE_TIME : DATE_AND_TIME ;    //Date and time OB100 started
END_VAR
BEGIN
NETWORK
TITLE =Zählerbaugruppe Adresse "512" Kanal-1 Geschwindigkeit


      U(    ; 
      U(    ; 
      L     512; 
      T     DB455.DBW    6; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
      U     BIE; 
      )     ; 
      SPBNB _001; 
      L     P#512.0; 
      T     DB455.DBD    8; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
_001: U     BIE; 
      )     ; 
      SPBNB _002; 
      L     32; 
      T     DB455.DBB   12; 
_002: NOP   0; 
NETWORK
TITLE =Zählerbaugruppe Adresse "512" Kanal-2 Reserve


      U(    ; 
      U(    ; 
      L     512; 
      T     DB456.DBW    6; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
      U     BIE; 
      )     ; 
      SPBNB _003; 
      L     P#544.0; 
      T     DB456.DBD    8; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
_003: U     BIE; 
      )     ; 
      SPBNB _004; 
      L     32; 
      T     DB456.DBB   12; 
_004: NOP   0; 
END_ORGANIZATION_BLOCK

Programmiersprache: Simatic STEP7 v5.3
CPU: 417-4 H

Vielen Dank im Voraus.
 
Die Zykluszeit der CPU sollte so gut wie keinen Einfluß auf das Messergebnis haben, weil die FM450-1 ein Zyklus-unabhängiger Hardware-Zähler ist.
Wie ist die Geschwindigkeitsmessung des Zählkanals parametriert (Modus, Parameter)? Wieviele Umdrehungen pro Minute macht der Encoder bei 70m/min? Wenn in der Messzeit zu wenige Impulse eingehen, dann kann einfach nicht hochauflösend genau gemessen werden.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich gebe Harald recht, dass schöne an der FM 450-1 ist gerade, dass es ein Hardwarezähler ist und es daher egal ist wann du im Zyklus draufguckst oder wie lange es dauert. Was du allerdings nicht gesagt hast ist, ob deine Walze mit dem Geber angetrieben ist oder nicht. Sollte dort ein Motor dran sein kannst du Schlupf nicht ausschliessen. Zusätzlich kommt es noch drauf an worauf du die Geschwindigkeit beziehst - so könnte es sein dass du eventuell noch die Dicke des Förderbandes einbeziehen musst. Was ich aus deinem Programm nicht rauslesen konnte war ob du die Geschwindigkeit absolut aus den gesamten Impulszeit errechnest (Beschleunigung?) oder ob du die Differenz aus 2 Zählwerten (Aktueller Zyklus - letzter Zyklus) immer wieder neu bestimmst.
 
Vielen Dank für Eure Antworten!


Unsere Walze ist ohne Antrieb und wird durch eine dünne folie angetrieben.
Der Encoder macht bei 70m/min 285,71 Umdrehungen pro Minute (4761 Imp/s).
Die angezeigte Geschwindigkeit springt (69,5..70,0..69,7..70,8..70,1 usw.).
In einem FB 450 Baustein haben wir einen Impuls von 1 sek realisiert.
Mit der positiven Flanke des Impulses lesen wir den alten Zählerwert ab und mit der negativen den neuen Zählerwert.
Kann es sein, dass die Zeit von 1 sek nicht immer konstant ist?

Vielleicht könntet Ihr mir ein Beispielprogramm zeigen, wie Ihr das machen würdet.
Vielen Dank.
 
In einem FB 450 Baustein haben wir einen Impuls von 1 sek realisiert. Mit der positiven Flanke des Impulses lesen wir den alten Zählerwert ab und mit der negativen den neuen Zählerwert.
Kann es sein, dass . . .
. . . die ZählImpulse zwischen der negativen und der positiven Flanke ignroriert/"weggeschmissen" werden?

Bei der Messung der Geschwindigkeit zwischen 0 m/min und 70 m/min haben wir einer Abweichung von +-2%.
Die angezeigte Geschwindigkeit springt (69,5..70,0..69,7..70,8..70,1 usw.).
Das sieht ja relativ symmetrisch zum erwarteten Wert von 70 m/min aus, so dass man nicht wirklich auf ein "Schlabbern" von Impulsen, z.B. durch Schlupf, schliessen muss.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das könnte ein Grund sein. Normalerweise kannst du im Hardwarekatalog der CPU ein sogenanntes Taktmerkerbyte (dann hat man 7 Bits die sich zeitlich von 100ms bis 2s ändern) eintragen. Die sind immer genau - versuch doch mal den auf deine Flanke zu packen anstatt den selbstgebastelten.

Weiterhin komm ich zwar nicht aus der Fördertechnik - aber ihr habt doch sicher auch Umrichter dran die die Motoren drehzahlgeregelt steuern. Bei erkennen eines Unterschiedes soll/ist kann der P-Anteil im Drehzahlregler etwas zu grosszügig eingestellt sein, dass es vllt zu einem kurzen Überschwingen kommt. Allerdings wie mein Vorposter sagt find ich die Werte auch nicht kritisch abweichend. Bei einer Bandanlage bei uns liegt die Geschwindigkeit bei 90m/min und da sind Abweichungen von +/- 1 m/min gang und gebe im laufenden Betrieb. Vllt. ist eine deiner Rollen auch keine Rolle sondern eine kleine Elipse und dein Band "eiert" - was dann die unterschiede Erklären würde. Jedes mal wenn die dicke Seite vom Ei kommt wirds langsamer und dann wieder schneller.

Anhand deiner Werte könnte es auch sein, dass der P-Anteil im Umrichter sehr klein aber der I-Anteil gross und du bei einer Drehzahldifferenz auch nach Erreichen der Solldrehzahl weiter integrierst.
 
Zuletzt bearbeitet:
Vllt. ist eine deiner Rollen auch keine Rolle sondern eine kleine Elipse und dein Band "eiert" - was dann die unterschiede Erklären würde. Jedes mal wenn die dicke Seite vom Ei kommt wirds langsamer und dann wieder schneller.
Ja, wenn das Ei angetrieben wird. Wenn das Band mit konstanter Geschwindigkeit läuft und ein DrehzahlMessEi vom Band angetrieben wird, ist es genau umgekehrt. Und es kommt wohl weniger auf die "dicke Seite" an, als auf die Lage der DrehAchse, die auch bei einem präzisen Kreis exzentrisch verlaufen kann. Egal, das hilft uns auch nicht weiter . . . wir wollen hier anstreben, dass die Software möglichst rund läuft.
TaktMerker ist nicht schlecht, aber der AuswertungsZeitpunkt im OB1-Zyklus dürfte um ±1/2 ZyklusZeit schwanken, hier also ca. ±30 ms also ca. ±3 % bezogen auf ein MessIntervall von 1 s.
WeckAlarm als Takt ist vermutlich genauer. Ganz wichtig: den HW-Zähler durchlaufen lassen und nur lesen - nicht nullen.
 
Also wir haben diese Sprünge im Bereich von ±3 % auch bei uns. Allerdings ist das bei uns auch nur eine Anzeige am HMI und daher den Aufwand nicht wert. Ich denke wie Heinileini schon schrieb, dass ein Weckalarm OB in dem du deine Differenzmessung machst und der auf 1s eingestellt ist deutlich genauer ist. Dadurch dürfte die Schwankung die durch die Software verschuldet wird gegen Null tendieren. Falls du nach der Umsetzung von Heinileinis Anweisungen noch Schwankungen hast sind diese vermutlich mechanischer Natur.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich stimme Heinileine voll zu. Solche Auswertungen macht man über einen konstanten Abfragezyklus. Bei Siemens gibt es dafür den Weckalarm.

Die Sprünge in der Anzeige sind dann vermutlich auf die nicht konstante Abfrage zurückzuführen und in der Höhe von der Impulszahl pro Abfragezyklus und von der zeitlichen Schwankung abhängig.
Je mehr Impulse pro Abfragezyklus desto genauer wird die Anzeige - zeitliche Konstanz voraausgesetzt. 4-fach-Auswertung heisst das glaube ich bei Siemens, wenn alle Flanken des Drehimpulsgebers zur Zählung herangezogen werden. Ergibt dann die 4-fache Impulszahl gegenüber der Strichzahl des Gebers.

@Heinileini
Wie kann die Zählung um einen halbe OB1-Zyklus schwanken? Wenn, dann hat man doch einen Jittter von 1 ganzem Zyklus oder nicht?
 
@Heinileini
Wie kann die Zählung um einen halbe OB1-Zyklus schwanken? Wenn, dann hat man doch einen Jittter von 1 ganzem Zyklus oder nicht?

Zumindest der Aufrufzeitpunkt schwankt um ±1 ganzen Zyklus wenn man einen Taktmerker verwendet. Das sind dann natürlich theoretische Außreißerwerte...
 
Der Encoder macht bei 70m/min 285,71 Umdrehungen pro Minute (4761 Imp/s).
Die angezeigte Geschwindigkeit springt (69,5..70,0..69,7..70,8..70,1 usw.).
In Deiner Geschwindigkeitsberechnung sind mehrere "Unschönheiten", wie man es besser nicht macht.

(1) Die Ganzzahl-Division in FB450 Netzwerk 7: #Drehzahl := #Frequenz * 60 / 1000;
Deshalb springt Deine Geschwindigkeits-Anzeige in Stufen von ca. 0.25 m/min (Zähldifferenz-Schwankungen wirken sich nur in Stufen ca. > 16 aus).
Besser: zumindest die Division in REAL machen.
(2) Die Erzeugung des 1s-Taktes ist suboptimal, die schwankt um 1 OB1-Zykluszeit.
Besser: den Zählerstand des Zählkanals in einem Weckalarm mit konstantem Aufruf-Intervall auslesen, das sorgt für viel weniger schwankendes Messintervall.
(3) Rücksetzen des FM450-1-Zählkanals bei laufender Achse ist nicht gut, weil da Zählimpulse verloren gehen können.
Besser: den Zählkanal frei in "Endlos Zählen" laufen lassen mit niemals Rücksetzen. Immer nur den aktuellen Zählerstand übernehmen. Der Zähler-Überlauf über die 2[SUP]32[/SUP]-Grenze wird elegant ausgeblendet, wenn man Zählerstand-Differenzen mit -D (SUB_DI) bildet und verarbeitet.

Weitere Anmerkungen:
Du hast den Geber als A+B+N parametriert - der Geber hat hoffentlich keinen N-Kanal bzw. der ist nicht angeschlossen. Bei Endlos-Zählen-Betriebsart darf der Geber den Zählerstand nicht nullen.
Du hast den Geber nur mit einfach-Auswertung parametriert - man kann die Rechen-Auflösung der Bandgeschwindigkeitsanzeige bei kleinen Drehzahlen erhöhen, wenn man auf zweifach- oder vierfach-Auflösung umstellt.

Versuche Dein Programm mal etwa so:

Zählerstand-Übernahme in Weckalarm (cyclic interrupt) OB32 alle 1000ms:
Code:
//OB32 alle 1000ms

      L     "DB450".Ende        //letzten End-Zählerstand
      T     "DB450".Anfang      //als neuen Anfangs-Zählerstand übernehmen

      L     PED516              //aktuellen Zählerstand (CH1: ACT_CNTV)
      T     "DB450".Ende        //als neuen End-Zählerstand übernehmen

Im FB450 die 1s-Messintervall-Erzeugung entfernen und auf REAL-Berechnung umstellen:
Code:
FUNCTION_BLOCK FB 450
TITLE =
// 
AUTHOR : 'EMP/SZ'
VERSION : 0.1

VAR
  TOR_STOP : BOOL ;	//TOR stoppen
  FEHL_QUIT : BOOL ;	//Bedienfehler quittieren
  BEDIEN_FEHLER : BOOL ;	//Bedienfehler aufgetreten
  LADE_INDIREKT : BOOL ;	//Neuen Zählerwert vorbereiten
  VERGL1_LADEN : BOOL ;	//Neuen Vergleichswert 1 laden
  VERGL2_LADEN : BOOL ;	//Neuen Vergleichswert 2 laden
  RES_SYNCHRO : BOOL ;	//Statusbit Synchronisation löschen
  RES_NULL : BOOL ;	//Statusbit Nulldurchgang löschen
  TP_1 : "TP";	
  Q_1 : BOOL ;	
  P_1 : BOOL ;	
  N_1 : BOOL ;	
  Anfang : DINT ;	//Zählerstand für Geschwindigkeit
  Ende : DINT ;	//Zählerstand für Geschwindigkeit
  FP_L_DIREKT_Zaeler : BOOL ;	
  LADE_DIREKT_Zaeler : BOOL ;	
  Frequenz : DINT ;	
  Drehzahl : DINT ;	
  Material_Geschw : REAL ;	//Statischer <merker <maschinengeschwinigkeit
END_VAR
VAR_TEMP
  t_Real : REAL ;	
  t_Time : TIME ;	
  t_Dint : DINT ;	
  t_Drehzahl_Real : REAL ;	
END_VAR
BEGIN
NETWORK
TITLE =Störung Zähler Quittieren

      U     "E0.0"; 
      =     #FEHL_QUIT; 
NETWORK
TITLE =Zählerbaugruppe Adresse "952" Kanal-1 Geschwindigkeit
//Kanal 1: Endlos Zählen, nie Rücksetzen
      U     "M1.1"; 
      =     L     16.0; 
      BLD   103; 
      U     #TOR_STOP; 
      =     L     16.1; 
      BLD   103; 
      U     #FEHL_QUIT; 
      =     L     16.2; 
      BLD   103; 
      CALL FC   450 (
           DB_NO                    := 455,
           SW_GATE                  := L     16.0,
           GATE_STP                 := L     16.1,
           OT_ERR_A                 := L     16.2,
           OT_ERR                   := #BEDIEN_FEHLER,
           L_DIRECT                 := #LADE_DIREKT_Zaeler,
           L_PREPAR                 := #LADE_INDIREKT,
           T_CMP_V1                 := #VERGL1_LADEN,
           T_CMP_V2                 := #VERGL2_LADEN,
           RES_SYNC                 := #RES_SYNCHRO,
           RES_ZERO                 := #RES_NULL);
      NOP   0; 
NETWORK
TITLE =Drehzahl U/min
//Inkremental Geber Auswertung "einfach":
//1000Imp/U ---> U/min = f * 60 /1000 = f * 0.06
      L     #Ende; 
      L     #Anfang; 
      -D    ; 
      T     #Frequenz; 
      UN    OV; 
      SAVE  ; 
      CLR   ; 
      U     BIE; 
      =     L     16.0; 
      U(    ; 
      U     L     16.0; 
      SPBNB _001; 
      L     #Frequenz; 
      L     L#60; 
      *D    ; 
      T     #t_Dint; 
      UN    OV; 
      SAVE  ; 
      CLR   ; 
_001: U     BIE; 
      )     ; 
      SPBNB _002; 
      L     #t_Dint; 
      L     L#1000; 
      /D    ; 
      T     #Drehzahl; 
_002: NOP   0; 
      U(    ; 
      U     L     16.0; 
      SPBNB _003; 
      L     #Frequenz; 
      DTR   ; 
      T     #t_Real; 
      SET   ; 
      SAVE  ; 
      CLR   ; 
_003: U     BIE; 
      )     ; 
      SPBNB _004; 
      L     #t_Real; 
      L     6.000000e-002; 
      *R    ; 
      T     #t_Drehzahl_Real; 
_004: NOP   0; 
NETWORK
TITLE =Material Geschwindigkeit m/min
// Walzenumfang = 245,0 mm 
//m/min = D * 0.245
      L     #t_Drehzahl_Real; 
      L     2.450000e-001; 
      *R    ; 
      T     #Material_Geschw; 
      NOP   0; 
NETWORK
TITLE =Zählerbaugruppe Adresse "952" Kanal-2 Reserve

      U     "M1.0"; 
      =     L     16.0; 
      BLD   103; 
      U     #TOR_STOP; 
      =     L     16.1; 
      BLD   103; 
      U     #FEHL_QUIT; 
      =     L     16.2; 
      BLD   103; 
      CALL FC   450 (
           DB_NO                    := 456,
           SW_GATE                  := L     16.0,
           GATE_STP                 := L     16.1,
           OT_ERR_A                 := L     16.2,
           OT_ERR                   := #BEDIEN_FEHLER,
           L_DIRECT                 := "M1.0",
           L_PREPAR                 := #LADE_INDIREKT,
           T_CMP_V1                 := #VERGL1_LADEN,
           T_CMP_V2                 := #VERGL2_LADEN,
           RES_SYNC                 := #RES_SYNCHRO,
           RES_ZERO                 := #RES_NULL);
      NOP   0; 
END_FUNCTION_BLOCK
(Brauchst Du die Drehzahl als Ganzzahl? Wenn nicht, dann kannst Du in Netzwerk 3 die Ganzzahl-Berechnung entfernen.)

Falls Dir die Geschwindigkeitsanzeige immer noch zu stark springt, dann könntest Du noch ein bisschen glätten/verschleifen, indem Du am Ende des Messintervalls nicht sofort den neuen Wert anzeigst, sondern zunächst den Mittelwert zwischen dem neuen Wert und dem vorherigen Wert und erst eine halbe Sekunde später den neuen Wert. Falls die halbe Sekunde Auflösung nicht reicht, dann könntest Du mehrere Messintervalle ineinander verschachteln, z.B. alle 100ms den Zählerstand in einen FIFO mit 10 Werten einschieben und die Differenz zum Zählerstand 1s vorher (10x 100ms vorher, der älteste im FIFO) bilden - so hast Du eine Messzeit von 1s, aber trotzdem alle 100ms einen neuen Geschwindigkeitswert.

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@Heinileini
Wie kann die Zählung um einen halbe OB1-Zyklus schwanken? Wenn, dann hat man doch einen Jittter von 1 ganzem Zyklus oder nicht?
Deine Formulierung ist wohl treffender, aber letztendlich beschreibt ±0,5 ebenfalls eine Spanne von 1.
 
Deine Formulierung ist wohl treffender, aber letztendlich beschreibt ±0,5 ebenfalls eine Spanne von 1.

Man hat aber eben eine Spanne von 2 (± 1 Zyklus) wenn man einen Merkertakt verwendet.

Beispiel:
Man nimmt als Trigger den 1 Hz Merker und hat eine Zykluszeit von 10ms:

1.) Beim ersten Zyklus war der Taktmerker geradeso nicht ausgelöst, weshalb beim zweiten Zyklus das Startsignal kommt wenn der Taktmerker bereits seit 9,9ms (= fast 1 Zyklus) an ist. Knapp eine Sekunde später trifft der Taktmerker hingegen sofort, weshalb die Zeitdifferenz zum letzten Auslösen 0,9901 s beträgt.

2.) Beim ersten Zyklus hat der Taktmerker genau getroffen. Knapp eine Sekunde später trifft der Taktmerker hingegen geradeso nicht, weshalb beim Zyklus danach das Startsignal kommt wenn der Taktmerker bereits seit 9,9ms (= fast 1 Zyklus) an ist., weshalb die Zeitdifferenz zum letzten Auslösen 1,0099 s beträgt.

--> schwankt um 2 Spannen (± 1 Zyklus)
 
Man hat aber eben eine Spanne von 2 (± 1 Zyklus) wenn man einen Merkertakt verwendet.
Ja, stimmt auffällig! Anfang "zu spät" erkannt: -1 ZyklusZeit, Ende "zu spät" erkannt: +1 ZyklusZeit. Das hatte ich viel zu oberflächlich betrachtet.
Also nicht lächerliche ±3 %, sondern bedenkliche ±6 %!
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Falls Dir die Geschwindigkeitsanzeige immer noch zu stark springt, dann könntest Du noch ein bisschen glätten/verschleifen, indem Du am Ende des Messintervalls nicht sofort den neuen Wert anzeigst, sondern zunächst den Mittelwert zwischen dem neuen Wert und dem vorherigen Wert und erst eine halbe Sekunde später den neuen Wert. Falls die halbe Sekunde Auflösung nicht reicht, dann könntest Du mehrere Messintervalle ineinander verschachteln, z.B. alle 100ms den Zählerstand in einen FIFO mit 10 Werten einschieben und die Differenz zum Zählerstand 1s vorher (10x 100ms vorher, der älteste im FIFO) bilden - so hast Du eine Messzeit von 1s, aber trotzdem alle 100ms einen neuen Geschwindigkeitswert.

Harald

Nennt sich gleitender Mittelwert. Hat meistens Vorteile. Ein Nachteil sollte nicht ungenannt bleiben: Der angezeigte Messwert hinkt dem Aktualwert um die Länge des FIFO hinterher. Ist aber (meistens) unwichtig für reine Anzeigeaufgaben.

@Heinileini
Halbe Zyklen gibt es nicht und @Stoky hat ausformuliert was Du ganz sicher schon wusstest.
 
Nennt sich gleitender Mittelwert. Hat meistens Vorteile. Ein Nachteil sollte nicht ungenannt bleiben: Der angezeigte Messwert hinkt dem Aktualwert um die Länge des FIFO hinterher.
Der von mir beschriebene FIFO hat nichts mit gleitenden Mittelwerten zu tun. Und da "hinkt" auch nichts hinterher, im Gegenteil: man hat schon alle 100ms einen echten unmanipulierten Meßwert anstatt alle 1s

Harald
 
Nochmal möchte ich mich bei allen bedanken! Wirklich viele nützliche Informationen, die mir bei meinem Problem bestimmt helfen werden.
Ich werde die Vorschläge einbauen und die Tage testen und darüber berichten.

Auch ein besonders großes Danke an PN/DP, für die ausführliche Erklärung, wie ich die Messungen verbessern kann.
Eine Frage bleibt mir noch und zwar:

Warum verwendest Du PED516?
Ich habe bisher immer DB455.DBD34 als den aktuellen Zählerstand benutzt.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Warum verwendest Du PED516?
Ich habe bisher immer DB455.DBD34 als den aktuellen Zählerstand benutzt.
Wenn Du die Zählerstand-Auswertung nur im OB1 machst, dann ist es relativ egal ob PED516 oder DB455.DBD34 verwendet wird.

Damit die Messzeit von 1s so genau und gleichbleibend wie möglich eingehalten wird, wird das Auslesen des Zählerstands in meinem Programmbeispiel extra im zyklischen Weckalarm OB32 gemacht. Der hat den OB1 an irgendeiner Stelle unterbrochen. Der Zählerstand in DB455.DBD34 (ACT_CNTV) kann gerade eben oder auch schon vor 60ms aktualisiert worden sein. Wenn man nun den Zählerstand aus DB455.DBD34 verwenden würde, dann würde man sich wieder den Jitter in der Größe der OB1-Zykluszeit ins Programm holen. Es soll/muß genau der Zählerstand gelesen werden, der zum Zeitpunkt des OB32-Aufrufs im Zähler ist - deshalb im OB32 das Zählerstand-Lesen direkt aus der Peripherieadresse des Zählkanals PED516.

Alternativ könnte man den FC450 (zusätzlich oder ausschließlich) im OB32 aufrufen, doch die Code-Ausführungszeit in Weckalarmen sollte möglichst kurz sein, damit die Weckalarme nicht zu zusätzlich schwankenden OB1-Zykluszeiten führen. Außerdem weiß ich nicht, ob der FC450 in verschiedenen OBs ausgeführt werden darf - er könnte sich da ja selbst unterbrechen.

Harald
 
Zurück
Oben