*As the Analog to Digital tutorial is going take longer than i estimated at first, i'll leave you another introductory on Timers...
While the use of delay() can be useful for simple tasks, will also keep the uC busy until it it finishes waiting !
While the use of delay() can be useful for simple tasks, will also keep the uC busy until it it finishes waiting !
So, we are going to have a look at the timers of an AVR chip !
The AVR has an interesting counting circuit. This circuit has 2 inputs and one output. If you tie it into the Tn pin it will count the pulses on the pin (this is referred to as a counter on the datasheet). If you tie it into the AVRs internal(or external) clock you now have a timer. If you tie the counter to the output you will get an Pulse Width Modulator signal on the OCnx pin.
- 2nd ( blue) shows the pulses coming out of the pre-scaler (clk_tn or clk/8). In our example the pre-scaler is set to 8 so, it divides the clk(red) by 8.
- 3rd shows the TCNTn (basically the count). The TCNTn updates on the falling edge of the pulse coming out of the pre-scaler. On our first pre-scaler pulse ( blue) our TCNTn is TOP-1 (or 254). On our 2nd pre-scaler pulse( blue) our TCNTn goes to TOP (or 255). Now, on our third pre-scaler ( blue) pulse the TCNTn register overflows back to the BOTTOM (or 0) because it was at its TOP value on the previous pulse. On our 4th pre-scaler pulse ( blue) the TCNTn register gets incremented again this time to BOTTOM + 1 (or 1).
- The 4th shows the TCNTn register again. The only difference is that it shows TCNTn register in a Phase Corrected PWM pattern, which means that it counts up until it hits the TOP and then start to count down until it hits the BOTTOM . * More about this in the PWM tutorial.
- The 5th line ( green) shows us the TOVn (Timer Overflow bit). This bit is set the first time that a timer overflows. Or in other words the first time that the timer goes from its TOP state to its next state (BOTTOM in the 3rd line or, TOP -1 in the 4th line).
- The 6th line shows the OCRnx register. This register deals with the PWM. The only thing that it is showing, is that the OCRnx register can only be updated when an TOVn (timer overflow) condition happens. * More on the OCRnx register in the PWM section.1
.
In other words, the pre-scaler counts the number of input pulses (from the internal clock or from external sources) and when the number reaches the preset number (0, 8, 32, 64, 128, 256 or 1024) it generates a pulse of its own. This can be seen in Figure 2 (above) which divides the input by 8. This is needed because the AVR only has an 8bit and a 16bit register
Now the maths :
What if we use a pre-scaler of (lets say ) 1024 ?!
As a taster, ill leave you a simple code here for a blinky, to use on the Arduino Board ( as Port B 5/ pin 13 is used for led ); I included a commented pre-scaler at 1 just for reference
In other words, the pre-scaler counts the number of input pulses (from the internal clock or from external sources) and when the number reaches the preset number (0, 8, 32, 64, 128, 256 or 1024) it generates a pulse of its own. This can be seen in Figure 2 (above) which divides the input by 8. This is needed because the AVR only has an 8bit and a 16bit register
Now the maths :
The math is fairly simple:
Pre-scaler = Pre-scaler / Pre-scaler
And
Pre-scaler = Pre-scaler * Pre-scaler
And don't forget the old
Frequency = Period / Time
Then, to calculate how long would take to the AVR to generate a pulse ?!?
Frequency = Period / Time
Period / Frequency = Time
Time = Period / Frequency
Time = 16bit_register_size / System_clock_speed
Time = 0xFFFF(aka 65535 )/ 16Mhz
=
Time
Pre-scaler
= Pre-scaler *
Pre-scaler
Pre-scaler =
Time * 1024
= Pre-scaler
In the datasheet says that it is recommended that all external sources are limited to system clock / 2.5 . The Arduino runs at 16Mhz therefore
you are only able to reliably measure up to an 6.4Mhz signal or less.
Also, starting the pre-scaler will start the timer, so I recommend setting the pre-scaler bits last when setting up your timer in your program.
Now, i will leave you with a handy reference table, that i am sure will be helpful many a time !!
Now, i will leave you with a handy reference table, that i am sure will be helpful many a time !!
As a taster, ill leave you a simple code here for a blinky, to use on the Arduino Board ( as Port B 5/ pin 13 is used for led ); I included a commented pre-scaler at 1 just for reference
#include <avr/io.h> int main (void) { unsigned char ElapsedTime = 0; // Make a new counter variable and initialise to zero DDRB |= (1 << 5); // Set LED as output TCCR1B |= (1 << CS10); // Set up timer at Fcpu/1 for (;;) { // Check timer value in if statement, true when count matches 1/2 second if (TCNT1 >= 16000) { TCNT1 = 0; // Reset timer value ElapsedTime++; if (ElapsedTime == 244) // Check { ElapsedTime = 0; // Reset counter variable PORTB ^= (1 << 5); // Toggle the LED } } } }
Reference :
- AVR130: Setup and Use the AVR Timers http://www.atmel.com/Images/doc2505.pdf
- Reference table http://www.gammon.com.au/forum/?id=11504
- Timers and counter http://embedded-lab.com/blog/?p=902