Timer PreLoading | How To Generate Delay With Timer Module?

Previous Tutorial Previous Tutorial Tutorial 11 Next Tutorial Next Tutorial
Timer Preloading | Generate Delay With Timer (100% Accurate)
Intermediate level ★★☆☆☆

 

In this tutorial, we’ll discuss how to generate accurate time intervals with timer modules using the timer preloading technique. You’ll learn both how to measure and eliminate error in timer output intervals. It’s going to be an easy yet interesting read so let’s get started!

[toc]


   Components Needed for this tutorial   

 

Quantity Component Name
1 PIC16F877A
1 Breadboard
1 Jumper Wires Pack
1 330Ω Resistors
1 LED
1 4MHz Crystal OSCillator
1 LM7805 Voltage Regulator
1 9v Battery or any Power Supply Source
1 PICkit3 (PIC Programmer)


   The Source Of Error   

 

Solving any kind of problems always starts by defining the problem itself. Figuring out what’s wrong or what’s the source of these tiny glitches is the first step to eliminate them all. That’s why we should point out the real reason behind the erroneous output of the timer1 module in the last tutorial (Tutorial 9 – LAB7). The step at which we were calculating the required number of timer overflows in order to get 1-second time interval as an output.

For the 16-Bit Timer1 module, with a system being clocked at a rate of 4MHz, with a prescaler ratio of 1:1, with an initial value of 0 loaded in TMR1 register, and the output time interval is set to be 1-second. Then the number of overflows (X) needed to complete 1-second is given by the following general equation.

timer-preloading

By solving for X, we need 15.26 overflows in order to get a time interval of 1 second. In the previous tutorial, we’ve neglected the 0.26 part. That’s obviously the main source of the error!

Well, the Toverflow is = 0.06553

Hence the output time interval, Tout = 15 * 0.06553 = 0.982 second

It should be 1 second, not 0.982 of course. But 15.26 * 0.06553 = 1 second

That’s why we should have taken that 0.26 fraction part into account! But how? How can the number of interrupt overflows be a floating-point number? Does it make sense to have a 4.7, 10.2, or 12.8 number of overflows?

Actually, it does make sense! yet it’s absolutely doable. But it may not be a very good idea to follow as long as we can avoid getting a floating number in the first place!

In this tutorial, I will explain both methods that I use and refer to as “Timer preloading”. Here is a brief description for both:

  The first method  

I always prefer and recommend this way and find it much easier to explain and implement. In this method, we avoid getting a floating number as a value for the number of overflows (X). This is technically achieved by adjusting the Toverflow for the timer1 module by preloading a calculated value into the TMR1 register at the beginning of each round.

  The second method  

Which I do not recommend as much. Anyway, in this method we firstly deal with the fraction part of X. Say it was (13.8), In this case, we’ll preload a value to get a (0.8 Toverflow). Then we’ll perform 13 complete overflows starting from (0 to 65535).

  What we’ll be doing next?  

Well, we’ll discuss the first method as it has proven to be the easier to grasp in most cases. In the next section, I will explain the basic idea in detail. The following couple of sections are going to be a step-by-step implementation, and a practical LAB respectively. Then, the tutorial is done and you can just jump to the next one. However, the final section in this tutorial will be a full demonstration of the second method of preloading for those who are interested (It’s optional).

 


   Timer Preloading Technique   

 

The basic idea of this technique is to avoid getting a floating number as a value for the number of overflows (X). How can we achieve this?

Let’s consider the previous case encountered in LAB7. In which we had a 16-Bit timer module (timer1), a system clocked at a rate of 4MHz, a prescaler of 1:1, and an initial value of 0. To get the Toverflow for this timer module in such settings, just use the general equation. By substituting for the number of overflows(X) by 1, you’ll get the Toverflow

Note that: For (X=1) ==>  Tout = Toverflow

timer-preloading

The result will be Toverflow = 0.06553 second

And that crazy number is actually the source of pain. Why? well, if that number is the time it takes our timer1 module to reach overflow state. Then how many overflow interrupts do we need to complete a 1-second time interval?

Obviously, it’s 1 / 0.06553

which will result in 15.26 overflow

That’s why Toverflow must be changed!

