In the previous tutorial we showed how to create time delay with Timer 0 and Timer 2 of the Arduino which is based on ATmega328 microcontroller. The timer 0 and timer 2 are 8 bits timer/counter. In this tutorial we show how to create time delay with Arduino Timer 1 which is 16 bit timer/counter.
For programming time delay with Timer 0 and Timer 2 see the following tutorials.
- Time delay using timer 0 without inbuild functions in Arduino
- Time Delay with Arduino Timer 2
To know how to program the timer it is good to know how it works. The way it works can be better understood if we look into its block diagram which is shown below.
To program the timer 1 as a time delay timer we can use the normal mode. The timer 1 is programmed in normal mode using the waveform generation mode bits(WGM13, WGM12,WGM11,WGM10) which are located in the TCCR1A and TCCR1B registers as shown below.
The normal mode is configured using the following table:
So for timer 1 in normal mode all WGMn bits are zero.
The following formula is used to calculate the timer 1 count value using the given time delay(Td).
\(C = 65536 -\frac{ F_{CPU}}{NF_d}\)
where \(F_{CPU}\) is the CPU frequency or the crystal oscillator frequency, N is the pre-scalar value and \(F_d\) is the frequency due to time delay(Td) which is given by,
\(F_d=\frac{1}{T_d}\)
So if the time delay we want is 1ms then,
\(F_d=\frac{1}{T_d}=\frac{1}{1ms}=1KHz\)
The pre-scalar N divides the cpu frequency or oscillator frequency and supplies that clock to drive the timer 2. The pre-scalar value is configured using the clock select bits in the TCCR1 registers.
So for N=8 prescalar we have CS bits as 010 and so for normal mode the TCCR1A and TCCR1B setting are,
TCCR1A = 0x00;
TCCR1B = 0b00000010;
TCCR1C = 0;
If we want time delay of 1ms, if the CPU frequency is 8MHz then we can calculate the count value using the above equation,
\(C = 65536 -\frac{ F_{CPU}}{NF_d}= 65536 - \frac{8MHz}{8 \times 1KHz} = 65536 - 1000 =64536 \)
So the count value required for 1ms delay is C=64536. We load this value into the TCNT1 register.
TCNT1 =64536;
The TCNT1 register has two 8 bits registers TCNT1H and TCNT1L as shown below but we can directly enter the value into the TCNT1. The compiler takes care of it. If you want you can also load the number into the two registers.
Once we have loaded the register and start the timer the count value is counted from zero to the count value. Once the timer reaches the count value the timer overflow flag TOV1 is set. This flag bit is located in the TIFR1 as shown.
In program, we monitor the TOV1 flag, stop the timer 1 and reset the TOV1 flag as follows,
while(!(TIFR1 & (1<<TOV1))); //wait until TOV1 flag is set
TCCR1B = 0; //turn off timer 1
TIFR1 |= (1<<TOV1); //clear TOV1 flag
So for writing 1ms time delay routine we have,
void T1delayOnems(){
//setup Timer 1
TCCR1A = 0x00;
TCCR1B = 0b00000010; //normal mode with 8 pre-scalar
TCCR1C = 0x00;
TCNT1 = 64536; //load count value for 1ms time delay
while(!(TIFR1 & (1<<TOV1))); //wait until TOV1 flag is set
TCCR1B = 0; //turn off timer 1
TIFR1 |= (1<<TOV1); //clear TOV1 flag
}
For creating n number of milli seconds we can simply call the above 1ms function for n times using a for loop as shown below.
void T1delayms(int n){
for(int i = 0; i <= n; i++){
T1delayOnems();
}
}
A simple example of using the time delay routines above, a LED blink program with 100ms delay between the on and off state is provided below.
#define LED PD3
void setup(){
pinMode(LED,OUTPUT);
}
void loop(){
digitalWrite(LED, HIGH);
T1delayms(100);
digitalWrite(LED, LOW);
T1delayms(100);
}
void T1delayOnems(){
//setup Timer 1
TCCR1A = 0x00;
TCCR1B = 0b00000010; //normal mode with 8 pre-scalar
TCCR1C = 0x00;
TCNT1 = 64536; //load count value for 1ms time delay
while(!(TIFR1 & (1<<TOV1))); //wait until TOV1 flag is set
TCCR1B = 0; //turn off timer 1
TIFR1 |= (1<<TOV1); //clear TOV1 flag
}
void T1delayms(int n){
for(int i = 0; i <= n; i++){
T1delayOnems();
}
}
In this time delay function illustration we polled the TOV1 flag and this can keep the CPU busy as it need to continuously check the flag. The other method to create time delay without causing the CPU lose time due to polling mechanism is the interrupt method. The interrupt method is better.