Discussion in "8051 Discussion Forum" started by    DavesGarage    Nov 14, 2009.
Sat Nov 14 2009, 10:09 am
#1
A system tick is a regular event, much like a heart beat, that can be used for a variety of things like delays, reading and writing I/O at regular intervals, checking for error conditions, etc.

More advanced uses might include things like a cooperative scheduler in a multitasking environment.

Getting your first piece of code running on a new target system is always a challenge, and even the simplest program (flashing an LED) requires a delay function.
Sat Nov 14 2009, 10:37 am
#2
So, where to start?

Firstly, we make a couple of assumptions about our target system:

The crystal frequency will be 12Mhz, and the processor will be a 12-clock/instruction processor.

so, here is the first part of the software:
//=====================================================================
// simple example software for testing system ticker...                
//=====================================================================
#include "AT89X51.H"


We include a header that has our special function registers defined for us. I'm using the Keil development environment, and this header came with it...

Next, we make a few definitions:
// get high order byte from word
#define High(X) ((unsigned char)((X&0xFF00)>
>
8))
 
// get low order byte from word
#define Low(X)  ((unsigned char)(X&0x00FF))        

// 1 millisecond
#define Msec1   64536
                         
// counter for T1 interrupt
volatile unsigned long Ticker;                  


The first two ( High() and Low() ) are macros. High() returns the uppermost 8-bits from a 16-bit value, and Low() returns the lowermost 8-bits from a 16-bit value.

The next value is Msec1, which stands for the timer value that will result in "1 millisecond" interrupts.

Remember, our clock frequency is 12Mhz, and it takes 12 clocks for a single instruction ( as well as a single timer count to occur ), so this means the timer will increment at a rate of 1Mhz, or every microsecond. Since the timer is a 16-bit timer, it can only count up to 65535 ( 0xFFFF in hexadecimal). The next increment (65536) will roll the count over back to zero. So, 1 millisecond worth of timer counts (1000) subtracted from the roll over amount (65536) is 64536.


Finally, we declare our global ticker value, "Ticker"
Sat Nov 14 2009, 10:43 am
#3
Next, we define a function to initialize our system ticker interrupt...

//=====================================================================
// init routine for ISR handler...                                    
//=====================================================================
void InitISR()
   {
   Ticker      = 0;
   EA          = 0;
   TH1         = High(Msec1);
   TL1         = Low(Msec1);   // load initial values for timer
   TMOD        = (TMOD & 0x0F) | 0X10; // sets timer1 to Mode 1, a 16-bit non-reload
   ET1         = 1;                    // enable timer 1 interrupt
   TR1         = 1;                    // turns on timer 1
   EA          = 1;                    // enable interrupts
   }


We initialize Ticker to zero, disable interrupts, load the hi order register and low order register of timer 1 with our "1 millisecond" value, and set the mode for the timer as a16-bit non-auto-reload timer. Then we enable the timer, turn on the timer, and re-enable the interrupts.



[ Edited Sun Nov 15 2009, 01:56 am ]
Sat Nov 14 2009, 10:47 am
#4
Now we need to define the actual interrupt service routine...

//=====================================================================
// Programmable Timer 1 Interrupt Service Routine                      
//=====================================================================
void ProgrammableTimer1_ISR() interrupt 3 using 1
   {
   TH1 = High(Msec1);  // Reset the clock for next interrupt
   TL1 = Low(Msec1);
   Ticker++;                  // bump ticker count...
   }


Since this routine is being executed EVERY millisecond, all it needs to do is reload the timer, and increment the Ticker value...

The routine is identified as"interrupt 3", which is the proper interrupt for timer 1, and is defined as using register set 1. For more information on register sets, you can read the "8052 bible" documents, listed at the end of this thread.


[ Edited Sun Nov 15 2009, 01:57 am ]
Sat Nov 14 2009, 10:50 am
#5
We're almost done now...

We need a delay function...

//=====================================================================
// delay routine...                                                    
//=====================================================================
void Delay( unsigned int NumMillisecs )
   {
   unsigned long DelayTickValue;

   DelayTickValue = Ticker + NumMillisecs;
   while( Ticker < DelayTickValue );
   }


All this routine does is take the passed argument (which is how many milliseconds you want to delay), add it to the system ticker value, and then wait for the ticker to increment it's way past the target value. Since the ticker increments every millisecond, all we have to do is wait for it...
Sat Nov 14 2009, 10:56 am
#6
Finally, we need the main() function. I've written a simple main() that will utilize our initialization function and our delay function, and it will toggle a bit. If this bit happened to be connected to an LED drive circuit, the LED would blink ON and OFF twice per second...

