looking help on 8051 timer interrupt and switch input

Thread Starter

Parth786

Joined Jun 19, 2017
642
8051 has two timers. One timer is TIMER0 and the other is TIMER1. Each of these timers is assigned a 16-bit register. The value of a Timer register increases by one every time a timer counts. Timer takes a time period of one machine cycle to count one. maximum number of times a timer can count without repeating is 216, i.e., 65536. So the maximum allowed counts in value of Timer registers can be from 0000H to FFFFH.

Since AT89C51 is an 8 bit controller, the registers of AT89C51 Timers are accessed as two different registers; one for lower byte and other for higher byte. For example, register of Timer0 is accessed as TL0 for lower byte and TH0 for higher byte. Similarly TL1 and TH1 are registers assigned to Timer 1.

Program: I want to set interrupt for 5 seconds. When interrupt happen, LED should be turn ON, otherwise it should be turn off.

Timer is use to generate time delay. I need 5 seconds interrupt time period. lets suppose I am using timer 0 and mode 1

5 seconds = 5000 ms = 5,00,000 uS

One timer tick take = 1.085uS
Total count by 16 bit counter = 65,536 ticks

Timer ticks * 1.085uS = Desired time

In my calculation timer should be run 460829 times in 5 second

I am stuck here The registers of Timers are loaded with some initial value. I don't understand how @cmartinez calculate TH0 and TL0 value
your formula 256*TH0 + TL0. How do you calculate value of TH0 and TL0 for 5 seconds ?
 

JohnInTX

Joined Jun 26, 2012
4,787
Program: I want to set interrupt for 5 seconds. When interrupt happen, LED should be turn ON, otherwise it should be turn off.
Timer is use to generate time delay. I need 5 seconds interrupt time period. lets suppose I am using timer 0 and mode 1
So, 5 seconds after the program starts, it should turn the LED on, yes?

Your calculation is off by 10, probably a typo:
5 sec / 1.085uS per tick = 4608294 ticks.
But the timer is only 16 bits so the most it can hold is 2^16 tiks: 65536 tiks.
65536 * 1.085 uS/tik = 71.1ms.
So you can't get a 5 second interrupt period just using the timer. You have to set the timer to interrupt at some period it can handle, 10ms for example, then COUNT the interrupts with a separate counter.
5 sec / 10ms = 500. So count 500 interrupts to make 5 sec.
 
Last edited:

Thread Starter

Parth786

Joined Jun 19, 2017
642
So, 5 seconds after the program starts, it should turn the LED on, yes?

Your calculation is off by 10, probably a typo:
5 sec / 1.085uS per tick = 4608294 ticks.
But the timer is only 16 bits so the most it can hold is 2^16 tiks- 65536 tiks.
65536 * 1.085 uS/tik = 71.1ms.
So you can't get a 5 second interrupt period just using the timer. You have to set the timer to interrupt at some period it can handle, 10ms for example, then COUNT the interrupts with a separate counter.
5 sec / 10ms = 500. So count 500 interrupts to make 5 sec.
I am stuck to calculate TH0 and TL0 value
suppose I want to set interrupt for 20 ms than how to calculate TH0 and TL0
20,000*1.085= 18433 timer ticks
how to calculate TH0 and TL0 for 20ms ?
 

cmartinez

Joined Jan 17, 2007
8,762
I am stuck to calculate TH0 and TL0 value
suppose I want to set interrupt for 20 ms than how to calculate TH0 and TL0
20,000*1.085= 18433 timer ticks
how to calculate TH0 and TL0 for 20ms ?
Parth, do you understand Hexadecimal? You can think of TH0 and TL0 as two digits of a 256-base number, that's the key.

For example:
  • In decimal (base 10), 18,433 = 1 x 10^4 + 8 x 10^3 + 4 x 10^2 + 3 x 10^1 + 3 x 10^0
  • In Hexadecimal (base 16), 18,433 = 4801H = 4 x 16^3 + 8 x 16^2 + 0 x 16^1 + 1 x 16^0
  • In base 256, 18,433 = 72 x 256^1 + 1 x 256^0