Well, it takes the timer1 module about (0.06553 seconds) to count from (0 to 65535). What if we could force it to overflow in less time? well, it can be a good solution. Especially if we chose a period of (0.05 second) which is less than 0.06553 and more importantly won’t generate a floating number when we divide 1second/0.05second = 20. Which means that we’ll exactly need clean 20 overflows to get our desired 1-second output interval. There won’t be any remainder fractions and so.

At this point, we all should be questioning the same thing. How can we force the timer1 module to overflow in just 0.05 second instead of 0.06553?

Well, if counting from (0 to 65535) takes 0.06553 seconds. Then if it started counting from a specific value in between, then it can theoretically overflow nearly at any instance of time we wish!

By using the general equation, setting (Tout = 1, X = 20, Fosc = 4MHz, PS = 1), and solving for TMR1. We’ll get the initial value to be preloaded in timer1 module. This will result in

TMR1 = 15535

And that is the value we should preload to the TMR1 register in order to make (Toverflow = 0.05sec). Which means that a Tout of 1-second will need clear 20 overflows!

That’s the basic idea behind the timer preloading technique. We’re changing the time till overflow Toverflow by loading a specific value in the TMR1 register at the beginning of counting, instead of starting at zero as usual!

 


   Implementing Timer Preloading   

 

Implementing the timer preloading technique in C-Code should be an easy task obviously. As long as you’ve correctly performed the calculations involved. Which means you’ve got a value to load to TMR1 and a number for the total interrupts that counts for the desired Tout. And here is the systematic step-by-step procedure for the timer preloading.

 step1 – Configure The Timer Module 

Check the Timer1 logic diagram in the datasheet to make sure that you’re doing this right. Don’t forget to preload the value which we’ve calculated previously. Let’s consider the same settings for LAB7, thus the loading value will be (15535) and the counter X will go up to (20) as we’ve calculated previously. The C-Code for this step will be as follows


 

 step2- Write The ISR 

At each overflow, you should preload the specific value in TMR1 register. And the if-statement should check for the new value of X which is 20 instead of 15 (as in LAB7)


 

And that’s it! Implementing the timer preloading technique in this method should take no longer than 5-minutes to perform the previous couple of steps!

 


 Generate 1sec Delay With Timer Preloading – LAB 

 

Lab Name Generate 1-sec Delay With Timer Preloading
Lab Number 8
Lab Level Intermediate
Lab Objectives Learn how to use the timer preloading technique to generate 100% accurate time intervals with Timer1 Module. And double-check the results.

 

       1. Coding       

 

Open the MPLAB IDE and create a new project name it “Timer Preloading”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.

timer-preloading

Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.

timer-preloading

Now, open the main.c file and let’s start developing the firmware for our project.

Our first task is to configure the RB0 to be an output pin (for LED) and set it to be OFF (initially)


Now, we’ll configure the Timer1 module to operate in timer mode. And don’t forget to preload the 15535 value which we’ve previously calculated.


Now, it’s time to configure the timer overflow interrupt and write the ISR handler for it. The configuration step is the same as we’ve been doing for a while.


Then, we’ll handle the Timer1 overflow interrupt by writing the ISR (interrupt service routine)

And that’s it! Implementing the timer preloading technique in this method should take no longer than several minutes to accomplish and develop the necessary firmware. Now, cross your fingers and Hit that compile button!

It should work flawlessly for you. And it’s the time to have your own hands-on experience and test some different values and settings! And I’ll be here to help you if it gets dodgy.

 

       2. Simulation       

The simulation results for this LAB should be a pure square wave with a 1-sec pulse width as shown below

timer-preloading

Compare that output diagram with the one we got in the previous LAB7 and notice the difference

timer-preloading timer-preloading
Without Timer Preloading

The Output Time Interval Tout = 0.98 second

With Timer Preloading

The Output Time Interval Tout = 1 second (Exactly)!

 


   Second Method Of Timer Preloading   

 

For those who are interested in the second way of implementing the timer preloading technique. This should be a bonus (optional) section of this tutorial. Anyway, let’s recap the main problem that we’re trying to solve via time preloading. Which is most of the time we get rational numbers as a value for X which is the number of overflows required to complete the desired time interval (Tout).

