Timer0 mode0 delay calculation for 11.0592 MHz crystal in 8051, ie, AT89C51

Lets generate a square wave of 2mSec period using an AT89C51 microcontroller with timer0 in mode0 on the P1.0 pin of port1. Assume xtal oscillator frequency of 11.0592 MHz.

#include <reg51.h>

sbit a=P1^0;

void delay();

void main (void)
{
TMOD=0x00;
while(1)
{
a=1;
delay();
a=0;
delay();
}
}

void delay()
{
TH0=0x1C;
TL0=0x67;
TR0=1;
while(TF0==0);
{
TR0=0;
TF0=0;
}
}


In the above, how have hex values of TH0 & TL0 been calculated? As per my calculations, for 2ms delay we need 1841 counts, ie, 2^13 - 1841=6351 should be the initial value of TH0 & TL0. In binary that is 0001100011001111. How do you split it between the 8bit TH0 & 5bit TL0 and convert it to hex?

• Does it have to be P1.0? If you're able to move it (P3), a much simpler way is to simply use the external timer pin. Oct 7, 2023 at 20:47
• The code would be a lot more readable if indented correctly. Oct 7, 2023 at 23:17
• @Greenonline I edited the code to indent it. After doing that one thing that stands out is there is the while loop while(TF0==0); which ends with a trailing semicolon followed by a block on the next line. This makes it confusing about if the author had intended the semicolon to create an empty while loop or not. @thebusybee has fixed that in their answer. Oct 8, 2023 at 7:56

You calculation is mainly correct and you found the binary value of your result is 0001100011001111.

How do you split it between the 8bit TH0 & 5bit TL0 ...

According to the manuals the lower 8 bits go in TH0 and the upper 5 bits in TL0.

... and convert it to hex?

Splitting 0001100011001111 in halves results in 00011000 and 11001111. Then use 4 bits of every 8-bit value and replace them with the corresponding hex digit. Tables for this are available all over the net.

00011000 binary is 0x18, and 11001111 binary is 0xCF.

Long version:

The delay() function is called twice for each 2 ms period. Therefore, each call shall need about 1ms. The following calculations do not take execution time for the other statements and the loop into account. These are commonly small enough to be ignored, however, if you need exact timing, you need to look into the generated machine code. Or you use a complete other approach with a timer generating the square wave.

Now let's have a look in the Atmel 8051 Microcontrollers Hardware Manual. You should never attempt to work on a controller without such a document.

TMOD is set to 0x00, which means for timer 0:

• GATE0 is 0: timer 0 runs whenever TR0 is set;
• C/T0# is 0: timer 0 counts the divided-down system clock;
• M10 and M00 are 0: timer 0 runs in mode 0 with TH0 as 8-bit timer and TL0 as 5-bit prescaler.

For the AT89C51 with a 11,0592 MHz crystal, the system clock is divided by 6 for timer 0, if you don't set T0X2 in CKCON. This gives a timer clock of 11,0592 MHz / 6 = 1843,2 kHz. To time a period of about 1 ms, the timer needs to count 1843 clocks.

The overflow flag TF0 is set if the timer rolls over from all 1s to all 0s. So its registers need to start at -1843 in two's complement with 13-bit width: 2^13-1843 = 0x18CD. The lower byte goes in TH0 and the upper byte in TL0.

A professional programmer had written these relation directly in the code. Additionally, she had organized the code more logical.

#define SYSTEM_CLOCK_HZ 11059200
#define TIMER0_CLOCK_HZ (SYSTEM_CLOCK_HZ / 6)

#define DELAY_PERIOD_MS 1
#define MS_PER_S 1000
#define DELAY_PERIOD_CLOCKS ((TIMER0_CLOCK_HZ * DELAY__PERIOD_MS) / MS_PER_S)

void delay()
{
TR0 = 0;
TH0 = (-DELAY_PERIOD_CLOCKS >> 0) & 0xFF;
TL0 = (-DELAY_PERIOD_CLOCKS >> 8) & 0x1F;
TF0 = 0;
TR0 = 1;
while (TF0 == 0)
{
// empty loop, just waiting
}
}


Which delay will the original source generate?

The values are 0x1C for TH0 and 0x67 for TL0. The upper 3 bits of TL0 are ignored, so the resulting value is 0x171C. As a 13-bit two's complement this is -2276 in decimal.

With timer 0 clocked by 1843,2 kHz this results in a delay of about 2276 / 1843,2 kHz = 1,23 ms.

It might be that the crystal was not 11,0592 MHz but some 13 MHz variant, for example 13,56 MHz. Then the delay would be like 0,99 ms.

But why 0x67 for TL0? Most probably because the author had typed "2 << 13" when calculating 2^13 when it should be "1 << 13"...

There is a bug in your calculations.

A square wave with 2ms period means it must toggle every 1ms.

Otherwise your calculation is correct and would lead to correct values, in all number bases like decimal, hex and binary.