That last calculation gives you a clue... except that the timer counts UP, not down. That is, the interrupt is called when the timer overflows from FFFF to 0000. And since the maximum value of the timer is FFFF = 65,535, you need to subtract 18,433 from 65,536 to obtain the starting point of the timer and define the values of TH0 and TL0...

So, to obtain 18,433 timer ticks before it triggers an interrupt, you need the following calculation:
Timer starts at 65,536 - 18,433 = 47,103
And in base 256, 47,103 = 183 x 256^1 + 255 x 256^0
That means that the values you have to assign to the registers (in decimal) are:
TH0 = 183
TL0 = 255

Got it?
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
Parth, do you understand Hexadecimal? You can think of TH0 and TL0 as two digits of a 256-base number, that's the key.

For example:
  • In decimal (base 10), 18,433 = 1 x 10^4 + 8 x 10^3 + 4 x 10^2 + 3 x 10^1 + 3 x 10^0
  • In Hexadecimal (base 16), 18,433 = 4801H = 4 x 16^3 + 8 x 16^2 + 0 x 16^1 + 1 x 16^0
  • In base 256, 18,433 = 72 x 256^1 + 1 x 256^0
That last calculation gives you a clue... except that the timer counts UP, not down. That is, the interrupt is called when the timer overflows from FFFF to 0000. And since the maximum value of the timer is FFFF = 65,535, you need to subtract 18,433 from 65,536 to obtain the starting point of the timer and define the values of TH0 and TL0...

So, to obtain 18,433 timer ticks before it triggers an interrupt, you need the following calculation:
Timer starts at 65,536 - 18,433 = 47,103
And in base 256, 47,103 = 183 x 256^1 + 255 x 256^0
That means that the values you have to assign to the registers (in decimal) are:
TH0 = 183
TL0 = 255

Got it?
Thanks for your detail explanations. Now I understood how to calculate TH0 and TL0
what is next step ?
 

JohnInTX

Joined Jun 26, 2012
4,787
The next step would be to detail the flow chart. In particular, when you set up an interrupt driven system, you always do things in this order:

  • With interrupts disabled from reset, fully configure the system.
  • Clear any pending interrupt flags.
  • Start the timers
  • Enable the timer interrupt
  • Enable global interrupts.

That way you don't get interrupted with a partially configured system.

Since you need 5 sec after startup and the timer interrupts every 20ms(?), you'll need to add a counter in the interrupt routine to count enough of those 20ms interrupts to make 5 sec. At that point, clear the counter and proceed with whatever you were going to do at 5 seconds. Note that by doing this, the 8051's timer becomes a prescaler to the main counter.
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
The next step would be to detail the flow chart. In particular, when you set up an interrupt driven system, you always do things in this order:

  • With interrupts disabled from reset, fully configure the system.
  • Clear any pending interrupt flags.
  • Start the timers
  • Enable the timer interrupt
  • Enable global interrupts.

That way you don't get interrupted with a partially configured system.

Since you need 5 sec after startup and the timer interrupts every 20ms(?), you'll need to add a counter in the interrupt routine to count enough of those 20ms interrupts to make 5 sec. At that point, clear the counter and proceed with whatever you were going to do at 5 seconds. Note that by doing this, the 8051's timer becomes a prescaler to the main counter.
I am little bit confuse. I read your post many times but I couldn't understand. I want to start with simple example. Suppose if program start from 0 us and when it reach at 10 ms, at this point interrupt should be enable. and if interrupt is enable, LED should be turn ON and when Interrupt is disabled, LED should be Turn off. Suppose Interrupt happen for 20 ms means LED will Turn on for 20 ms after that Interrupt will disable and processor will return as what he was doing.

I want to do two things Generate interrupt at 10 ms after start of program and enable interrupt for 20 ms.
upload_2017-9-30_15-59-55.png
 

