Isn’t it amazing how we humans have managed to alter everything around us, including the complexities of the human body, making us wonder will we be able to conquer the abstract concept of time? With this food for thought, let us get on with understanding timers and counters in the 8051 microcontrollers.
Keeping time is important for humans, but what might come as a shock to you is that even machines need to monitor time to function correctly.
SoCs and microcontrollers have an independent timer in tandem with a clock on board. These timers help microcontrollers generate precise time delays and keep operations in sync with the master clock, which is the heart of the microcontroller. Not only this, but these timers also help optimize CPU utilization as they can generate delays independently.
Timer 0 and Timer 1 Registers
The 8051 microcontroller has two timers, namely Timer 0 and Timer 1. Both these timers are 16-bit registers. Since the 8051 microcontroller has an 8-bit architecture, these registers are divided into two parts TL (Lower 8-bits) and TH (Upper 8-bits) . These timers, play the dual functions of being timers and counters.
As Timers, they generate time delays.
As Counters, they count events.
How do these timer registers work?
Here’s how the entire process of generating delays or counting events takes place in the 8051 microcontrollers.
A pre-scaler scales the clock pulses from the master clock that are sent into the timer. In the case of the 8051 microcontrollers, the master clock frequency is divided by 12 and then fed into the timer. This helps to increase the accuracy of time kept but decreases the range at the same time. The reason for having the pre-scaler value set to twelve is because each machine cycle for the 8051 microcontroller takes 12 clocks, and this helps keep everything in complete synchronization.
Once the pulses reach the timer, it starts counting up from 0000 to FFFFH.
So you might be thinking if this timer is just counting pulses, how does it keep time?
The answer to this question is simple: As mentioned earlier the timers on the 8051 microcontroller are 16 bit in size. What this means is that they can count up to a maximum value of FFFFH. The input signal to these registers is a prescaled version of the master clock making them count upwards at particular durations of time. Each of these pulses from the pre-scaler increases the value in the register until it reaches its upper limit of FFFFH. Once the register reaches FFFFH and is said to have overflowed the microcontroller resets the timer register to 0000H and sets the TF1/TF0 bit in TCON register to 1. This is to alert the programmer that the overflow has taken place. Now this change in the value of TF1/TF0 flag will occur at regular intervals of time and can be used to generate accurate time delays.
Let us say the 8051 microcontroller runs on a frequency of 11.0592 MHz; this is divided by 12 and then fed to the timer. Hence, the timer receives a frequency of 11.0592/12= 921.6 kHz which is 0.00108 milliseconds or 1.08 microseconds. What this means is that the timer gets a pulse every 1.08 microseconds and counts up for each pulse. The timer starts at 0000H or any value inserted into the timer registers and begins counting up till FFFFH, which is 65536 in decimal.
Once it reaches this value, it overflows and tells the system that a specific time has elapsed. This update occurs every 70.7 (65536x 1.08 milliseconds) millisecond when counting from 0000 to FFFFH.
Hence, you get a timer that can keep time for a maximum time of 70.7 milliseconds and signals the programmer (via updating TF0/TF1 in TCON register) when it gets over. We will be talking about the TCON register in great detail later.
Here’s another analogy to break down the concept even more. Let us say you have a smartphone and set a timer on it and it sounds an alert once the time has elapsed. In the case of the microcontroller, you set the timer by initializing the timer registers, and once the time has passed, it generates a change in the TCON register to alert you. The only difference being this timer can only keep time till 70.7 milliseconds. You can loop the timer to get more delay though. We’ll get to that in this post too.
What’s the purpose of the TMOD and TCON registers in 8051?
The 8051 uses two registers to handle and control the working of the Timer registers. One of these registers is TMOD. The other is TCON.
- TMOD (Timer mode register) – The timer registers can operate in four different modes. We’ll take a look at all these modes in a jiffy. But the point is, the selection of the functioning mode is done in this register. Additionally, the overall function of the timer registers, whether to work as timers or counters, is done here too.
- TCON (Timer Control Register) – At the risk of a slight oversimplification that we will address later, we only use half of the TCON register for timing and counting purposes. This register is used to initialize the counting and to indicate when the timers have reached their counting limit.
Let’s dive into their functions in more detail.
TMOD register in 8051
TMOD stands for Timer Mode, and as the name suggests, it is responsible for setting the mode of a timer among other things. It is an 8-bit special function register that is placed at the address 89H in the ROM space and is not bit addressable. What this means is that each value in the 8-bit register can’t be changed independently.
This 8-bit register is divided into two 4-bit registers to manage T0 and T1, respectively. The lower 4 bits manage the modes for Timer 0, and the higher four bits manage Timer 1. These four bits are Gate, C/T, M1, and M0.
- Gate: Most microcontrollers need a way to start a timer, in case of the 8051 microcontrollers the timer can start by external hardware or software.
- When you wish to put the timers to use using external hardware (like interrupts): TR0/TR1 bit (in TCON register) = HIGH; GATE bit = HIGH; and / pins of the microcontroller = LOW.
- When you wish to put the timers to use using software: TR0/TR1 bit (in TCON register) = HIGH; GATE bit = LOW; and / pins of the microcontroller = HIGH.
- C/T: These timer registers can be used as both timers and counters to keep time and to count external events. To use it as a timer the C/T bit is set to 0(counts internal pulses) whereas it is set to 1(counts external pulses) if it needs to be used as a counter of events.
- M0 and M1: As mentioned earlier, there are four modes that 8051 offers. This means that we need two bits to set these modes.
|0||0||Mode 0 (13-bit timer mode)|
|0||1||Mode 1 (16-bit timer mode)|
|0||1||Mode 2 (8-bit auto-reload mode)|
|1||1||Mode 3 (Split timer mode)|
We’ll take a detailed look into each of these modes after we cover the TCON register.
TCON register in 8051
Now that we have got TMOD out of the way lets go to the next control SFR which is used by timers, TCON. TCON stands for timer control and is used to send the control signals for the functioning of the timer. The TCON register is bit addressable and is places at the address 88H in the ROM. It is an 8-bit register that starts the timer and also contains the flag which gets updated when the timer overflows.
To understand the functioning of timers, only the higher 4 bits need to be understood. TF1 and TF0 are timer flags that indicate overflow condition in timers 1 and timer 0 respectively. When an overflow condition is reached, the value is changed to 1 from 0. TR0 and TR1 are used to start timers 0 and 1. When a value 1 loads into these registers, the timers start counting from the values which are inside them.
Timer modes in 8051 microcontroller
Now that you have a basic understanding of how timers function on the 8051 microcontrollers let us dig deep into the various modes it has to offer. The 8051 microcontroller provides four different modes of operation, and a programmer can decide which mode to use according to their needs. We will discuss how to set these modes in the next section.
Mode 0: In this mode, both the timers act as 13-bit counters. What this means is that they can count up from 0000 to 1FFFH. The primary use of this mode is to provide backward compatibility with older microcontrollers like 8048. This mode offers a smaller counter size and is similar to mode one discussed next.
Mode 1: In this mode, both the timers act as 16-bit timers, enabling them to count from 0000 to FFFFH.Most programmers use this mode due to its high counting capacity. One issue of this mode is that the start value has to be put in the timer registers after each cycle increasing software overhead.
Mode 2: This mode comes with an auto-reload function, which helps deal with the software overhead issue in mode 2. In this configuration, the timer acts like an 8 bit counter and uses the lower bit (TL0/TL1) as the actual counter. As it is an 8 bit counter, it counts from 00 to FFH. The higher bit (TH1/TH0) acts as a storage element that stores and inputs the value to the lower bits when they reset.
Mode 3: In this mode, both T0 and T1 behave differently. T0 works as a two 8 bit counters. The lower 8 bits use the control signals for T0 in both TMOD and TCON registers, whereas the second 8-bit counter in T0 uses the control signals for T1. Due to this reason, T1 has no control bits and can be used only for baud rate generation. This mode is beneficial when two timers and baud rate generation are required simultaneously.
Counters in 8051
Now that we have understood timers in great detail, mastering counters will be a piece of cake. As mentioned earlier, the timer registers in 8051 are upward counters, increasing the value stored in them on each input clock signal. In the case of timers, this clock frequency is given by the pre-scaler (making it count upwards every 1.08 millisecond). Whereas in the case of a counter, this signal is given by any input value. Now that the clock signal to the register is given by an external stimulus, it counts upwards for each clock pulse given by the external peripheral. making it act as a counter. All of the things mentioned above about timers are applicable for counters; the only difference being in the value of C/T bit in TMOD register.
Note: due to the 16-bit size of timer registers the maximum value you can count up to is 65536 after which the timer is reset. Input signals are taken from port 3.4 for timer 0 and port 3.5 for timer 1.
Programming the timers in the 8051 microcontroller
All this theory might be making you feel a little lazy so let’s get down to some coding and spice things up. Most people think that assemble level language is difficult; well it is, there is no doubt in that. But now that you have an idea of how timers work programming will be much easier. So to make things easy, we will first list the steps which need to be done to configure the timer and then write the code for it.
If you remember the smartphone analogy, we mentioned earlier programming the 8051 timers would be a piece of cake. In the example mentioned below, we will try to generate a time delay of 14 seconds using mode 1
- Step 1: Select the mode and timer you want to use by setting values in the TMOD register. This decision should be made on what operation you are performing with the timer.
- Step 2: Insert the values in timer 0 or timer 1 from where you want them to should start up counting.
- Step 3: Start the timer by setting the TR flag in the TCON register
- Step 4: Wait for the overflow condition by monitoring the TF flag in the TCON register.
- Step 5: Reset all the flags as the software does not reset them
- Step 6: Redo all the steps to generate a delay of 14 seconds
Assembly level code
MOV TMOD , #10H //The value 10H is 00010000B and selects mode 1 of timer 1 MOV R3 , #200H //used as a counter to create a delay of 14 seconds AGAIN : MOVTL1 , #08H //sets the value of 08H in the lower bit of timer 1 and the again keyword helps to create a loop. MOV TH1 , #01H //sets the value of 01H in the lower bit of timer 1 SETB TR1 //turns on the timer BACK: JNB TF1, BACK //checks the TF1 flag in TCON register continuously to know if overflow has occurred or not CLR TR1 //clears TR1 flag to stop the timer CLR TF1 //clears overflow bit as the timer is reset DJNZ R3, AGAIN //keeps looping the statements after again keyword till the value in R3 reduces to 0. DJNZ command decreases the value in r3 and checks if it zero
Now you might be wondering how do we know how much time delay this code generated? So our timer has a value of 0108H which is 264 in decimal. As mentioned earlier, the timer can count till 65536; therefore, the total number of counts by the timer are 65536-264=65272. Due to this, each loop generated a delay of 655272 x 1.085 microseconds=70.820 milliseconds. This loop repeats 200 times thanks to register R3 giving a total delay of 200 x 70.820 milliseconds= 14.16 seconds
Note: To use the timers as counters you have to place 1 in the C/T bit and it will act as a counter. Counters are used to count pulses from external devices.
Programming counters in 8051
Programing counters is very similar to timers. To give you an example we will be writing an assembly language code to count values on port 3.5 and show them on port 2.
MOV TMOD #0110000B //sets counter1, mode 2,C/T=1(counts external pulses) MOV TH1, #0 //clears TH1 register AGAIN:SETB P3.5 //sets P3.5 as input port (all ports are configured as output ports by default) BACK: MOV A,TL1 //sends the value in TL1 to accumulator MOV P2, A //sends values to port 2 JNB TF1,BACK //checks overflow condition CLR TR1 //stops the counter CLR TF1 //makes TF=0 SJMP AGAIN //performs tasks infinitely
We hope that reading this article helped you gain more insights on how timers/counters work and how to program them. If at any point in this article, you feel you are out of your depth, feel free to drop a message in the comments section below.