0

I need to run some code every time the PLC starts. This code should only be run once and then never again until the PLC is restarted. I initialize some global variables and validate the persistent data before allowing the main PLC to run. This is because the actions of the machine can be damaging if some of these variables are not setup correctly.

Is there a way to start/stop the other PLC tasks? I noticed TwinCAT doesn't support initialization and shutdown interrupts for PLC tasks.

DevLocus
  • 55
  • 1
  • 9

2 Answers2

2

TwinCAT has a 'PlcTaskSystemInfo' struct containing a boolean for FirstCycle. You can use that to run the initializing code only once.

VAR fbGetCurTaskIdx: GETCURTASKINDEX; (* Further example+explanation in Infosys *)

fbGetCurTaskIdx();
IF _TaskInfo[fbGetCurTaskIdx.index].FirstCycle THEN
  (* Initialization code here *)
ELSE
  (* Normal code here *)
END_IF;
pboedker
  • 523
  • 1
  • 3
  • 17
  • Interesting! Do you know if FirstCycle is true on Reset Cold/Origin? – Felix Keil Jan 21 '17 at 05:19
  • I'm 99% sure the FirstCycle bit is true on both power up and when using the Reset commands. – pboedker Jan 22 '17 at 16:25
  • @felix-keil The following program demonstrates that FirstCycle is TRUE when using both Rest Cold/Origin (try it with bCheckForFirstCycle initialized to either TRUE or FALSE): `VAR fbGetCurTaskIdx: GETCURTASKINDEX; i: INT := 23; bCheckForFirstScan: BOOL := TRUE; END_VAR; fbGetCurTaskIdx(); IF _TaskInfo[fbGetCurTaskIdx.index].FirstCycle AND bCheckForFirstScan THEN (* Initialization code here *) i := 17; ELSE (* Normal code here *) i := i; END_IF;` – pboedker Jan 22 '17 at 19:16
  • 1
    That is plan B, but it doesn't allow all that an initialization interrupt or program would allow. Most PLCs which have an initialization interrupt/program allow the interrupt/program to violate the normal timing of a cyclic program (e.g. a program with a cycle of 10 ms would allow the initialization program to execute like much longer without a cycle time exception). This is useful for setting up faster running tasks (e.g. a motion control task is 1 ms and the initialization of the drive structures may take 10 ms). – DevLocus Jan 22 '17 at 22:55
  • @DevLocus then take a look at **FB_init**, **FB_reinit**, **FB_exit** available for FunctionBlocks. These methods are not called within the normal task cycles. See [Infosys](https://infosys.beckhoff.com/content/1033/tc3_plc_intro/9007199390945931.html?id=8333023073559976250) – Felix Keil Jan 23 '17 at 14:10
  • This will work if I had only 1 task, but I have multiple that need to wait for all tasks to initialize before going into free run mode. It still looks like I will have to do plan B (a global variable to prevent all tasks from running the free run code until all initialization is complete). – DevLocus Jan 23 '17 at 14:57
0

I don't know of a way to start/stop individual PLC tasks. You can start/stop a runtime though.

But perhaps it can be as simple as this code below, which will only run when your PLC starts.

VAR initialized: BOOL := FALSE;

IF NOT initialized THEN
  (* Run your initialization code here *)
  initialized := TRUE;
END_IF

(* Rest of your program here *)

Edit:

I used a state machine inside the initialization code to help with the task allowed time issue.

Example:

VAR
  Initialized : BOOL := FALSE;
  Init_State  : UINT := 0;
END_VAR

IF NOT Initialized THEN
  (* Initialization State Machine *)
  CASE Init_State OF
    0: (* First step in initialization *)
       Init_State := Init_State + 1;
    1: (* Second step in initialization *)
       Init_State := Init_State + 1;
     .
     .
     .
    n: (* Last step in initialization *)
       Initialized := TRUE;
  END_CASE
END_IF
DevLocus
  • 55
  • 1
  • 9
stevenv
  • 411
  • 3
  • 11