JohnInTX

Joined Jun 26, 2012
4,787
I am little bit confuse. I read your post many times but I couldn't understand. I want to start with simple example. Suppose if program start from 0 us and when it reach at 10 ms, at this point interrupt should be enable. and if interrupt is enable, LED should be turn ON and when Interrupt is disabled, LED should be Turn off. Suppose Interrupt happen for 20 ms means LED will Turn on for 20 ms after that Interrupt will disable and processor will return as what he was doing.

I want to do two things Generate interrupt at 10 ms after start of program and enable interrupt for 20 ms.
View attachment 136175
I am confuse too. What happened to what you wanted before i.e. turn LED on after 5 seconds? I don't think a 'simple example' is any simpler than just moving on and doing what you want it to do.

The bullet points in my post are the order that the init functions should follow but your flow chart shows almost exactly the opposite.
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
I am confuse too. What happened to what you wanted before i.e. turn LED on after 5 seconds? I don't think a 'simple example' is any simpler than just moving on and doing what you want it to do.

The bullet points in my post are the order that the init functions should follow but your flow chart shows almost exactly the opposite.
I am trying to explain what I want to do
tell the processor that we want this particular condition to raise an interrupt - 10 ms after start of program
tell the processor when we want the interrupt to fire.- interrupt for 20 ms
upload_2017-9-30_23-15-48.png
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
OK, then in the program initialization set the timer to the number of counts for 10ms (using the method @cmartinez or I showed you above) then in the interrupt routine reload it to the 20ms value.
I can calculate TH0 and TL0 value. I understand how to set interrupt. but I don't know how to set more than one interrupt.
Look at this chart
upload_2017-10-1_14-37-44.png
Now I want set interrupt's more than one. First interrupt generate at 10 ms after start of program. Second interrupt generate at 30 ms. Third interrupt generate at 50 ms

I want to set interrupts for three LED's Red , Green and Yellow. When first interrupt generate at 10 ms, turn ON Red LED for 10 ms and then Turn OFF. When second interrupt generate at 30 ms, turn ON Green LED for 10 ms and then Turn off. When Third interrupt generate at 50 ms, turn ON Yellow LED for 10 ms and then Turn off
 

JohnInTX

Joined Jun 26, 2012
4,787
Did you get the basic interrupt working first? If so, post the code. If not, get the basics working before moving on.

Your new scheme is completely different. You would not use a separate interrupt source for each LED. You would, as pointed out above, use ONE repeating interrupt at some convenient interval and count that interrupt to generate the other, longer intervals. You would also have to 'remember' where you are in the sequence.

But be clear, this is two problems now 1) the interrupt timing 2) using that timing to generate a sequence of events - in this case, turning on and off the LEDs.

But that is getting ahead of yourself and you keep changing what you want to do. The advice I would give is the same as always:

State the problem fully and completely.
Stick to the problem and stop jumping around. Do not waste time on 'simple' solutions that are not a part of the original problem.
Think about it and figure out how you would go about solving the problem, step by step.
Flow out those steps.
Test the flow by going over it mentally.
Code it.
Use the debugging capabilities you have in your Kiel system to test each step against your design.

I am running out of time here and repeating the basics every time is burning too much of it. You are going to have to step it up and apply what you have been taught.
 
Last edited:

Thread Starter

Parth786

Joined Jun 19, 2017
642
Did you get the basic interrupt working first? If so, post the code. If not, get the basics working before moving on.

But that is getting ahead of yourself and you keep changing what you want to do. The advice I would give is the same as always so I won't repeat it.
I will post complete code with design but I am little bit confuse on your two statement
  • With interrupts disabled from reset, fully configure the system.
  • Clear any pending interrupt flags
What are meaning of these statement related program ?

Sorry for jumping on another topics before completing first one
 

JohnInTX

Joined Jun 26, 2012
4,787
I will post complete code with design but I am little bit confuse on your two statement
  • With interrupts disabled from reset, fully configure the system.
  • Clear any pending interrupt flags
