In the previous video in this series, we looked at how microcontrollers interfaced with the outside world, using their I/O ports. And while that is arguably the most important feature of a microcontroller, along with the CPU itself, there are still a lot of features that make working with these microcontrollers a lot easier. Take, for instance, the standard blinking LED example that everyone is familiar with. You simply delay the CPU in order to flash the LED. But what if you wanted to do other things at the same time. That’s where hardware timers come in. They can keep track of time for you, while the CPU is free to do other things. So, how do these timers work, and how can we utilize them? Well, in this video I will show you how a timer like this might work, and how you can use one to run a function every few miliseconds. Let’s get started!
Much like the previous video, I made a PCB in order to visually show you how these hardware timers work. In this case, the timer is based off of the ATmega8A’s 8-bit timer0. Before I explain how it all works, I’ll just show you it first. Here it is in timer mode with the slowest possible clock. Now here it is with the fastest possible clock. And finally, here it is in counter mode. Ok now that you’ve seen it, let me explain it to you. Let’s first begin by looking at the datasheet. The reason why I picked this specific timer is because of its simplicity. The other timers have other useful features, but I wanted to keep the demonstration simple. Don’t worry though, because I will be covering the more advanced features later in this video. We have the control register, the counter, some control circuitry, a comparator, and the clock input.
Let’s start with the counter. The counter simply counts up in binary, and is labeled TCNT. Now, if you don’t know binary, you can get a crash course online. It’s really simple. Anyways, the counter will count from 0 all the way up to a maximum of 255. This is because the counter is only 8 bits long. If it is full, and tries to increment again, it will simply reset. This is because there is nowhere for the ninth bit to go. There is also some more behavior when the counter reaches its maximum value. The comparator checks when it is at the top, and then sends a signal to the control circuitry. It is up to the programmer as to what happens afterwards, but it can generate an interrupt if so desired. We can see it in action on the example board too. Once the timer reaches the top, the TOV0 led flashes. I got it backwards by accident though, it should turn on when at the top, not off.
The TCCR register allows the programmer to select the desired control options. Due to the simplicity of this timer, the control circuitry has few options. You can only change the clock’s behavior. And that’s it. But how does the clock’s behavior change? Well, let’s take a look. The clock has two sources, the CPU clock, or an external pin. This is the reason why it is both called a counter and a timer. I have a simple 555 timer clock that will simulate our CPU clock. When TCCR is 0, then the timer is paused and both clock sources are disconnected. When it is one, the clock is directly connected to the CPU clock. So, one CPU clock means one timer tick. After that though, we get into the prescaler region. What is a prescaler? Well it is a device that divides the CPU clock by a certain amount. If, for example, we use the first prescaler option of dividing by 8, that means it takes 8 CPU clock cycles to clock the timer just once. The same can be said for the other options, but with increasing division. You will also notice the two other settings at the bottom. They both have to do with another external clock source, on the T0 pin. They both do the same thing but activate the clock on either the falling or rising edge. We can see it on the board when I set the TCCR register and then press the T0 button. One press is one clock cycle.
Ok, this is really cool to look at, but the actual AVRs have more timers that have even more features. So with that, let’s get out the actual AVRs and go over some practical use cases. Let’s begin by replicating the board on the AVR. Let’s also setup the overflow interrupt with the timer as well. So, our CPU will do whatever it is currently busy with inside of the while loop. But, once our timer overflows, the CPU will pause its main action and execute the interrupt. In this case it is just toggling our LED. So, by using this method we can have timed events without using the entirety of the CPU’s focus. Using this method, we have essentially just created a PWM output on our LED.
While this PWM output works, there is actually still a more efficient way to toggle an external pin. Let’s take a look at timer2 inside of the AVR. Timer2 is very similar to timer0, which is what we just looked at. The difference is that it has an added functionality, which is a custom compare feature. This means that we can do something when the timer reaches a custom specified value. The first thing that can be done is to change the timer’s resolution. Normally, the timer is in 8-bit mode, so it has to count to 255 before resetting to 0. When we put the timer into CTC mode (clear timer on compare match mode), we can define a new top for the timer. Instead of it being 255, we can set it to 98 for example. This essentially allows us to alter the frequency of the timer. Furthermore, we can actually setup a pin to automatically toggle when it reaches our custom top. Now, for those of you who are thinking of use cases, we can use this functionality to setup a set output frequency on the OCn pin. One such use case is generating frequencies for music. If any of you have watched my first ever video, you could improve the code by using this method. Simply lookup the frequency for the note you want to play, and then generate it automatically using timer2, no CPU involvement aside from intialization. It is worth noting though that this feature is not the greatest for PWM, since you are basically locked into a 50% duty cycle.
Speaking of PWM, let’s take a look at the two PWM modes: Fast PWM and Phase Correct PWM. Let’s begin with Fast PWM. In this mode, we will still use the compare feature, but it will act a little differently. The timer behaves mostly like it does in normal mode, and it resets once it reaches the maximum value. The difference is that an external pin is HIGH every time that the timer reaches the BOTTOM and LOW when it reaches the compare value. This essentially creates a variable duty cycle on the output pin. This is also how you can digitally dim an LED, and you have much more fine-tuned control than if you did it with the CPU method.
Now what about Phase Correct PWM mode makes it different? Well the main difference is that instead of just counting up, the timer alternates between counting up and down. When the timer reaches the compare value, it does one of two things. If the timer is upcounting, the pin will go LOW, and during downcounting it will go HIGH. You may be asking why there are two different PWM methods, and when to use each one. Well, for most applications they are equivalent and you should probably just use Fast PWM for its simplicity. But Phase Correct PWM can be useful if you want to make a measurement at the center of the PWM waveform, since the timer’s behavior is symmetrical.
Let’s move on to the final timer. This timer is the largest and most feature packed timer. First of all, this is a 16-bit timer, so you have a much higher resolution to work with. The only disadvantage to this timer compared to the others is that it takes two read cycles to read the entire value of the timer. The timer also has two compare registers, meaning that you can run two different PWM duty cycles using the same timer. And finally it has an input capture unit.
The input capture unit is a useful piece of hardware that allows you to capture the state of the timer based on an outside event, essentially giving you a stopwatch for external events. You could use this feature to calculate the frequency of a waveform for example. But how does it work exactly? Well, when activated, it stores the value of the timer into separate registers for the CPU to read from. You have two methods of activating it. The first is by changing the logic level on the ICP1 pin. You could measure a square wave or button press for example. The other method is by using the analog comparator. When a level change occurs on the comparator, it will send a signal to the capture unit. I used a method similar to this in my capacitor measurement video.
Well, that’s basically it for timers. So, in summary, you can use them to time events without using valuable CPU time. You can also use them to generate specific frequencies or specific duty cycles. Hopefully you can start integrating them into your microcontroller code to make you code more efficicent. Anyways, if you enjoyed this video please consider subscribing so that you can see the other videos that I make. Have a good one.