Lesson 22. Work with time in Arduino. A sports stopwatch project.

Time in Arduino

We will consider the Arduino functions for working with time. Develop a sports stopwatch based on the Arduino board.

Previous lesson     List of lessons     Next lesson

There are 4 standard functions for working with time in the Arduino system:

  • delay (time);
  • delayMicroseconds (time);
  • millis ();
  • micros ().

Consider these functions in detail.

 

void delay (unsigned long time)

The function suspends the program for the time specified in ms.

delay (500); // pause for 0.5 seconds

We have already used this function in previous lessons.  More often it is used in debugging programs. In practical programs, the function is rarely used.

The fact is that it stops the program. The program does nothing for a given interval of time. This is not a permissible luxury, only valid in debug modes.

In addition, the function does not allow you to create cycles that exactly work out the specified time. For example, the time of the next cycle will not be exactly 100 ms.

while (true) {
  // code of the program block
  delay (100);
}

The cycle time is equal to the sum: the specified time 100 ms, the execution time of the program block and the transition time to the beginning of the while() cycle. The program block time may vary depending on the program execution algorithm. The transition time to the beginning of the cycle is also not defined exactly. As a result, the cycle time can only be determined approximately.

For the organization of cycles with a given time, it is better to use a timer interrupt (lesson 10). It is only necessary to understand that this method provides a stable cycle time, but it may differ slightly from the specified one. For example, the MsTimer2 library sets the time in ms. Real time may differ by a few µs. In some applications, for example in a clock, the error can accumulate and lead to unacceptable errors.

 

void delayMicroseconds (int time)

The function suspends the program for the time specified in μs.

delayMicroseconds (50); // pause for 50 µs

The analogue of the function delay (), only provides shorter program stops. It is quite acceptable for use in practical programs for two reasons.

  • Short periods of time are difficult to implement with other methods.
  • Stopping the program even for several tens of microseconds will not cause disastrous consequences.

 

unsigned long millis (void)

The function returns the time in ms, since the start of the current program. The time value overflows after 1193 hours, approximately 50 days.

tm = millis (); // read time in tm

In fact, this is a function of reading the Arduino system time. The time is counted in a parallel process and does not depend on the algorithms of program execution, stops, including the function delay(), etc. To measure a time interval, it is necessary to read the system time at the beginning and end of the interval and calculate the difference of these values. Below is an example of a program for working with time intervals.

Disabling interrupts with the noInterrupts() function for a long time may disrupt the system clock.

 

The accuracy of the millis () function.

The accuracy of the time counting by the millis() function is determined by the accuracy and stability of the frequency of the Arduino board quartz resonator. Even for cheap resonators, the frequency error does not exceed 30 ppm. Together with temperature instability, under normal conditions, it is 50 ppm, which corresponds to ± 0.00005%. Thus, the total absolute error of the Arduino system time will be:

  • 0.18 seconds for 1 hour;
  • 4.32 seconds for the day;
  • 129.6 seconds for a month;
  • 26 minutes for the year.

Probably quite acceptable accuracy for creating timers, stopwatches and even clocks.

 

unsigned long micros (void)

The function returns the time in μs since the start of the current program. The value overflows in about 70 minutes.

tm = micros (); // read time in tm

For Arduino boards with a clocking frequency of 16 MHz, the resolution of the value of the micros() function is 4 μs. For boards with a frequency of 8 MHz - 8 μs.

 

A sports stopwatch based on the Arduino board.

We implement a fairly simple project - a stopwatch. Probably, the practical application of such a device is limited. The stopwatch with power from the ac network has the right to exist only in stationary devices. In the scoreboard for sports competitions, in systems for intellectual games, etc. But having understood the program, you can easily correct the stopwatch for your tasks or create a completely different device.

The stopwatch is controlled by two buttons:

  • START / STOP;
  • RESET.

After pressing the START / STOP button, the stopwatch starts counting down the time. Pressing this button again stops the counting. The next press continues the countdown from the stopped value. Thus, the stopwatch can be used to count the “pure” playing time of sports competitions.

To reset the time, you must press the RESET button.

The time is displayed on a four-digit seven-segment display in the following formats.

Time value Digit 3 Digit 2 Digit 1 Digit 0
0 … 59 seconds seconds hundredths of a second
1 … 10 minutes minutes seconds tenths of a second
10 … 99 minutes minutes seconds
More than 99 minutes - - - -

The output format changes automatically depending on the time value. Minutes, seconds and the fractional part are separated on the indicator by decimal points. Pressing the buttons are accompanied by beeps.

 

The scheme of the sports stopwatch based on the Arduino UNO R3 board.

According to the already well-known circuits, we connect to the Arduino board:

  • 4-digit seven-segment LED display GNQ-3641BUE;
  • two buttons;
  • sound piezo emitter.

A sports stopwatch circuit based on Arduino

All of these components may be different. If you are developing a stopwatch for a sports scoreboard, the display should be large. You can even assemble it from individual LEDs. How to connect the display to the board can be found in lesson 19.

If the stopwatch control buttons are physically located at a considerable distance from the board, then it is better to connect them according to the security alarm scheme, lesson 17. Or at least connect the inputs of the buttons with + 5 V power through 1 kΩ resistors.

But for debugging and checking the program is enough of the above scheme. I assembled it on a breadboard.

An Arduino based sports stopwatch

 

The program for the sports stopwatch on Arduino.

The sketch of the program can be downloaded from this link.

Do not forget to install the libraries from previous lessons:

The sketch for the stopwatch looks like this.

// sports stopwatch
#include <MsTimer2.h>
#include <Led4Digits.h>
#include <Button.h>

