Beispielprogramm 1 und 2 (Offset/Gain)

Download TwinCAT 3 Projekt:

Programmlink

Programmbeschreibung/ Funktion:

Es lässt sich in diesem Beispielprogramm die Konfiguration von minimal zulässiger Eingangsfrequenz, Reihenfolge der Berechnungen Gain und Offset sowie das direkte Schreiben in das CoE‑Verzeichnis (Objekt „PAI Scaler Settings“) vornehmen (siehe Variablendeklaration).

Vorgesehen ist die folgende Vorgehensweise:

  1. Konfiguration „bWriteToCoEEnable“ = TRUE, d.h. nach Abschluss der Berechnung der Korrekturwerte werden diese in das CoE Objekt „PAI Scaler Settings“ geschrieben.
  2. Box über das CoE‑Verzeichnis im Objekt „PAI Settings Ch. 1“ 0x8000:2E auf „Extended Range“ (0) einstellen.
  3. Aufschaltung eines periodischen Signals (Dreieck, Sinus, Rechteck, ...) an die Box innerhalb des ausgewählten Spannungs-/ Strombereichs (MBE) über PAI‑Settings Objekt 0x8000:01 (Interface).
  4. Start des Programms durch das Setzen von „bEnable“ auf „TRUE“.
  5. Das Ausführungsende ist anhand der Variablen „bScaleGainDone“ und „bScaleOffsetDone“ erkennbar, sobald beide TRUE sind.
  6. Ist das Schreiben in das CoE aktiviert („bWriteToCoEEnable“ = TRUE), sollten die ermittelten Werte in das CoE Verzeichnis, Objekt „PAI Scaler Settings“, geschrieben worden sein (siehe Variable „bError“).
  7. Falls 6. ausgeführt wurde, kann die Box über das CoE‑Verzeichnis im Objekt „PAI Settings Ch. 1“ 0x8000:2E auf „Linear“ (1) eingestellt werden. Dadurch führt die Box die Korrekturberechnung intern aus (siehe: „nScaledSampleVal“).

Anmerkungen:

Alternativ kann anstelle des Funktionsblocks „FB_GET_MIN_MAX“ auch von der TC3 Analytics Library (TF3510) Gebrauch gemacht werden. Der Funktionsblock „FB_ALY_MinMaxAvg_1Ch“ kann ebenfalls für die Ermittlung der Min./Max. Werte herangezogen werden. Es kann dann auch die gesamte Berechnung in diesem Programm durch Verwendung des von diesem Funktionsblock zur Verfügung gestellten Mittelwertes modifiziert werden.

Bei der Box EPP3504/ ERP3504 ist das „PAI Scaler Settings“ – Objekt 0x80n6 und zudem können die Variablen nOffset und nGain auch direkt ohne die Typ-Konvertierung (REAL zu DINT) geschrieben werden; eine Skalierung des Amplituden-Korrekturwertes mit 65536 ist ebenfalls nicht mehr nötig.

Variablendeklaration Beispielprogramme 1 und 2

PROGRAM MAIN
VAR_INPUT
   bEnable               :BOOL; // Start the code (Offset / Gain adjust)
   nPAI_Sample AT%I*     :DINT; // Input samples of the measurement value
