How to call function every Nth seconds in IEC61131-3 structured text (TwinCAT3)?

1.3k views Asked by At

What I want to do in the code?

I want to create a function block that is made up out of 4 methods: start, stop, run, calculate. Start method will call a run method that has an while loop that periodically calls calculate method. The while loop inside the run method will end only if the stop method is called.

What I have tried already:

  1. When I call the object.start() I want it to start a cycle that will go as long as I don't call the stop method.
timer(IN := triggerTimer, PT := T#0.1S);
trigger(CLK := timer.Q);

workingFlag := TRUE;
run();
  1. The cycle will be in the run method. Cycle will consist of a while loop conditioned via workingFlag variable. When workingFlag is True the the while loop will constantly trigger a timer structure which will every 0.1S call the calculate method.
WHILE workingFlag = TRUE DO
    triggerTimer := TRUE; //Start timer
    
    IF trigger.Q THEN //If timer expired execute code below ...
        calculate();
        triggerTimer := FALSE; //Reset the timer
    END_IF;
END_WHILE
  1. Finally the stop method will just set the workingFlag to False and theoretically it would end the cycle in run method.
workingFlag := FALSE;

What is the problem?

  • After I call the object.start() my whole PC crashes. Therefor ... I think something is horribly wrong with my code (:

What I want to achieve with this?

  • The object will be a PID controller. And I want in the main program just call the start method when I want it to regulate and stop when I need it to shut down.
  • To this day I was calling manually the calculate method inside my main program with the timer that you can find in the run method above.
  • My problem with this approach was that when I had more PID's (or another functions I needed to call periodically) the code got messy really quick.
  • Therefor I wanted to create a function block that would have local timers and would be managing the periodical calling by itself.

So please any suggestions how to approach this problem?

2

There are 2 answers

0
Sergey Romanov On BEST ANSWER

Jouke already told you that WHILE is the reason. Here is your code example refactored. This is how it should be done if you want 100 milliseconds impulse work.

timer(IN := TRUE, PT := T#100MS);
IF timer.Q THEN
    calculate();
    timer(IN := FALSE); // reset timer
END_IF;

But remember that your main PLC cycle should not be longer than 100ms.

The object will be a PID controller. And I want in the main program just call the start method when I want it to regulate and stop when I need it to shut down.

Every PID function block has Enable input parameter. You can use that to start and stop PID.

Just set you Start variable to PID function block input, that is it.

0
Jouke Aalvanger On

It crashes because you instruct the PLC to run the while loop forever. The PLC software already runs cyclically (according to your PLCtask). It would be easier to put your code that is inside the while loop into a method (or in the body of the function block) that you call every cycle.

A PLC starts the code from top to bottom. Then 10ms (or other cycletime) later, it executes the same code again from top to bottom. So it's essentially a big while loop already. When running a while loop like in your example, the code enters the while loop, but never exits. Then a watchdog somewhere times out and TwinCAT crashes.