//=====================================================================
// main function to test ISR above...                                  
//=====================================================================
void main()
   {
   InitISR();

   while(1)
      {
      P3_0 = 1;
      Delay(250);   // wait for 250 milliseconds
      P3_0 = 0;
      Delay(250);   // wait for 250 milliseconds
      }
   }


This concludes my cursory example of how to implement a system ticker on a typical 8052...

I hope this helps
Sat Nov 14 2009, 11:07 am
#7
Here are the links to the "8052 bible":

http://www.nxp.com/acrobat_download/various/80C51_FAM_ARCH_1.pdf
http://www.nxp.com/acrobat_download/various/80C51_FAM_PROG_GUIDE_1.pdf
http://www.nxp.com/acrobat_download/various/80C51_FAM_HARDWARE_1.pdf
Fri Nov 20 2009, 12:47 pm
#8
I added a simple function to wait for the next tick, and consolidated all of the above into one file. Here it is:

//=====================================================================
// simple example software for testing system ticker...                
//=====================================================================
#include "AT89X51.H"

typedef unsigned long ULONG;
typedef unsigned int  WORD;
typedef unsigned char BYTE;

// get high order byte from word
#define High(X) ((BYTE)((X&0xFF00)>
>
8))
 
// get low order byte from word
#define Low(X)  ((BYTE)(X&0x00FF))        

// 1 millisecond
#define Msec1   64536
                         
// counter for T1 interrupt
volatile ULONG Ticker;                  

//=====================================================================
// init routine for ISR handler...                                    
//=====================================================================
void InitISR()
   {
   Ticker      = 0;
   EA          = 0;
   TH1         = High(Msec1);
   TL1         = Low(Msec1);   // load initial values for timer
   TMOD        = (TMOD & 0x0F) | 0X10; // sets timer1 to Mode 1, a 16-bit non-reload
   ET1         = 1;                    // enable timer 1 interrupt
   TR1         = 1;                    // turns on timer 1
   EA          = 1;                    // enable interrupts
   }

//=====================================================================
// Programmable Timer 1 Interrupt Service Routine                      
//=====================================================================
void ProgrammableTimer1_ISR() interrupt 3 using 1
   {
   TH1 = High(Msec1);  // Reset the clock for next interrupt
   TL1 = Low(Msec1);
   Ticker++;                  // bump ticker count...
   }


//=====================================================================
// wait for the ticker to increment...                                 
//=====================================================================
void WaitForTicker()
   {
   volatile ULONG DelayTickValue;

   DelayTickValue = Ticker;
   while( Ticker == DelayTickValue );
   }

//=====================================================================
// delay routine...                                                    
//=====================================================================
void Delay( unsigned int NumMillisecs )
   {
   volatile ULONG DelayTickValue;

   DelayTickValue = Ticker + NumMillisecs;
   while( Ticker < DelayTickValue )
      WaitForTicker();
   }

//=====================================================================
// main function to test ISR above...                                  
//=====================================================================
void main()
   {
   InitISR();

   while(1)
      {
      P3_0 = 1;
      Delay(250);   // wait for 250 milliseconds
      P3_0 = 0;
      Delay(250);   // wait for 250 milliseconds
      }
   }


Here is the output from the logic analyzer in Keil's debugger:



 kennedyugo like this.
Thu Dec 24 2009, 08:26 pm
#9
hello sir... i went thr this thread ...its right as u got the proper output...bt can i ask u ma doubt here???????In isr routine why u hav nt used TF=0? Bcz as per ma knowelged when u dnt clear TF then u block any new interrupt since the pin status indicate that interupt is still being serviced.....we hv RETI instruction in assembly to do d same job...i refered c programs from mazidi also,there also i found that they hvnt cleared timer flag.
Why it is so?? i m nt getting it....
Fri Dec 25 2009, 12:08 am
#10
The TF flag is automatically reset when an interrupt service routine is enabled, and used to respond to the flag. When there is no ISR, the flag must be manually reset.

If you read the sections on interrupt handling in the bible documents, you will discover this fact...

Use this bible: http://www.nxp.com/acrobat_download/various/80C51_FAM_HARDWARE_1.pdf

refer to page 7, and look at the description for the TCON register. Below it, you should read the definition for TF1 and TF0


I hope this helps,


[ Edited Fri Dec 25 2009, 01:23 am ]

Get Social

Information

Powered by e107 Forum System

Downloads

Comments

Bobbyerilar
Thu Mar 28 2024, 08:08 am
pb58
Thu Mar 28 2024, 05:54 am
Clarazkafup
Thu Mar 28 2024, 02:24 am
Walterkic
Thu Mar 28 2024, 01:19 am
Davidusawn
Wed Mar 27 2024, 08:30 pm
Richardsop
Tue Mar 26 2024, 10:33 pm
Stevencog
Tue Mar 26 2024, 04:26 pm
Bernardwarge
Tue Mar 26 2024, 11:15 am