Configuration Example: DC541-CM Used as Interrupt I/O Device

Hardware configuration

The example control system shall have the following configuration:

  • Terminal base TB521 (two Communication Module slots)
  • DC541-CM in Communication Module slot 1 (first slot on the left of the CPU)
  • PM591-ETH
  • I/O module DC532 on the I/O Bus

Wiring

The channels are connected as follows:

DC532 / C16 ————– DC541 / C0

DC532 / C17 ————– DC541 / C1

DC532 / C18 ————– DC541 / C2

DC532 / C19 ————– DC541 / C3

DC532 / C20 ————– DC541 / C4

DC532 / C21 ————– DC541 / C5

PLC configuration

- DC541-CM in slot 1, operating mode “IO mode”

- Configuration: Channels C0…C4 Interrupt input
  Channel C5 Input
  Channels C6…C7 Outputs
  • Specification of the ETHERNET Communication Module as internal Communication Module (if available)
  • DC532 on the I/O bus

Task configuration

  • Task 1: Cyclic program / Prio = 10 / Interval = t#10ms / PLC_PRG
  • Task 2: HIGHInterrupt_1 / DC541_Interrupt_Ext1()

Purpose of the interrupt program DC541_Interrupt_Ext1()

The interrupt program should fulfill the following functionality:

  • Counting of all interrupts
  • Counting of the interrupts per input
  • Calculation of the interrupt frequency in [Int/s]
  • Reporting of the number of interrupts per input
  • Input C4: Resetting the counters
  • Input C5: Input
  • Output C6: Status of input C5
  • Output C7: Toggle output

The declaration part of the program looks as follows:

PROGRAM DC541_Interrupt_Ext1  
VAR    
  dwIntCount : DWORD; (* count all interrupts *)
  dwIntCountOld : DWORD; (* start value for next measure *)
  tActual : TIME; (* systemtick in ms *)
  tStart : TIME; (* start value of systemtick for next calculation *)
  dwUsedTime : DWORD; (* time for 1000 interrupts in ms *)
  dwFrequenz : DWORD; (* interrupt frequency in [Int / sec] *)
  DC541_IntSource : DC541_INT_IN; (* instance FB: read interrupt source *)
  DC541_Ios : DC541_IO; (* instance FB: read/write inputs/outputs *)
  dwCount_InX : ARRAY[0..cbyDC541_IntInp] OF DWORD; (* count interrupts of In0..In3 *)
  dwCount_InXOld : ARRAY[0..cbyDC541_IntInp] OF DWORD; (* start value for next 1000 interrupts *)
  dwIntHisto : ARRAY[0..cbyDC541_IntInp, 0..cbyDC541_MaxHist] OF DWORD; (* histo data C0…C3 *)
  wIndex : WORD; (* index for histo data *)
  byInd : BYTE; (* loop index *)
END_VAR    
VAR CONSTANT    
  cbyDC541_SLOT : BYTE := 1; (* SLOT number of DC541 *)
  cbyDC541_MaxHist : BYTE := 9; (* max number of histo entries *)
  cbyDC541_IntInp : BYTE := 4; (* number of interrupt inputs -1 *)
END_VAR    

The instruction part looks as follows:

At the beginning, the interrupts are counted in dwIntCount. After each 1000 interrupts, a calculation of the frequency is performed and the counting values for the interrupts per input are stored.

dwIntCount := dwIntCount + 1; (* count all interrupts *)
IF dwIntCount - dwIntCountOld >= 1000 THEN (* after 1000 interrupts -> calculate frequency  *)
  dwIntCountOld := dwIntCount; (* save dwIntCount for next call *)
  tActual := TIME();  
  dwUsedTime := TIME_TO_DWORD(tActual - tStart); (* duration in ms for 1000 interrupts *)
  dwFrequenz := 1000000 / dwUsedTime; (* [Interrupt / sec] 1000 Int * 1000 ms/sec *)
  tStart := tActual; (* for next measure *)
  dwIntHisto[0,wIndex] := dwCount_InX[0] - dwCount_InXOld[0]; (* IN0 interrupts of last 1000 *)
  dwCount_InXOld[0] :=dwCount_InX[0]; (* start value for next measure *)
  dwIntHisto[1,wIndex] := dwCount_InX[1] - dwCount_InXOld[1]; (* IN1 interrupts of last 1000 *)
  dwCount_InXOld[1] :=dwCount_InX[1]; (* start value for next measure *)
  dwIntHisto[2,wIndex] := dwCount_InX[2] - dwCount_InXOld[2]; (* IN2 interrupts of last 1000 *)
  dwCount_InXOld[2] :=dwCount_InX[2]; (* start value for next measure *)
  dwIntHisto[3,wIndex] := dwCount_InX[3] - dwCount_InXOld[3]; (* IN3 interrupts of last 1000 *)
  dwCount_InXOld[3] :=dwCount_InX[3]; (* start value for next measure *)
  wIndex := wIndex + 1; (* increase index *)
  IF wIndex > cbyDC541_MaxHist THEN wIndex := 0; END_IF; (* reset index, if >1000 *)
END_IF; (* 1000 Interrupts *)  

After this, the block DC541_INT_IN is called to identify the interrupt source and then the interrupt counters of the channels are updated depending on the outputs of this block.

(* Read interrupt source –> if output  = TRUE –> interrupt since last call *)

DC541_IntSource(EN := TRUE, SLOT := cbyDC541_SLOT);

