- HMI Model: CMT3072
- EasyBuilder Pro Version: 6.10
- How do I create a running elapsed time timer using a macro? Or is there a better way of displaying elapsed time?
Hi @leadfoote ,
One way to display elapsed time is by using the timer object, which can be found under the Object tab. If you want the timer to work across all windows, select the global version; if you only need it on one page, choose the per-page timer.
For the Mode of the timer, I recommend selecting either On delay or Accumulated On delay. Both will start the timer when the input bit is turned ON. The key difference is that Accumulated On delay retains the elapsed time when the input bit is turned off before ET reaches the PT. When On delay is used and the input bit is turned off before ET reaches the PT, the ET will reset to 0.
Additionally, enable the Elapsed time memory register to view the elapsed time, and assign it to a free memory register. You will also need to set a Preset time, which determines the maximum value your timer will count to. The maximum value for the preset timer is 86400 seconds. This can be a constant value or linked to a memory register for dynamic control.
Please let me know if this solution meets your project goals. If not, could you please describe how you are want to record the elapsed time? That way, we can recommend the best approach for your needs.
Thanks for getting back to me!
I need to show elapsed time for much longer than 24 hours possibly weeks. I was thinking I may have to use the timer combined with a counter? Maybe I need to use a macro? Thanks
Hi @leadfoote ,
Yes, if you wanted to hold weeks, it would be a combination of the timer object and macros. I was curious about how precise you needed the count to be. Are you only displaying the weeks and days, or something finer like hours, minutes, and seconds for your elapsed time?
Thank you!
I need to display days, hours, minutes and seconds.
Hi @leadfoote,
Yes, you were correct , using macros was the best solution, as we can utilize the HMI’s system time to calculate the elapsed time. The system time can be accessed through LW-9030, which is a system address tag.
Below is the macro we used. It sets up variables for the start time (at the beginning of execution) and the current time. By subtracting these values, we get the elapsed time. Dividing the result by 10 modifies the value into seconds as the periodical execution is set to 10x100ms . We then display the hours, minutes, and seconds using division and modulus operations.
Additionally, a toggle switch is set at LB-0 to reset the values and start the timer when needed. To achieve this, we store the start value in LW-8999.
Here is also the project if needed: Project
macro_command main()
// Variable Set up
unsigned int start = 0, now = 0, result = 0
bool trigger
short total_seconds, hours, minutes, seconds
// Grab the trigger and start values from HMI memory address
GetData(trigger, "Local HMI", LB, 0,1)
GetData(start, "Local HMI", LW, 8999, 1)
// Trigger is LB 0 to start the timer
if trigger then
// check if start is 0, if it is grab the time for current and place it within a HMI memory address.
if start == 0 then
GetData(start, "Local HMI", LW, 9030, 1)
SetData(start, "Local HMI", LW, 8999, 1)
end if
// grab the current value.
GetData(now, "Local HMI", LW, 9030, 1)
result =now - start
// calc hour, minute, second based on result / 10
// ADD more calucations here for days, weeks and years if needed.
// set the seconds
total_seconds = result/10
seconds = total_seconds %60
SetData(seconds, "Local HMI", LW, 0, 1)
// set the mins
minutes = (total_seconds % 3600)/60
SetData(minutes,"Local HMI",LW,1,1)
// set the hours
hours = total_seconds /3600
SetData(hours,"Local HMI",LW,2,1)
else // if trigger is off, then reset all values back to default values
start =0
SetData(start, "Local HMI", LW, 8999, 1)
end if
end macro_command
AaronS
Thank you for your help! I spent three days working on this and couldn’t figure it out, you guys are miracle workers!
Hi @leadfoote ,
We are glad this solution worked for your project! Please don’t hesitate to reach out if any other questions come up!
All the best!
Aaron,
I actually have one more question. How do I combine the hour, minute and seconds and display them on one line? Displayed like 12:34:56 HR:MIN:SEC
Hi @leadfoote
To combine the hours, minutes, and seconds within one line or memory space, we need to convert the integer values of each variable to strings. We can then take these strings and concatenate them into the correct format. Within our macro function, we have the DEC2ASCII function, which will convert integers to ASCII values for us. Then we can use the StringCat function to format all the strings in the desired order.
Please note that within the code below, I placed the final version of the string within the char
array named answer. Then I used the StringSet function to place the correctly formatted string within the LW-20 memory address. This is tied to an ASCII object.
ADDED CODE
// make the correct string //
// place holders for the string versions of hour,min, and seconds.
char hour_char[10]
char minutes_char[10]
char seconds_char[10]
// place int to ascii values within the char arrays
// The DEC2ASCII function will turn the int values into strings for us to use later.
DEC2ASCII(hours, hour_char[0], 2)
DEC2ASCII(minutes, minutes_char[0], 2)
DEC2ASCII(seconds, seconds_char[0], 2)
// make the correct string place in ascii object
char answer[100] // final string that will hold the string to set to LW 20
char colon[2] = ":" // colon to add to string
// get the correct string -> 00:00:00
StringCat(hour_char[0], answer[0]) // placing hour in string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(minutes_char[0], answer[0]) // placing minutes in the string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(seconds_char[0], answer[0]) // placing seconds in the string
// Placing string in LW 20
StringSet(answer[0], "Local HMI", LW, 20, 14) // to add in more to the string update the size of 14 to a higher number
FULL CODE
macro_command main()
// Variable Set up
unsigned int start = 0, now = 0, result = 0
bool trigger
short total_seconds, hours, minutes, seconds
// Grab the trigger and start values from HMI memory address
GetData(trigger, "Local HMI", LB, 0,1)
GetData(start, "Local HMI", LW, 8999, 1)
// Trigger is LB 0 to start the timer
if trigger then
// check if start is 0, if it is grab the time for current and place it within a HMI memory address.
if start == 0 then
GetData(start, "Local HMI", LW, 9030, 1)
SetData(start, "Local HMI", LW, 8999, 1)
end if
// grab the current value.
GetData(now, "Local HMI", LW, 9030, 1)
result =now - start
// calc hour, minute, second based on result / 10
// ADD more calucations here for days, weeks and years if needed.
// set the seconds
total_seconds = result/10
seconds = total_seconds %60
SetData(seconds, "Local HMI", LW, 0, 1)
// set the mins
minutes = (total_seconds % 3600)/60
SetData(minutes,"Local HMI",LW,1,1)
// set the hours
hours = total_seconds /3600
SetData(hours,"Local HMI",LW,2,1)
// make the correct string //
// place holders for the string versions of hour,min, and seconds.
char hour_char[10]
char minutes_char[10]
char seconds_char[10]
// place int to ascii values within the char arrays
// The DEC2ASCII function will turn the int values into strings for us to use later.
DEC2ASCII(hours, hour_char[0], 2)
DEC2ASCII(minutes, minutes_char[0], 2)
DEC2ASCII(seconds, seconds_char[0], 2)
// make the correct string place in ascii object
char answer[100] // final string that will hold the string to set to LW 20
char colon[2] = ":" // colon to add to string
// get the correct string -> 00:00:00
StringCat(hour_char[0], answer[0]) // placing hour in string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(minutes_char[0], answer[0]) // placing minutes in the string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(seconds_char[0], answer[0]) // placing seconds in the string
// Placing string in LW 20
StringSet(answer[0], "Local HMI", LW, 20, 14) // to add in more to the string update the size of 14 to a higher number
else // if trigger is off, then reset all values back to default values
start =0
SetData(start, "Local HMI", LW, 8999, 1)
end if
end macro_command
Aaron,
When I implemented the code, it created the ASCII object like its supposed to but it only counts for one cycle and stops at 7sec and when the trigger is released and enabled again it doesn’t reset back to zero. sorry to keep bothering you with this, I’m really new to macros, I’m trying to learn.
Hi @leadfoote
No bother at all, we truly appreciate all the questions coming in!
Regarding the reset issue, please make sure to enable “Auto initialize variable” in the Macro Manager settings. This should ensure your variables reset as expected.
For your reference, here’s a link to the updated project I’m working from: Updated Project
Please let me know if you have any other questions!
Got it, that worked! Thank you!
Aaron,
I had another scenario come up.
Is it possible to have the timer pause and hold its value when the “trigger” is off and then pickup in the same spot when the trigger is on again? And use another bit to “reset” back to zero? Like if the process needs to be paused for a moment but not have the timer reset to zero when restarted.
Hi @leadfoote
Below is a rough template that works to set the start and pause on LB-0 and reset on LB-2. Modification still may be needed.
macro_command main()
// === Variable Setup ===
unsigned int start = 0, now = 0, result = 0, paused_elapsed = 0
bool trigger, was_paused, reset
short total_seconds, hours, minutes, seconds
bool t = true, f = false
int hold = 0
char colon[2] = ":"
// === Read HMI values from memory registers ===
GetData(trigger, "Local HMI", LB, 0, 1) // Pause/Run toggle
GetData(was_paused, "Local HMI", LB, 1, 1) // Pause flag
GetData(reset, "Local HMI", LB, 2, 1) // Reset button
GetData(start, "Local HMI", LW, 8999, 1) // Stored start time
GetData(paused_elapsed,"Local HMI", LW, 8998, 1) // Elapsed at pause
GetData(now, "Local HMI", LW, 9030, 1) // System clock (0.1s units)
// === RESET LOGIC ===
if reset == 1 then
start = 0
paused_elapsed = 0
result = 0
SetData(start, "Local HMI", LW, 8999, 1)
SetData(paused_elapsed, "Local HMI", LW, 8998, 1)
SetData(f, "Local HMI", LB, 1, 1) // clear was_paused
// clear numeric display
SetData(hold, "Local HMI", LW, 0, 1)
SetData(hold, "Local HMI", LW, 1, 1)
SetData(hold, "Local HMI", LW, 2, 1)
char time_answer[100]
// clear string display
time_answer[0] = 0
char time_char[10] = "00"
StringCat(time_char[0], time_answer[0]) // placing hour in string
StringCat(colon[0], time_answer[0]) // adding a colon
StringCat(time_char[0], time_answer[0]) // placing minutes in the string
StringCat(colon[0],time_answer[0]) // adding a colon
StringCat(time_char[0], time_answer[0]) // placing seconds in the string
StringSet(time_answer[0], "Local HMI", LW, 20, 14)
return
end if
// === RUN / PAUSE LOGIC ===
if trigger == 1 then
// running
if was_paused == 1 then
// resume: adjust start so elapsed == paused_elapsed
start = now - paused_elapsed
SetData(start, "Local HMI", LW, 8999, 1)
SetData(f, "Local HMI", LB, 1, 1) // clear was_paused
end if
// initialize on first run
if start == 0 then
start = now
SetData(start, "Local HMI", LW, 8999, 1)
end if
// update elapsed
GetData(now, "Local HMI", LW, 9030, 1)
result = now - start
else // paused
if start <> 0 and was_paused == 0 then
// capture elapsed
paused_elapsed = now - start
SetData(paused_elapsed, "Local HMI", LW, 8998, 1)
SetData(t, "Local HMI", LB, 1, 1)
end if
if start <> 0 then
result = paused_elapsed
end if
end if
// === TIME CONVERSION & DISPLAY ===
total_seconds = result / 10
seconds = total_seconds % 60
minutes = (total_seconds % 3600) / 60
hours = total_seconds / 3600
SetData(seconds, "Local HMI", LW, 0, 1)
SetData(minutes, "Local HMI", LW, 1, 1)
SetData(hours, "Local HMI", LW, 2, 1)
// === TIME STRING BUILD ===
char hour_char[10]
char minutes_char[10]
char seconds_char[10]
char answer[100]
DEC2ASCII(hours, hour_char[0], 2)
DEC2ASCII(minutes, minutes_char[0], 2)
DEC2ASCII(seconds, seconds_char[0], 2)
answer[0] = 0
// get the correct string -> 00:00:00
StringCat(hour_char[0], answer[0]) // placing hour in string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(minutes_char[0], answer[0]) // placing minutes in the string
StringCat(colon[0], answer[0]) // adding a colon
StringCat(seconds_char[0], answer[0]) // placing seconds in the string
// Placing string in LW 20
StringSet(answer[0], "Local HMI", LW, 20, 14) // to add in more to the string update the size of 14 to a higher number
end macro_command
Aaron,
I appreciate your help so much! With some minor modifications I was able to get this to work for me. Thanks again!