MicroPython 'time' Library: Delays & Timing
Contents
Introduction to the time Library
This article investigates methods from the generic MicroPython time library to:
- Code a defined length (blocking) delay during program execution
- Precisely time a process.
The MicroPython time library is a subset of the Python library of the same name.
The Pyboard-specific MicroPython pyb library provides similar methods and are discussed in the article MicroPython 'pyb' Library: Delays & Timing.
Delays During Code Execution
There are many instances when program execution must be held for a short period of time. A classic example occurs when the microcontroller requests a reading from a sensor then must wait while the sensor takes the reading and processes it ready for the microcontroller to receive the value.
From the time library there are three delay methods:
- time.sleep(seconds) : Delay for the given number of seconds.
- time.sleep_ms(ms) : Delay for the given number of milliseconds.
- time.sleep_us(us) : Delay for the given number of microseconds.
Example 1:
# Simulates a sensor that measures widgets.
# Algorithm:
# (1) The microcontroller requests a measurement.
# (2) The microcontroller must wait 500 ms for the sensor
# to take the measurement and do any conversions.
# (3) The microcontroller asks for the reading from the
# sensor.
import time
import random
class WIDGETS():
def Measurement(self):
pass
def Reading(self):
return random.uniform(3.0, 5.0)
widgets = WIDGETS()
widgets.Measurement() # Request measurement
time.sleep_ms(500) # delay for 500 ms
print(widgets.Reading(), 'Widgets') # Get reading and report it
Sample Output:
4.5200632 Widgets
This example uses the uniform() method from the random MicroPython standard library. In this case it generates a random float value between 3.0 and 5.0 inclusive.
Timing a Process
Introducing a delay into the execution of the MicroPython program is often very useful. The main problem is this delay is blocking i.e. execution of code (except for interrupt handling) comes to a standstill till the delay interval times out.
Sometimes it's necessary for a process to continue but not beyond a set time limit. Or it might be necessary to know how long a process takes to complete.
The time library has four methods that are useful for accurately timing a process:
- time.ticks_ms() : Returns an increasing millisecond counter with an arbitrary reference point, that wraps around after some value.
- time.ticks_us() : Returns an increasing microsecond counter with an arbitrary reference point, that wraps around after some value.
- time.ticks_add(start, delta) : Offset ticks value by a given number, which can be either positive or negative.
- time.ticks_diff(ticks1, ticks2) : Returns the number of ticks from ticks1 - ticks2.
The methods time.ticks_ms() and time.ticks_us() count up to a maximum value then wrap back to zero. Direct arithmetic shouldn't be applied to the values from these methods.
This is why the methods time.ticks_add() and time.ticks_diff() are provided. They take into account this wraparound behaviour.
Example 2 calculates the sequence usually referred to as 'the sum of the squares of the first n natural numbers'.
- Sum = 12 + 22 + 32 + ... + n2
Since this series is infinite in nature the calculation will only be permitted to run for 700 microseconds.
Example 2:
# Calculates the sum of the squares of the first 'n' integers.
# The calculation is allowed to proceed for 700 microseconds.
import time
sum = n = 0
# Get current time + 700 microseconds.
finish = time.ticks_add(time.ticks_us(), 700)
# Calculate series for about 700 microseconds.
while time.ticks_diff(finish, time.ticks_us()) > 0:
n += 1
sum += n*n
print('n:', n, ' Sum:', sum)
Output:
n: 31 Sum: 10416
Example 3 times a process that needs to be measured in microseconds. In this case the actual process of doing the timing must be measured and offset.
Example 3:
# Program that uses methods from the MicroPython 'time' library
# to time a coded 200 us delay.
import time
# Calculate offset.
# This is the time in microseconds that is taken to measure
# the 'measuring' process.
start = time.ticks_us()
finish = time.ticks_us()
offset = time.ticks_diff(finish, start)
print('Offset(us):', offset)
# Time a delay of 200 microseconds
start = time.ticks_us()
pyb.udelay(200)
finish = time.ticks_us()
interval = time.ticks_diff(finish, start)
interval -= offset
print('Coded delay (us):', 200)
print('Measured delay (us):', interval)
Sample Output:
Offset(us): 21
Coded delay (us): 200
Measured delay (us): 198
Example 4 times a process that needs to be measured in milliseconds. Even for a microcontroller running an interpreted language (MicroPython) this is a simple task with a high degree of accuracy.
Example 4:
# Program that uses methods from the MicroPython 'time' library
# to time a coded 200 ms delay.
import time
# Time a delay of 200 milliseconds
start = time.ticks_ms()
time.sleep_ms(200)
finish = time.ticks_ms()
interval = time.ticks_diff(finish, start)
print('Coded delay (ms):', 200)
print('Measured delay (ms):', interval)
Sample Output:
Coded delay (ms): 200
Measured delay (ms): 200