(* count the interrupts for each interrupt input C0..C3 *)

dwCount_InX[0] := dwCount_InX[0] + BOOL_TO_DWORD(DC541_IntSource.IN0);

dwCount_InX[1] := dwCount_InX[1] + BOOL_TO_DWORD(DC541_IntSource.IN1);

dwCount_InX[2] := dwCount_InX[2] + BOOL_TO_DWORD(DC541_IntSource.IN2);

dwCount_InX[3] := dwCount_InX[3] + BOOL_TO_DWORD(DC541_IntSource.IN3);

dwCount_InX[4] := dwCount_InX[4] + BOOL_TO_DWORD(DC541_IntSource.IN4);

In case of an interrupt on channel 4, the counters are reset.

IF DC541_IntSource.IN4 THEN (* Input channel C4 = TRUE *)
  dwIntCount := dwIntCountOld := 0; (* reset count all interrupts *)
  FOR byInd := 0 TO cbyDC541_IntInp-1 DO (* reset channel interrupt counters C0..C3 *)
  dwCount_InX[byInd] := dwCount_InXOld[byInd] := 0;
  END_FOR; (* byInd *)  
  wIndex := 0; (* start historical data from 0 *)
END_IF; (* C4 = TRUE *)  

At the end, the static inputs and outputs are processed, i.e.:

  • reading the inputs,
  • execution of actions
  • writing the outputs.
(* Read inputs of DC541 *)    
DC541_IOs(EN := TRUE, SLOT := cbyDC541_SLOT );    
     
DC541_IOs.OUT6 := DC541_IOs.IN5; (* C6 := state of input channel C5 *)  
DC541_IOs.OUT7 := NOT DC541_IOs.OUT7; (* toggle channel C7 *)  
     
(* Write outputs to DC541*)    
DC541_IOs(EN := TRUE, SLOT := cbyDC541_SLOT);    

Purpose of the cyclic program PLC_PRG:

The cyclic program PLC_PRG contains the following functions:

  • Cycles counter dwC := dwC + 1;
  • Reading the configuration of the DC541 Calling of block DC541_GET_CFG
  • Reading the status of the DC541 Calling of block DC541_STATE - Reading/writing the static channels of the DC541 Calling of block DC541_IO
  • Simulation of the interrupts for the DC541 Calling of block Simu_Pulse

The blocks DC541_GET_CFG, DC541_STATE and DC541_IO are contained in the library DC541_AC500_V11.lib and described in detail in the library documentation DC541_Library: DC541 Library

The block Simu_Pulse is used to generate an adjustable number of pulses. Its representation in the function block diagram (FBD) is as follows:

../_images/a569c3fae38b5a070a33139000eba54e

The meanings of the block’s inputs and outputs are as follows:

Instance   fbSimuPulse Instance name
bEn Input/Output BOOL Enabling of the pulse output
bAutoReset Input/Output BOOL Automatic reset of the pulse counter after the specified number of pulses have been output and after expiration of tResetTime
bReset Input/Output BOOL Reset of the pulse counter
tResetTime Input/Output TIME Time until the reset is initiated after the specified number of pulses is reached, if bAutoReset = TRUE
dwPulse Input/Output DWORD

Number of pulses to be output:

=0: Endless mode (pulse output continues until bEn = FALSE or bReset = TRUE

> 0: Cyclic mode (output of the specified number of pulses)

bDone Output BOOL Completion message after tResetTime has expired or bReset = TRUE for 1 cycle
bToggle_0 Output BOOL Provides a FALSE->TRUE edge with each 2nd call (i.e. the output is toggled with each call)
bToggle_1 Output BOOL Provides a FALSE->TRUE edge with each 4th call
bToggle_2 Output BOOL Provides a FALSE->TRUE edge with each 8th call
bToggle_3 Output BOOL Provides a FALSE->TRUE edge with each 16th call
dwActPulse Output DWORD Displays the number of pulses output (corresponds to the number of edges at bToggle_0)
tActTime Output TIME Displays the elapsed time while tResetTime is running

In the example, bEn: = bAutoReset: = TRUE. 10000 pulses are output (dwSetPulse). After the specified number of pulses has been reached, a wait time of 10 seconds is applied and then counting is started from the beginning.

The example has a visualization implemented which can be used to operate the program. After 10000 pulses, the visualization looks as follows:

9375 interrupts are generated:

5000 x C0 + 2500 x C1 + 1250 x C2 + 625 x C3 = 9375

Act Pulse Triggers the following interrupts:
Value

IN 3

8

IN 2

4

IN 1

2

IN 0

1

0 0 0 0 0 none
1 0 0 0 1 IN 0 -> in every 2. cycle (10000 : 2 = 5000)
2 0 0 1 0 IN 1 -> in every 4. cycle (10000 : 4 = 2500)
3 0 0 1 1 IN 0
4 0 1 0 0 IN 2 -> in every 8. cycle (10000 : 8 = 1250)
5 0 1 0 1 IN 0
6 0 1 1 0 IN 1
7 0 1 1 1 IN 0
8 1 0 0 0 IN 3 -> in every 16. cycle (10000 : 16 = 625)
9 1 0 0 1 IN 0
10 1 0 1 0 IN 1
11 1 0 1 1 IN 0
12 1 1 0 0 IN 2
13 1 1 0 1 IN 0
14 1 1 1 0 IN 1
15 1 1 1 1 IN 0
16 0 0 0 0 none
../_images/6172f1d8e38b59b90a33139000eba54e