What are meaning of these statement related program ?

Sorry for jumping on another topics before completing first one
After reset, interrupts are disabled as they should be. Configure the system just means to initialize the IO, set the timer values etc. like you would when starting any program.
When initializing an interrupt system, it is common for the interrupt flag(s) to be in an unknown state. For example, the timer might roll over while you are busy doing the other init tasks so its interrupt flag will be set even if the interrupt enable is still cleared. In that case, you will get the first timer interrupt immediately after enabling the interrupts. To prevent that, good programming practice says that you should manually clear any interrupt flags before enabling the corresponding interrupts.
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
Problem statement
  • Set interrupt at every 10 ms
  • When interrupt happen blink LED for 20ms
Interrupt Design
upload_2017-10-2_13-35-38.png

Calculation for TH0 and TL0

10 ms = 10000/1.085= 9216 timer tick
Decimal 9216 = 2400 H
TH0 = 24 H
TL0 = 00 H

20 ms = 20000/1.085 = 18433 timer tick
Decimal 18433 = 4801H
TH0 = 48 H
TL0 = 01 H

Program code
C:
#include<reg51.h>

sbit LED = P1^7;  

int main(void)
{
/* Make all ports zero */
   P0 = 0x00;  
   P1 = 0x00;  
   P2 = 0x00;  
   P3 = 0x00;
  
/* Stop Timer 0   */
   TR0 = 0;  

/*Clear the interrupt flag */
   TF0 = 0;  

/*Set timer0 in mode 1*/  
   TMOD = 0x01;  

/* 10 ms reloading time */  
   TH0 = 0x24;  
   TL0 = 0x00;  

/* Enable Timer0 interrupts */  
   ET0 = 1;  

/* Global interrupt enable */
   EA  = 1;  

/* Start Timer 0 */  
   TR0 = 1;  

/* Do Nothing */
while (1)
   {
   }
}

/* It is called after every 10ms */
void timer(void) interrupt 1  
  {
       LED=~LED;               /*toggle LED on interrupt */
       TH0=0x48;                /* initial values loaded to timer */
       TL0=0x01;
  }
 

cmartinez

Joined Jan 17, 2007
8,762
Problem statement
  • Set interrupt at every 10 ms
  • When interrupt happen blink LED for 20ms
Interrupt Design
View attachment 136299

Calculation for TH0 and TL0

10 ms = 10000/1.085= 9216 timer tick
Decimal 9216 = 2400 H
TH0 = 24 H
TL0 = 00 H

20 ms = 20000/1.085 = 18433 timer tick
Decimal 18433 = 4801H
TH0 = 48 H
TL0 = 01 H

Program code
C:
#include<reg51.h>

sbit LED = P1^7; 

int main(void)
{
/* Make all ports zero */
   P0 = 0x00; 
   P1 = 0x00; 
   P2 = 0x00; 
   P3 = 0x00;
 
/* Stop Timer 0   */
   TR0 = 0; 

/*Clear the interrupt flag */
   TF0 = 0; 

/*Set timer0 in mode 1*/ 
   TMOD = 0x01; 

/* 10 ms reloading time */ 
   TH0 = 0x24; 
   TL0 = 0x00; 

/* Enable Timer0 interrupts */ 
   ET0 = 1; 

/* Global interrupt enable */
   EA  = 1; 

/* Start Timer 0 */ 
   TR0 = 1; 

/* Do Nothing */
while (1)
   {
   }
}

/* It is called after every 10ms */
void timer(void) interrupt 1 
  {
       LED=~LED;               /*toggle LED on interrupt */
       TH0=0x48;                /* initial values loaded to timer */
       TL0=0x01;
  }
Perth, I think you're forgetting that the timer counts up. So for 10ms, the registers value should be 65,536 - 9216 = 56,320. And for 20ms it would be 65,536 - 18,433 = 47,103
 
Top