END_VAR
VAR
   // Enter your Net-Id here:
   userNetId             :T_AmsNetId := 'a.b.c.d.x.y';
   // Enter EtherCAT device address here:
   nUserSlaveAddr        :UINT := 1002; // Check, if correct
   // Configurations:
   fMinFrequencyIn       :REAL:=1.5; // Hz
   bScalingOrder         :BOOL:=FALSE; // TRUE: Start scale offset first
   bWriteToCoEEnable     :BOOL:=FALSE; // TRUE: Enable writing to CoE
   // ===============================================
   // "Main" State controlling Offset/Gain adjusting:
   nMainCal_State        :BYTE:=0;
   // For CoE Object 0x8005 access:
   fb_coe_write          :FB_EcCoESdoWrite; // FB for writing to CoE
   nSTATE_WRITE_COE      :BYTE := 0;
   nSubIndex             :BYTE;
   nCoEIndexScaler       :WORD := 16#8005; // Use channel 1
   // For EPP3504/ ERP3504 this is 0x8006
   nSubIndScalGain       :BYTE := 16#02;
   nSubIndScalOffs       :BYTE := 16#01;
   nADSErrId             :UDINT; // Copy of ADS-Error ID
   // ===============================================
   fb_get_min_max        :FB_GET_MIN_MAX; // Min/Max values needed
   // Note: you may also use "FB_ALY_MinMaxAvg_1Ch" of TwinCAT analytics)
   // instead; there avg (average values can also be determinated
   // Variables used for offset scaling:
   nSTATE_SCALE_OFFSET   :INT := 0;
   bScaleOffsetStart     :BOOL := FALSE;
   bScaleOffsetDone      :BOOL := FALSE;
   fOffsetDeviationVal   :REAL;
   nOFFSET_MIN_VAL_REF   :WORD := 200;  // Max. limit value for offset
   // Variables used for gain scaling:
   nSTATE_SCALE_GAIN     :INT := 0;
   bScaleGainStart       :BOOL := FALSE;
   bScaleGainDone        :BOOL := FALSE;
   nPRESET_MAX_VAL       :REAL := 3000000; // Target amplitude value
   // ===============================================
   // Variables for evaluating of gain and offset:
   nOffset               :REAL := 0; // Offset value
   nGain                 :REAL := 1; // Gain value
   nScaledSampleVal      :REAL;
   nDINT_Value           :DINT;
   fb_trig_bEnable       :R_TRIG; // Trigger FB for Enable
   bError                :BOOL := FALSE; // Evaluate..
END_VAR

Ausführungsteil:

// THIS CODE IS ONLY AN EXAMPLE - YOU HAVE TO CHECK APTITUDE FOR YOUR APPLICATION
// Example program 1 and 2 program code:
// =====================================
// 1. PAI setting of 0x80n0:2E must be "Extended Range" at first
// 2. When writing of scaling values were done, switch to "Linear"
// Calculation of the temporary value (..and use for ScopeView to check)
nScaledSampleVal := nOffset + nGain * DINT_TO_REAL(nPAI_Sample);
// Main-State Procedure:
CASE nMainCal_State OF
   0:
      fb_trig_bEnable(CLK:=(bEnable AND NOT bError));
      IF fb_trig_bEnable.Q THEN // Poll switch or button
         // Initialize temporary offset and gain values:
         nOffset:= 0;
         nGain  := 1;
         bScaleOffsetStart := bScalingOrder;
         bScaleGainStart   := NOT bScalingOrder;
         fb_get_min_max.nMinFreqInput := fMinFrequencyIn;
         nMainCal_State := 10; // Start
      END_IF
   10:
      IF (bScaleGainDone AND NOT bScalingOrder)
        OR (bScaleOffsetDone AND bScalingOrder) THEN
         bScaleOffsetStart := NOT bScalingOrder;
         bScaleGainStart   := bScalingOrder;
         nMainCal_State := nMainCal_State + 10;
      END_IF
   20:
      IF bScaleGainDone AND bScaleOffsetDone THEN
         nMainCal_State :=0; // All done, initalization for next start
      END_IF
END_CASE
// ----- Offset scaling (program 1) -----
IF bScaleOffsetStart THEN
   CASE nSTATE_SCALE_OFFSET OF
   0:
      bScaleOffsetDone := FALSE; // Initialization of confirmation flag
      // Get min/max values within a period of the signal:
      fb_get_min_max(nInputValue:=nScaledSampleVal);
      IF fb_get_min_max.bRESULT THEN // Wait if Limit-Values are valid
         // Min/Max Values valid, continue..
         // calculate current offset deviation:
         fOffsetDeviationVal :=
         (fb_get_min_max.nMaxVal - ABS((fb_get_min_max.nMaxVal-fb_get_min_max.nMinVal)/2));
         // Offset deviation check:
         IF ABS(fOffsetDeviationVal) < nOFFSET_MIN_VAL_REF THEN
            // Deviation in acceptable range - offset scaling done,
            // now write correction value into CoE Object:
            nDINT_Value := REAL_TO_DINT(nOffset);
            // Initiate writing to CoE:
            nSubIndex := nSubIndScalOffs;
            nSTATE_WRITE_COE := 10;
            nSTATE_SCALE_OFFSET := nSTATE_SCALE_OFFSET + 10;
         ELSE
            // Calculate new offset value (new by old with deviation)
            nOffset := nOffset - fOffsetDeviationVal;
         END_IF
      END_IF
   10:
      IF(nSTATE_WRITE_COE = 0) THEN
         // Scaling offset done within CoE for the device
         bScaleOffsetDone := TRUE;
         bScaleOffsetStart := FALSE;
         nSTATE_SCALE_OFFSET := 0;
        END_IF
   END_CASE
