Warm tip: This article is reproduced from serverfault.com, please click

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

发布于 2021-01-25 13:14:05

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?

Questioner
Jakub Szlaur
Viewed
0
463 2021-02-07 15:29:36

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.