#define SOUND_PIN 18 // sound emitter pin, pin 18 (A4)

// the display type 1; digit pins 5,4,3,2; segment pins 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

Button buttonReset(16, 10); // RESET button, pin 16 (A2)
Button buttonStartStop(17, 10); // START / STOP button, pin 17 (A3)

byte mode= 0; // mode, 0 - STOP, 1 - START
unsigned long msTime=0; // time of interval, milliseconds
byte minTime=0; // time of interval, minutes
byte decMinTime=0; // time of interval, tens of minutes
unsigned long prevTime; // previous time value
unsigned long curentTime; // current time value
byte soundCount=0; // sound time counter

void setup() {
  MsTimer2::set(2, timerInterrupt); // timer interrupts 2 ms
  MsTimer2::start(); // enable interrupt
  pinMode(SOUND_PIN, OUTPUT); // sound emitter pin
}

void loop() {

//----------------------- switching the START / STOP mode
  if ( buttonStartStop.flagClick == true ) {
    buttonStartStop.flagClick= false; // reset sign
    // mode inversion
    if ( mode == 0) {
      mode= 1; // START
      soundCount= 250; // sound for start of 250 * 2 ms
    }
    else { // STOP
    mode= 0;
    soundCount= 50; // sound on stop 50 * 2 ms
    }
  }

  //----------------------- RESET button
  if ( buttonReset.flagClick == true ) {
    buttonReset.flagClick= false; // reset sign
    msTime=0;
    minTime=0;
    decMinTime=0;
    soundCount= 50; // sound on reset 50 * 2 ms
  }

  //----------------------- time counting
  if ( mode == 0 ) {
    // STOP
    prevTime= millis();
  }
  else {
    // START
    curentTime= millis(); // read current time
    msTime += curentTime - prevTime; // add time to milliseconds
    if ( msTime > 59999 ) {
      // milliseconds overflowed, more than a minute
      msTime -= 60000;
      minTime ++; // +1 to minutes
      if ( minTime > 9 ) {
        // units of minutes overflowed
        minTime -= 10;
        decMinTime ++; // +1 to tens of minutes
      }
    }
    prevTime= curentTime; // overload previous time
  }

  //--------------------- display time
  if ( (minTime == 0) && (decMinTime == 0)) {
    // less than a minute
    disp.print(msTime / 10, 4, 0); // output four digits of milliseconds
    // points
    disp.digit[0] &= 0x7f; // extinguish
    disp.digit[1] &= 0x7f; // extinguish
    disp.digit[2] |= 0x80; // light
    disp.digit[3] &= 0x7f; // extinguish
  }
  else if ( decMinTime == 0 ) {
    // less than 10 minutes
    disp.print(msTime / 100, 3, 0); // output three digits of milliseconds
    disp.tetradToSegCod(3, minTime); // units of minutes output to the high digit
    // points
    disp.digit[0] &= 0x7f; // extinguish
    disp.digit[1] |= 0x80; // light
    disp.digit[2] &= 0x7f; // extinguish
    disp.digit[3] |= 0x80; // light
  }
  else if ( decMinTime < 10 ) {
    // less than 100 minutes
    disp.print(msTime / 1000, 2, 0); // output two digits of milliseconds
    disp.tetradToSegCod(3, decMinTime); // output of tens of minutes to the high digit
    disp.tetradToSegCod(2, minTime); // output units of minutes to 3 digit
    // points
    disp.digit[0] &= 0x7f; // extinguish
    disp.digit[1] &= 0x7f; // extinguish
    disp.digit[2] |= 0x80; // light
    disp.digit[3] &= 0x7f; // extinguish
  }
  else {
    // more than 100 minutes
    // ----
    disp.digit[0]= 0x40;
    disp.digit[1]= 0x40;
    disp.digit[2]= 0x40;
    disp.digit[3]= 0x40;
  }
}

//----------- interrupt handler 2 ms
void timerInterrupt() {
  disp.regen(); // regeneration of the display
  buttonReset.filterAvarage(); // scanning of button, filtering method by average
  buttonStartStop.filterAvarage(); // scanning of button, filtering method by average

  // sound
  if (soundCount != 0) {
    digitalWrite(SOUND_PIN, ! digitalRead(SOUND_PIN));
    soundCount--;
  }
}

Most of the program is designed according to the principles detailed in previous lessons.

  • Implemented timer interrupt with a period of 2 ms.
  • In the handler, interrupts are called:
    • the display regeneration method;
    • the methods for scanning the button signals;
    • the sound signal block .
  • According to the signs of pressing the buttons occur:
    • mode switching (START / STOP);
    • resetting the time.
  • Depending on the time value in the display unit, the format of data output changes.

I would like to dwell on the program block "time counting". Time counting can be implemented in different ways. For example, you can count the time in milliseconds, and in the display block to do the translation in the desired format. I decided that it was much easier to count time in the format:

  • milliseconds;
  • minutes;
  • tens of minutes.

In this case, it is not necessary to perform binary-decimal conversions to display the minutes. Of course, if we had the task of measuring only one time interval, then it would be enough to read time by the millis() function at the beginning and end of the interval, and then calculate the difference. But we need to accumulate time, so the algorithm is somewhat more complicated.

The program has enough comments. I think you can easily figure it out and be able to create a device for your tasks, be it a sports stopwatch, a system for intellectual games " What? Where? When? ” or ” Brain Ring ” and much more. We will return to the stopwatch and work with time in the development of sports scoreboards based on LED modules.

Previous lesson     List of lessons     Next lesson

Leave a Reply

Your email address will not be published. Required fields are marked *