How to create a stopwatch?

open
2023-12-07
2023-12-16
  • open - 2023-12-07

    Hi,

    how to create a stopwatch when start is pressed, timer will start counting and stop is pressed, timer will stop counting in structured text?

     
  • ph0010421 - 2023-12-07
    FUNCTION_BLOCK fbdStopwatch
    VAR_INPUT
        Condition: BOOL;
    END_VAR
    VAR_OUTPUT
        TimeTaken: TIME;
    END_VAR
    VAR
        StartTime: TIME;
        fbiStartOs: R_TRIG;
        fbiStopOs: F_TRIG;
    END_VAR
    

    and then:

    fbiStartOs(CLK := Condition);
    fbiStopOs(CLK := Condition);
    
    IF fbiStartOs.Q THEN StartTime := TIME(); END_IF;
    IF fbiStopOs.Q THEN TimeTaken := TIME() - StartTime; END_IF;
    
     
  • open - 2023-12-08

    Hi @ph0010421,

    I tried the program the TimeTaken is calculated when stop is triggered. I want the TimeTaken to be continuously calculated and counting when a BOOL variable is true.

    I tried to program this way:
    Declaration:

    PROGRAM PLC_PRG
    VAR
        bStartStop: BOOL := FALSE;    // Start/Stop button
        bReset: BOOL := FALSE;        // Reset button
        bRunning: BOOL := FALSE;      // Flag indicating whether the stopwatch is running
        tStartTime: TIME;             // Variable to store the start time
        tElapsedTime: TIME;           // Variable to store the elapsed time
    END_VAR
    

    Implementation:

    // Main program logic
    IF bReset THEN
        // Reset button pressed, reset the stopwatch
        bRunning := FALSE;
        tElapsedTime := T#0s;
    ELSIF bStartStop THEN
        // Start/Stop button pressed, toggle the running state
        IF bRunning THEN
            // Stop the stopwatch
            bRunning := FALSE;
        ELSE
            // Start the stopwatch
            bRunning := TRUE;
            tStartTime := tElapsedTime;
        END_IF;
    END_IF
    
    // Update the elapsed time when the stopwatch is running
    IF bRunning THEN
        tElapsedTime := tElapsedTime + T#1s; // Adjust the time increment as needed
    END_IF
    

    However counting of the seconds is not accurate. I tried changing the main task cycle time interval to 1000ms. The counting of seconds become slower. (see attached)

    Please help

     
  • ph0010421 - 2023-12-08

    Do you need an 'hours-run' counter? And 1 second resolution is ok? I think you're over-thinking it.
    (The task time needs to be < 1second)

    Have a look at the LAD...
    Then, the time in seconds can be made into hh:mm:ss with this FUNction
    Declarations:

    FUNCTION funSecondsToStringTime: string 
    VAR_INPUT
        InSeconds: UDINT;
    END_VAR
    VAR
        AsString: STRING;
        Minutes: UDINT;
        Hours: UDINT;
        Seconds: UDINT;
        MinutesAsString: STRING(2);
        HoursAsString: STRING(2);
        SecondsAsString: STRING(2);
    END_VAR
    

    and the code:

    Hours := InSeconds / 60 / 60;                               //Derive hours
    Minutes := (InSeconds - (Hours * 60 * 60)) / 60;            //Derive minutes
    Seconds := InSeconds - ((Hours * 60 * 60) + (Minutes * 60));//Derive seconds
    HoursAsString := UDINT_TO_STRING(Hours);
    MinutesAsString := UDINT_TO_STRING(Minutes);
    SecondsAsString := UDINT_TO_STRING(Seconds);
    
    IF LEN(HoursAsString) = 1 THEN
        HoursAsString := CONCAT('0',HoursAsString);
    END_IF;
    
    IF LEN(MinutesAsString) = 1 THEN
        MinutesAsString := CONCAT('0',MinutesAsString);
    END_IF;
    
    IF LEN(SecondsAsString) = 1 THEN
        SecondsAsString := CONCAT('0',SecondsAsString);
    END_IF;
    
    AsString := CONCAT(HoursAsString, ':');         //assemble string
    AsString := CONCAT(AsString,MinutesAsString);
    AsString := CONCAT(AsString,':');
    AsString := CONCAT(AsString, SecondsAsString);
    
    funSecondsToStringTime := AsString;
    
     
  • Ton - 2023-12-09

    One i wrote this to measure elepse time

    When xMeasure is true is starts en when false it stops and time is messured.

    FUNCTION_BLOCK FB_ElapseTime
    VAR_INPUT
        xMeasure: BOOL;
    END_VAR
    VAR_OUTPUT
        xRisingEdge: BOOL;
        xFallingEdge: BOOL;
    
        tElapsed: TIME;
        ltElapsed: LTIME;
        ltPrev_Elapsed: LTIME;
        ltElapsedMax: LTIME;
    END_VAR
    VAR
        xLastValue: BOOL;
    
        LTIMEStart: LTIME;
        LTIMEEnd: LTIME;
        tonReset: TON:= (IN:= TRUE, PT:= TIME#30S0MS);
    END_VAR
    -------------------------------------------
    xRisingEdge:= (xLastValue XOR xMeasure) AND xMeasure;
    xFallingEdge:= (xLastValue XOR xMeasure) AND NOT xMeasure;
    IF xRisingEdge THEN
        ltPrev_Elapsed:= ltElapsed;
        LTIMEStart:= LTIME();
    END_IF
    IF xMeasure OR xFallingEdge THEN
        LTIMEEnd:= LTIME(); 
    END_IF
    
    ltElapsed:= LTIMEEnd - LTIMEStart;
    ltElapsedMax:= MAX(ltElapsedMax, ltElapsed);
    tElapsed:= LTIME_TO_TIME(ltElapsed);
    
    xLastValue:= xMeasure;
    
    tonReset();
    IF tonReset.Q THEN
        tonReset.IN:= FALSE;
        ltElapsedMax:= LTIME#0NS;
    END_IF
    

    Meaby this will help.

     
  • open - 2023-12-11

    Hi @ph0010421 and @Ton,

    Is it possible to program a stopwatch to measure a system running time when it is turn on, and pause when the system is turn off. I tried your examples when stopped, the elapsed time will then be calculated, but i need the time to be continuously counting.

    Warmest regards,

     
  • Ton - 2023-12-12

    Hi,

    i guess you want to make a hour counter.

    You need to store the measured value.
    Try to use a retain variable, but need a graceful shutdown, or save it your self.
    see https://forge.codesys.com/forge/talk/Runtime/thread/278e325579/

    Succes.

     
  • open - 2023-12-14

    Thanks everyone for your input,

    I am using persistent variables to retain the timer value after machine shutdown, and main task to be as low as possible for the seconds TON to be accurate.

     
  • Ton - 2023-12-16

    If you use LTIME() you will be very accurate and be able to have a normal task cycle time.

     

Log in to post a comment.