创建定时循环结构化文本

Create Timed For Loop Structured Text

我正在尝试创建一个具有时间延迟的 FOR TO 循环。但它似乎无法正常工作我无法弄清楚错误在哪里,但似乎循环 运行s 完全没有考虑时间延迟。

FOR vCount := 0 TO 800 DO

fbBlink(ENABLE := TRUE, TIMELOW := T#1s, TIMEHIGH := T#1s, OUT => bSignal);

    IF bSignal THEN
        vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));
    END_IF

END_FOR

所以我预计这个循环会占用 801 秒。因此,每一秒都有一个新值被添加到数组中。但是当我 运行 代码在短时间后(例如 1 秒)我已经在数组中有 801 个值,所以计时器不工作。

我已经用 TON 尝试过代码,现在我在这个论坛上找到了 FB Blink,但它仍然不起作用。

谁能帮帮我

BINKTON 不像“等待”或“延迟”那样工作,程序将卡在上面直到到达时间)。当时间到时,将触发输出位(Q、OUT、OUTPUT 或其他取决于您使用的库),但您应该在每个程序周期处理它,连续地等待输出。

更好的处理PLC程序的方法是它永远不应该停止,它应该总是运行,然后在流程中做出决定。

因此,由于这个延迟,FOR 不是最好的方法...状态机是您可以使用的一个好概念。

由于您没有指定程序的启动方式,它包含一个 bStart 位来控制何时开始循环。

VAR
    bStart : BOOL;
    vVsample : ARRAY [0 .. 800] OF REAL;
    vVin : WORD;
    fbTon : TON;
    bStartTimer : BOOL := FALSE;
    vCount : INT := 0;
    vState : INT := 0;
END_VAR


//The timer is processed continuously 
fbTon(IN := bStartTimer, PT := T#1S);

//State Machine
CASE vState OF

    0 : //Start the Timer
        
        IF bStart THEN
            bStartTimer := TRUE;    
            //Go to State 10 (Wait Timer)   
            vState := 10;
        END_IF
        
    10 : //Wait for the timer
        
        IF fbTon.Q AND vCount <= 800 THEN
            //Set value and increment counter
            vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));         
            vCount := vCount + 1;           
            //Reset the timer in the next cycle
            bStartTimer := FALSE;           
            //Return to state 0
            vState := 0;
        END_IF
        
        //Checks if reached the end of the array
        IF vCount > 800 THEN
            //reset flags
            bStartTimer := FALSE;   
            bStart := FALSE;
            vCount := 0;
            //Return to state 0
            vState := 0;
        END_IF
        
END_CASE

您似乎对 CODESYS 运行 代码的使用方式存在误解。与 C/C++ 等代码从上到下执行一次的语言不同,在 codesys 中,代码每秒执行多次,只要控制器有电(在我工作的 PLC 上,它被执行每 20 毫秒,换句话说,每秒 50 次)。

因此,您无法拥有 stall/delay 执行的函数。计时器在 CODESYS 中的实际作用是,它们会记住您第一次调用它们的时间,然后在每次调用时它们只会检查经过了多少时间(它们不会停止!)。一旦设定的时间过去,他们会在他们的输出上升起一个标志,这样你就可以执行一些任务。

所以让我们分解一下当您 运行 您的代码时会发生什么:

// first run:
FOR vCount := 0 TO 800 DO
    // on first itewration (vCount = 0) this will remember the current time,
    // however it won't stop here and it will continue to the next line.
    // on next iterations (vCount >= 1) the timer will check the elapsed time,
    // which will be 0, so it will do nothing and continue to the next line.
    fbBlink(ENABLE := TRUE, TIMELOW := T#1s, TIMEHIGH := T#1s, OUT => bSignal);
    // the timer just started so bSignal is FALSE
    IF bSignal THEN
        vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));
    END_IF
END_FOR

// second run:
FOR vCount := 0 TO 800 DO
    // the timer will compare current time to the recorded first time.
    // the elapsed time is below the target, so skip to the next line.
    // this will be repeated 800 times for no good reason...
    fbBlink(ENABLE := TRUE, TIMELOW := T#1s, TIMEHIGH := T#1s, OUT => bSignal);
    // the timer hasn't reached target time so bSignal is FALSE
    IF bSignal THEN
        vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));
    END_IF
END_FOR
// the above will reapeat for another 48 cycles

// 50th run:
FOR vCount := 0 TO 800 DO
    // the timer will compare current time to the recorded first time.
    // the elapsed time has reached the target 1 second (TIMELOW := T#1s),
    // so it will raise the OUT flag to TRUE.
    // the comparison will happen on every 800 iterations, and every time
    // it will be set to TRUE.
    fbBlink(ENABLE := TRUE, TIMELOW := T#1s, TIMEHIGH := T#1s, OUT => bSignal);
    // since bSignal is TRUE on every iteration, ener the if for every element.
    IF bSignal THEN
        vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));
    END_IF
END_FOR

如果您想要每秒向数组添加一个值,那么您可以这样做(请注意,这不会停止/stall/delay 执行和之后的代码这仍将每隔 运行 执行一次。如果不需要,您必须单独处理):

timer(IN := vCount <> 801, PT := T#1S); // timer is TON
IF (timer.Q) THEN
    timer(IN := FALSE); // reset the timer so it starts counting again nextr run
    vVsample[vCount] := INT_TO_REAL(WORD_TO_INT(vVin));
    vCount := vCount + 1; // increment the counter
END_IF