END_IF
// ----- Gain scaling (program 2) -----
IF bScaleGainStart THEN
   CASE nSTATE_SCALE_GAIN OF
   0:
      bScaleGainDone := FALSE; // Initialization of confirmation flag
      // Get min/max values within a period of the signal:
      fb_get_min_max(nInputValue:=DINT_TO_REAL(nPAI_Sample));
      IF fb_get_min_max.bRESULT THEN // Wait if Limit-Values are valid
         // Calculate Gain 
         nGain := nPRESET_MAX_VAL/ABS((fb_get_min_max.nMaxVal-fb_get_min_max.nMinVal)/2);
         // ..shift gain value by 16 Bit left and convert to DINT:
         nDINT_Value := REAL_TO_DINT(65536 * nGain);
         //Due to 'output = gain * input + offset', the offset have to be adapted:
         nOffset := nOffset * nGain;
          // Initiate writing to CoE:
         nSubIndex := nSubIndScalGain;
         nSTATE_WRITE_COE := 10;
         nSTATE_SCALE_GAIN := nSTATE_SCALE_GAIN + 10;
        END_IF
   10:
      IF(nSTATE_WRITE_COE = 0) THEN
         IF NOT (nOffset = 0) THEN
            // (bScalingOrder is TRUE)
            nDINT_Value := REAL_TO_DINT(nOffset);
            // Initiate writing to CoE (again):
            nSubIndex := nSubIndScalOffs;
            nSTATE_WRITE_COE := 10;
            END_IF
         nSTATE_SCALE_GAIN := nSTATE_SCALE_GAIN + 10;
        END_IF   
   20:
      IF(nSTATE_WRITE_COE = 0) THEN        
         // Scaling gain done within CoE for the device
         bScaleGainStart := FALSE;
         bScaleGainDone := TRUE;
         nSTATE_SCALE_GAIN := 0; // Set initial state
        END_IF
   END_CASE
END_IF
IF (nSTATE_WRITE_COE > 0) THEN
   IF bWriteToCoEEnable THEN
      CASE nSTATE_WRITE_COE OF
      10:
         // Prepare CoE write access
         fb_coe_write(
            sNetId:=     userNetId,
            nSlaveAddr:= nUserSlaveAddr,
            nIndex:=     nCoEIndexScaler,
            bExecute:=   FALSE,
            tTimeout:=   T#1S
         ); 
         nSTATE_WRITE_COE := nSTATE_WRITE_COE + 10;
      20:
         // Write nDINT_Value to CoE Index "Scaler":
         fb_coe_write(
         nSubIndex:= nSubIndex,
         pSrcBuf:= ADR(nDINT_Value),
         cbBufLen:= SIZEOF(nDINT_Value),
         bExecute:= TRUE
         );
         nSTATE_WRITE_COE := nSTATE_WRITE_COE + 10;
      30:
         fb_coe_write();
         IF NOT fb_coe_write.bBusy THEN
            nSTATE_WRITE_COE := 0;
         END_IF
      END_CASE
   ELSE
      nSTATE_WRITE_COE := 0;
    END_IF
END_IF
IF(fb_coe_write.bError) AND NOT bError THEN
   bError := TRUE;
   nADSErrId := fb_coe_write.nErrId;
   // CoE write acccess error occured: reset all
   nSTATE_WRITE_COE := nMainCal_State := 0;
   bScaleOffsetDone := bScaleOffsetStart := FALSE;
   bScaleGainDone   := bScaleGainStart   := FALSE;
END_IF