Get time format [mm:ss.ms] from Software Timers

Hello People, this thread is more about programming doubts and betters ways to do such a thing like a stopwatch with this format: [mm:ss.ms]

I want to avoid to use millis() because is related to system execution and this is less accurate, and I think that using Software Timers will be better to get what I am trying to get.

Basically starting from the example:

// EXAMPLE

void print_every_second()
{
    static int count = 0;
    Serial.println(count++);
}

Timer timer(1000, print_every_second);

void setup()
{
    Serial.begin(9600);
    timer.start();
}

I want to change the period from 1000 to 100 which I think must be instead of 1 second, 100 milliseconds.

How can I get this kind of format data counting up my timer from the software timers feature?

I was starting to go with something like:

char time_string[] = {'0', '0', ':', '0', '0', '.', '0', '\0'};

void print_every_millisecond() {
    timer_ms++;
    time_string[0] = timer_ms / 60 / 10 + '0';
    time_string[1] = timer_ms / 60 % 10 + '0';
    time_string[3] = timer_ms % 60 / 10 + '0';
    time_string[4] = timer_ms % 60 % 10 + '0';
    time_string[6] = timer_ms % 60 % 10 + '0';
    Serial.println(time_string);
}

Timer timer(100, print_every_millisecond);

void setup() {
    Serial.begin(9600);
    timer.start();
}

But I realize that the way that time is calculated is not correct at all. So I wanted to see if I can get some help debugging how to make it reliable and readable.

Thanks for your time.

@fabocode, what are you trying to achieve? The Photon has a hardware RTC that keeps the time so not sure why you need to use a Software Timer. It can be synchronized with the Cloud to keep accuracy. Take a look at the docs on Time. :wink:

1 Like

The only issue with the Cloud synchronization is because I will not going to have an internet connection to synch with the cloud. But if I work with the RTC from the Photon I think that could work, I still will require to get the time format that I previously said: [mm:ss.ms] and this will work as a stopwatch to measure time for different kind of events.

The RTC has only got a 1sec resolution so in order to get milliseconds, you'd have to normalise the millis() counter to fit the flip of the second on the RTC.

@fabocode, why would you think that Software Timers would be more accuarte than millis()?
The basis for both is the same and interrupts will interfere with the FreeRTOS timing just the same as with the millis() counter.
If you really can't afford to lose single milliseconds, you could go for the micros() count or the fundamental (hardware based) system ticks.
e.g.

   Serial.printlnf("%lu / %lu = %.3fµs", System.ticks(), System.ticksPerMicrosecond(), (double)System.ticks() / System.ticksPerMicrosecond());

BTW, do you need the time of the day or do you only want to measure a timespan?

Once you have your desired base value to convert into a string, this would be one way

  char     sTime[16];
  uint32_t msSpan = now - startTime;
  uint8_t  mm     = msSpan / (60*1000);
  uint8_t  ss     = (msSpan / 1000) % 60;
  uint8_t  ms     = msSpan % 1000;
  snprintf(sTime, sizeof(sTime), "%02d:%02d.%03d", mm, ss, ms);
1 Like

The main problem that I want to solve is that I've a display connected to my Photon and in order to draw to it I need to use delays to avoid wrong behaviours on the display. The timer that I previous made is not running accurately as I think it was.

So I was starting to think on different ways to measure time than using millis(). And the way it works the Software Timers looks very easy to use. However, as you suggest, I might need to look for a different direction.

void runTimer(void)
{
    char time_string[] = {'0', '0', ':', '0', '0', '.', '0', '\0'};
    unsigned long time_ms = (millis() - LastTime) / 100;
    CurrentTime = (millis() - LastTime) / 1000;
    if (CurrentTime >= timeConverted) {
        currentMenu = REST_OPEN_TRAINING;
    }
    time_string[0] = CurrentTime / 60 / 10 + '0';
    time_string[1] = CurrentTime / 60 % 10 + '0';
    time_string[3] = CurrentTime % 60 / 10 + '0';
    time_string[4] = CurrentTime % 60 % 10 + '0';
    time_string[6] = time_ms % 60 % 10 + '0';
    Display.txt_Width(3);      // set size text
    Display.txt_Height(3);     // set size text
    Display.txt_MoveCursor(3, 8);     // moving the cursor to the "center"//selOpt[] = TRAINING_LABEL;
    Display.putstr(time_string);
    Serial.println(time_string);

do you only want to measure a timespan?

on this display I want to show a timespan, yes. The issue is that I think that this delays are making my timer less accurate.

As indicated above millis and micros are derived from a hardware counter that is totally unimpressed by your code, it just counts the clock cycles of the system clock.
If you are not playing around with noInterrupts(), ATOMIC_BLOCK or other “low level” stuff millis() should be accurate enough for your needs.
You’d capture the count at the beginning of your period and then calculate the difference between the current count and the captured count.

But if you don’t trust millis() you can go for System.ticks() and adapt the maths accordingly.