Society of Robots
Search and Index Search Here

 Parts List
 Robot Forum
 Member Pages
 Axon MCU
 Robot Books

 How To Build
  A Robot




 Robot Journals
 Robot Theory



    Timers for Microcontrollers
    The timer function is one of the basic features of a microcontroller. Although some compilers provide simple macros that implement delay routines, in order to determine time elapsed and to maximize use of the timer, understanding the timer functionality is necessary. This example will be done using the PIC16F877 microcontroller in C.

    To introduce delays in an application, the CCSC macro delay_ms() and delay_us() can be used. These macros provide an ability to block the MCU until the specified delay has elapsed. But what if you instead want to determine elapsed time for say a PID controller, or a data logger?

    For tasks that require the ability to measure time, it is possible to write code that uses the microcontroller timers.

    The Timer
    Different microcontrollers have different numbers and types of timers (Timer0, Timer1, Timer2, watchdog timer, etc.). Check the data sheet for the microcontroller you are using for specific details.

    These timers are essentially counters that increment based on the clock cycle and the timer prescaler. An application can monitor these counters to determine how much time has elapsed.

    On the PIC16F877, Timer0 and Timer2 are 8-bit counters whereas Timer1 is a 16-bit counter. Individual timer counters can be set to an arbitrary value using the CCSC macro set_timer0, set_timer1, or set_timer2. When the counter reaches its limit (255 for 8-bit and 65535 for 16-bit counters), it overflows and wraps around to 0. Interrupts can be generated when wrap around occurs, allowing you to count these resets or initiate a timed event. Timer1 is normally used for PWM or capture and compare functions.

    Each timer can be configured with a different source (internal or external) and a prescaler. The prescaler determines the timer granularity (resolution). A timer with a prescaler of 1 increments its counter every 4 clock cycles - 1,000,000 times a second if using a 4 MHz clock. A timer with a prescaler of 8 increments its counter every 32 clock cycles. It is recommended to use the highest prescaler possible with your application.

    Calculating Time Passed
    The equation to determine the time passed after counting the number of ticks would be:

      delay (in ms) = (# ticks) * 4 * prescaler * 1000 / (clock frequency)

    for example . . .

    Assume that Timer1 is set up with a prescaler of 8 on a MCU clocked at 20 MHz. Assume that a total of 6250 clicks were counted.

    then . . .

      delay (in ms) = (# ticks) * 4 * 8 * 1000 / (20000000)

      delay (in ms) = (6250) / 625 = 10 ms

    Code in C
    First you must initialize the timer:

      long delay;

      setup_timer_0(T0_INTERNAL | T0_DIV_BY_8); //Set Timer0 prescaler to 8

    now put this code in your main loop:

      set_timer0(0); //reset timer to zero where needed

      printf("I eat bugs for breakfast."); //do something that takes time

      //calculate elapsed time in ms, use it for something like PID
      delay = get_timer0() / 625;

      //or print out data and put a time stamp on it for data logging
      printf("%u, %u, %lu\r\n", analog(PIN_A0), analog(PIN_A1), get_timer0());

    Note that it is very important that you do not call the get_timer0() command until exactly when it is needed. In the above example I call the timer in my printf() statement - exactly when I need it.

    Timer Overflow
    You should also be careful that the timer never overflows in your loop or the timer will be wrong. If you expect it to overflow, you could call a timer overflow interrupt that counts the number of overflows - each overflow being a known set of time depending on your prescaler.

    In CCSC, interrupt service routines are functions that are preceded with #int_xxx. For instance, a Timer1 interrupt service routine would be declared as follows:


      //timer1 has overflowed
      void timer1_interrupt()

        //do something quickly here
        //maybe count the interrupt
        //or perform some task
        //good practice not stay in interrupt too long

    To enable interrupts, the global interrupt bit must be set and then the specific interrupt bits must be set. For instance, to enable Timer0 interrupts, one would program the following lines right after the timer is initialized:


    If you want to stop the application from processing interrupts, you can disable the interrupts using the disable_interrupts(INT_TIMER0) CCSC macro. You can either disable a specific interrupt or all interrupts using the GLOBAL define.

    Timer Delay
    Here is another code sample that shows how to create a delay of 50 ms before resuming execution (alternative to delay_ms):

      setup_timer_0(T0_INTERNAL | T0_DIV_BY_8); //Set Timer0 prescaler to 8

      set_timer0(0); //reset timer
      while (get_timer0() < 3125); // wait for 50ms

Get Your Ad Here

Has this site helped you with your robot? Give us credit - link back, and help others in the forums!
Society of Robots copyright 2005-2014
forum SMF post simple machines