In this article we introduce the millis(); function and put it to use to create various timing examples.

Millis? Nothing to do with lip-syncers… hopefully you recognised milli as being the numerical prefix for one-thousandths; that is multiplying a unit of measure by 0.001 (or ten to the power of negative 3). Interestingly our Arduino systems will count the number of milliseconds (thousands of a second) from the start of a sketch running until the count reaches the maximum number capable of being stored in the variable type unsigned long (a 32-bit [four byte] integer – that ranges from zero to (2^32)-1.

(2^32)-1, or 4294967295 milliseconds converts to 49.71027-odd days. The counter resets when the Arduino is reset, it reaches the maximum value or a new sketch is uploaded. To get the value of the counter at a particular juncture, just call the function – for example:

Arduino

1

start=millis();

Where start is an unsigned long variable. Here is a very simple example to show you millis() in action:

Arduino

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

/*

Example 37.1 - millis() demonstration

http://tronixstuff.com/tutorials > chapter 37

John Boxall | CC by-sa-nc

*/

unsignedlongstart,finished,elapsed;

voidsetup()

{

Serial.begin(9600);

}

voidloop()

{

Serial.println("Start...");

start=millis();

delay(1000);

finished=millis();

Serial.println("Finished");

elapsed=finished-start;

Serial.print(elapsed);

Serial.println(" milliseconds elapsed");

Serial.println();

delay(500);

}

The sketch stores the current millis count in start, then waits one second, then stores the value of millis again in finished. Finally it calculates the elapsed time of the delay. In the following screen dump of the serial monitor, you can see that the duration was not always exactly 1000 milliseconds:

To put it simply, the millis function makes use of an internal counter within the ATmega microcontroller at the heart of your Arduino. This counter increments every clock cycle – which happens (in standard Arduino and compatibles) at a clock speed of 16 Mhz. This speed is controlled by the crystal on the Arduino board (the silver thing with T16.000 stamped on it):

Crystal accuracy can vary depending on external temperature, and the tolerance of the crystal itself. This in turn will affect the accuracy of your millis result. Anecdotal experience has reported the drift in timing accuracy can be around three or four seconds per twenty-four hour period. If you are using a board or your own version that is using a ceramic resonator instead of a crystal, note that they are not as accurate and will introduce the possibility of higher drift levels. If you need a much higher level of timing accuracy, consider specific timer ICs such as the Maxim DS3232.

Now we can make use of the millis for various timing functions. As demonstrated in the previous example sketch, we can calculate elapsed time. To take this idea forward, let’s make a simple stopwatch. Doing so can be as simple or as complex as necessary, but for this case we will veer towards simple. On the hardware perspective, we will have two buttons – Start and Stop – with the 10k ohm pull-down resistors connected to digital pins 2 and 3 respectively.

When the user presses start the sketch will note the value for millis – then after stop is pressed, the sketch will again note the value for millis, calculate and display the elapsed time. The user can then press start to repeat the process, or stop for updated data. Here is the sketch:

Arduino

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

/*

Example 37.2 – Super-basic stopwatch using millis();

http://tronixstuff.com/tutorials > chapter 37

John Boxall | CC by-sa-nc

*/

unsignedlongstart,finished,elapsed;

voidsetup()

{

Serial.begin(9600);

pinMode(2,INPUT);// start button

pinMode(3,INPUT);// stop button

Serial.println("Press 1 for Start/reset, 2 for elapsed time");

}

voiddisplayResult()

{

floath,m,s,ms;

unsignedlongover;

elapsed=finished-start;

h=int(elapsed/3600000);

over=elapsed%3600000;

m=int(over/60000);

over=over%60000;

s=int(over/1000);

ms=over%1000;

Serial.print("Raw elapsed time: ");

Serial.println(elapsed);

Serial.print("Elapsed time: ");

Serial.print(h,0);

Serial.print("h ");

Serial.print(m,0);

Serial.print("m ");

Serial.print(s,0);

Serial.print("s ");

Serial.print(ms,0);

Serial.println("ms");

Serial.println();

}

voidloop()

{

if(digitalRead(2)==HIGH)

{

start=millis();

delay(200);// for debounce

Serial.println("Started...");

}

if(digitalRead(3)==HIGH)

{

finished=millis();

delay(200);// for debounce

displayResult();

}

}

The calls to delay() are used to debounce the switches – these are optional and their use will depend on your hardware. Below is an example of the sketch’s serial monitor output – the stopwatch has started, and then button two pressed six times across periods of time:

If you had a sensor at the start and end of a fixed distance, speed could be calculated: speed = distance ÷ time.

You can also make a speedometer for a wheeled form of motion, for example a bicycle. At the present time I do not have a bicycle to mess about with, however we can describe the process to do so – it is quite simple. (Disclaimer – do so at your own risk etc.) First of all, let’s review the necessary maths. You will need to know the circumference of the wheel. Hardware – you will need a sensor. For example – a reed switch and magnet. Consider the reed switch to be a normally-open button, and connect as usual with a 10k ohm pull-down resistor. Others may use a hall-effect sensor – each to their own). Remember from maths class:

where r is the radius of the circle. Now that you have the wheel circumference, this value can be considered as our ‘fixed distance’, and therefore the speed can be calculated by measuring the elapsed time between of a full rotation.

Your sensor – once fitted – should act in the same method as a normally-open button that is pushed every rotation. Our sketch will measure the time elapsed between every pulse from the sensor. To do this, our example will have the sensor output connected to digital pin 2 – as it will trigger an interrupt to calculate the speed. (Interrupts? See chapter three). The sketch will otherwise be displaying the speed on a normal I2C-interface LCD module. The I2C interface is suggested as this requires only 4 wires from the Arduino board to the LCD – the less wires the better.

There isn’t that much going on – every time the wheel completes one revolution the signal from the sensor will go from low to high – triggering an interrupt which calls the function speedCalc(). This takes a reading of millis() and then calculates the difference between the current reading and the previous reading – this value becomes the time to cover the distance (which is the circumference of the wheel relative to the sensor – stored in

Arduino

1

floatcircMetric=1.2;

and is measured in metres). It finally calculates the speed in km/h and MPH. Between interrupts the sketch displays the updated speed data on the LCD as well as the raw time value for each revolution for curiosity’s sake. In real life I don’t think anyone would mount an LCD on a bicycle, perhaps an LED display would be more relevant.

In the meanwhile, you can see how this example works in the following short video clip. Instead of a bike wheel and reed switch/magnet combination, I have connected the square-wave output from a function generator to the interrupt pin to simulate the pulses from the sensor, so you can get an idea of how it works:

That just about sums up the use of millis() for the time being. There is also the micros(); function which counts microseconds. So there you have it – another practical function that can allow more problems to be solved via the world of Arduino. As always, now it is up to you and your imagination to find something to control or get up to other shenanigans.

Have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.

It looks like the Arduino Language Reference entry for the attachInterrupt function is incomplete. I don’t see HIGH being listed as a legal vale for the mode parameter. Your code compiles just fine (of course).

Just a question with Example 37.2
is there any way of having a third input as a pause button ?
then resumes with ether start button or by pressing the pause button a second time
and then shows the time data once stopped.