Let’s consider the following case, we’ve got a system running @ 4MHz, with 16-Bit timer, 1:1 Prescaler, and we need to get a time interval of (Tout = 2 seconds). Assuming that the timer starts counting at zero (TMR1 = 0), then the general equation will give the following results.

timer-preloading

X = (1 / 0.06553) = 30.52 overflows

As you’ve noticed, X is not an integer! We also can not neglect the fraction part (0.52 overflow) it’s not an option. But the idea of the method we’re talking about right now is to preload the timer module in order to perform a (0.52 of the full Toverflow period). Which is 0.52 * 0.06553 = 0.034 second. And here is the step-by-step procedure in order to calculate and implement this method of preloading.

 Step1 – Calculate the initial value to be loaded 

 The time interval value for (0.52 of Toverflow) is = 0.034 second. So let’s substitute for Tout by 0.034, X = 1, and solve for the initial value TMR1

timer-preloading

Thus, the value which we’ll be loading to Timer1 is => (TMR1 = 34002)

 Step2 – Configure The Timer1 Module 


 

 Step3 – Write The ISR Handler 

Just pay attention to where we’re loading the specific value to the TMR1 register. It’s done only once before the first overflow, and the Timer1 will be counting from (0 to 65535) for all of the consecutive 30-overflows till the end of the pre-calculated Tout time interval. Which means that we load it once only when (C == 31)

And That’s it! Yea it’s actually more efficient way as it seems to be. However, from my own perspective, I can see that it’s a little bit trickier and not a beginner-friendly way to do this job. Anyway, Here is the full code listing for the time preloading implementation (method-2). Cross your fingers! Hit the compile button! Then, it’s the time to play with it and do some testing on your own.

The Full Code Listing For LAB-8 Using The 2nd Method of Timer Preloading

That’s it actually. Try calculating and generating a 1-second time interval. The value to preload should be nearly 34002 and X=15.26 Hence, the C counter should be counting up to 16. Double-Check these results yourself and try other values if you wish. And I’ll be here for help!

 


   Conclusion   

 

  1  

Use oscilloscope and logic analyzer to double check your output validity. Get familiar with your tools to find out if everything is running OK or there is a problem. You should also be able to figure out when and where changes have to be made.

  2  

The timer preloading technique that we’ve discussed in this tutorial will help you generate accurate time intervals with timer modules without any glitches. However, if improperly implemented, it’ll do more of a headache than good. So just be careful and take the time to calculate the required stuff.

 

If you find this useful, then share it with your network and let me know that you’re willing to see more of my tutorialsSee You In The Next Tutorials… Good Luck ^^

 

 

Previous Tutorial Previous Tutorial Tutorial 11 Next Tutorial Next Tutorial

 

Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?

15 thoughts on “Timer PreLoading | How To Generate Delay With Timer Module?”

  1. Just want to say thank you. I’m a hardware engineer trying to break into the fw side of things and this is by far the best site I’ve come across.

    Reply
  2. Dear Brother Khaled

    I have built this code using your instruction, the generated time interval does not give 1s delay. Could you please take a close look at the code and let me know what do you think.
    Thanks very much in advance
    Adam

    // Configuration Bit Settings
    #pragma config FOSC = HS
    #pragma config WDTE = OFF
    #pragma config PWRTE = OFF
    #pragma config BOREN = OFF
    #pragma config LVP = OFF
    #pragma config CPD = OFF
    #pragma config WRT = OFF
    #pragma config CP = OFF
    // Variable Declaration
    #include
    #define _XTAL_FREQ 4000000
    void main(void)
    {
    ADCON1=7; // To Disable All Internal Analogue Channel
    CMCON=7; // To Disable The Intenal Comparator
    TRISBbits.TRISB1=0;
    PORTBbits.RB1=0;
    // Timer TMR0 SetUp
    PIR1bits.TMR1IF=0; // Clear Interrupt Flag bit
    TMR1=15535; // Load Count Value Into TMR-1
    T1CONbits.TMR1CS=0; // Assign the Internal Clock Source
    T1CONbits.T1CKPS1=0; // Select the Prescaler Rate 1:1
    T1CONbits.T1CKPS0=0;
    PIE1bits.TMR1IE=1; // Enable Interrupt Upon Overflow
    INTCONbits.GIE=1; // Enable Global Interrupt
    INTCONbits.PEIE=1; //Enable Peripheral Interrupt
    T1CONbits.TMR1ON=1; //Enable Peripheral Interrupt
    // Main Program
    while(1)
    {
    if (!PIR1bits.TMR1IF)
    {
    PORTBbits.RB1=~PORTBbits.RB1;
    PIR1bits.TMR1IF=0; //Clear Interrupt Flag of TMR0
    TMR1=0x0BDC;
    }
    }
    }
    // End of Program

    Reply
    • Hmmm. I’m just wondering why did you enable the TMR1 Interrupt signal despite the fact that you’re not using it at all. You’re polling the TMR1IF flag bit. It’s OK to do so, functionally, but it’s not the way to handle interrupts generally.
      Counting from 15535 up to 65535 won’t be done in 1 second as you hope for.
      Provided that your Fosc=4MHz & TMR1 Prescaler is 1:1, So the TMR1 will overflow in 0.05 second.
      Therefore, you’ll have to create a software counter “Variable” and count 20 timer overflow event. Only then you can toggle your IO pin and expect it to be 1 second time interval.
      I hope this helps and please copy the code in the tutorial and give it a try.
      Good luck,

      Regards,

      Reply
  3. Thanks very much for the hint…The fragment of counter code has now been added in order to count the number of overflow events. The generated waveform (using Proteus Software) gives a precise 1 second delay, but the shape of waveform is like the capacitor behavior [during charge & discharge states]. The waveform actually comes with ramps and decays, I expected to be a square wave. Probably this is something to do with the software itself.
    I would appreciate hearing your input on this matter
    Best Wishes,
    Adam

    Reply
    • No problem my friend, you’re always welcome ^^
      Well, set the oscilloscope’s coupling to “DC”, instead of “AC”. Then, tell me if it looks like what you want or not

      Reply
  4. Great tutorial and now I understand everything behind the scenes in the Timer Modules manner.But I wonder why we declared again the TMR1=15535 in the ISR part and if part of the code while we have already declared it at the beginning of the code globally?

    Reply
    • No No .. TMR1 is not a variable at all, it’s the Timer1 16-bit register
      After Enabling the Timer1 module to count “By setting the TMR1ON bit”
      TMR1ON = 1;
      Then, the TMR1 starts incrementing automatically each cycle from Fosc/4 clock input
      The line of TMR1=15535 is preloading the Timer1 module’s register
      to start counting not from zero but from the value 15535
      and every time it reaches the maximum value 2^16-1 = 65535, then an interrupt is fired and in the ISR we preload it again with TMR1=15535

      I hope this clarifies the technique a little bit more ^^

      Reply
      • I see.Then, can we say it would be enough to preload a value to timer1 which is TMR1=15535 only in the ISR(Interrupt Service Routine) handler part of the code?I mean in the if sections of the code?

        Reply
        • O.o That’s Ture! I think I’ve cleared the idea but implemented it wrong in the code!
          It should be edited now. Thanks a lot, Yaşar <3

          Reply
    • Why to do so?
      Preloading a value of 34002 will make the Timer1 overflow once each 0.0315 second
      so the number of interrupts needed to count a 1 second time interval is 1/0.0315 = 31 (nearly)

      Reply
  5. I am not a C programmer but have worked with Basic and machine language
    as a hobby. So that is my prospective here.

    In tutorial 11, lab 8 looking at the coding for the interrupt ISR second timing
    method, shouldn’t TMR1 = 34002 be under the third set of braces?
    To me, this would preload the timer only when C is 31. And, since
    TMR!F is cleared right after, the preloading would happen before
    the next timer overflow.
    Thank you for your perspective on this matter.

    Reply
    • The timer should be loaded with the value we’ve calculated each time it reaches overflow state. This doesn’t depend on the number of overflow interrupts (C) so it’s placed at the end of ISR.
      If you’re in doubt, you can still simulate this and measure the period on a scope.

      Reply
  6. I realized that we loaded the 34002 value to TMR1 register for every overlow situation.Shouldn’t we write

    this value to TMR1 register only for the fraction part of X=0.24(in other words for Tout = 0.034 seconds) ?

    Reply

Leave a Comment