PIC16F877 Timer/Timing

Discussion in 'Embedded Systems and Microcontrollers' started by CVMichael, Jun 8, 2008.

  1. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    I am using a PIC16F877, using a 20MHz clock, I write code for it in mikroC

    I need to find out how long some code took, for example if I have code that takes an unknown time to execute, how can I tell when the code is done, how much time it took to execute ?


    Code ( (Unknown Language)):
    1. start_time = current_time;
    3. // some code here that could take any amount of time
    5. end_time = current_time;
    6. time_taken = end_time - start_time;
    So what I need is the "time_taken", but how ?

    I would prefer to get the time in clocks, or the smallest interval possible, because I need to do things accurately.
  2. beenthere

    Retired Moderator

    Apr 20, 2004
    I would imagine that the PIC's data sheet would give the execution speed of each instruction in terms of clock ticks.

    Your easiest way to determine that run time of any code segment is by analysis of the hex code that executes - parse the hex file for the instructions and assign clocks to each as determined from the data sheet. Assuming there are no conditional branches, the total number of clocks over the frequency will give you execution time.

    Writing the code in C or even one of the Basics wouldn't be too much of a challenge.
  3. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    Well, parsing HEX is beyond me... that's why I write code in C :D

    Also, that is assuming that the code will take the same amount of time... but depending on analog input and/or other inputs, the time it takes changes...

    I looked in the mikroC help, and the only reference to time I found some code that looks like this:
    // Timer 0
    T0CON = 0x07;
    TMR0H = (65536-156) >> 8;
    TMR0L = (65536-156) & 0xFF;
    INTCON.T0IE = 1; // Enable T0IE
    T0CON.TMR0ON = 1;

    But in the whole help file, it does not say what T0CON is or what TMR0H is, etc...

    I can't believe that in the help file there is no mention about timers :(
  4. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    OK, I found a good example for PIC16F877 written in MikroC, that I tested on my chip and works fine:
    Code ( (Unknown Language)):
    2. unsigned int cnt;
    4. void interrupt() {
    5.   cnt++;                   // Increment value of cnt on every interrupt
    6.   TMR0   = 96;
    7.   INTCON = 0x20;           // Set T0IE, clear T0IF
    8. }
    10. void main() {
    11.   OPTION_REG = 0x84;       // Assign prescaler to TMR0
    12.   TRISD = 0;               // PORTD is output
    13.   PORTD = 0xFF;            // Initialize PORTD
    14.   TMR0  = 96;              // Timer0 initial value
    15.   INTCON = 0xA0;           // Enable TMRO interrupt
    16.   cnt = 0;                 // Initialize cnt
    18.   do {
    19.     if (cnt == 400) {
    20.       PORTD = ~PORTD;      // Toggle PORTD LEDs
    21.       cnt = 0;             // Reset cnt
    22.       }
    23.     } while(1);
    24. }
    The only thing I understand there is that it executes an interrupt, that interrupt counts how many times it executes, then in the main function, it flips the bits on port D every time the counter reaches 400.

    What I DON'T understand is how to set the interrupt ?
    How do I set the interval ?

    To be more precise, what does each line in the following do:
    OPTION_REG = 0x84; // Assign prescaler to TMR0

    Why 0x84 ? what is that magic number ? what is a prescaler ?

    TMR0 = 96; // Timer0 initial value

    Why 96 ?

    INTCON = 0xA0; // Enable TMRO interrupt

    Why 0xA0 ??

    Also in the interrupt:
    INTCON = 0x20; // Set T0IE, clear T0IF

    Why 0x20 ?

    Where do I find a table/description with what each value means ?
  5. n9352527

    AAC Fanatic!

    Oct 14, 2005
  6. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    Datasheet does not explain how everything works...

    But I searched the web, and I found help:

    On page 6 & 7 it explains how to calculate the values, so, in my case for a 20Mhz clock, if I want a timer to fire every millisecond, I have to set the following values:

    OPTION_REG = 0x84; // Prescaler Delay = 16 cycles
    TMR0 = 100; // Timer0 initial value

    And the math: 20000000 / 8 / 16 / (256-100) = 1001.6

    That's pretty close to what I need....
  7. n9352527

    AAC Fanatic!

    Oct 14, 2005

  8. nanovate

    Distinguished Member

    May 7, 2007
    Just a comment about TMR0 and the prescaler:

    If you assign the prescaler to the watchdog then the timer updates every instruction (4 clocks) NOT two instructions.
  9. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    Yea, I tried to read the datasheet, but I could not understand almost anything...

    Now that I already know it works, looking through the datasheet I understand it better (the timers section that is...), but before it was just gibberish to me...

    Everything else is still gibberish to me when I look at the datasheet :D so it's gonna be a while until I understand everything in there...

    For me this is first time doing this, so I need really basic explanations
  10. CVMichael

    Thread Starter AAC Fanatic!

    Aug 3, 2007
    Thanks for the info, but there is something there that does not make sence to me...

    First of all, before I made this thread, I thought that there is an integrated timer that keeps track of the clocks, and I thought that I could tap into that to find the time takes for parts of code to run, but it's not like that, as I know now...

    If I do it the way you said, how can it run all the code ?
    I mean it does one instruction per 4 clocks, right ? in my interrupt code, I have more than one instruction, so how can it run the interrupt for every 4 clocks, when the code in the interrupt is more than 4 clocks ??

    Can you give me a short example on how to do it ?

    Anyways, I found an even better combination of OPTION_REG / TMR0 values:

    OPTION_REG = 0x81; // Prescaler Delay = 2 cycles
    TMR0 = 131; // Timer0 initial value

    That gives me: 20000000 / 8 / 2 / (256-131) = 10,000

    I like that much better because it does exactly 10,000 interrupts per one second, so there are no rounding errors in there, and it's perfect for my needs.

    PS. I made a small VB6 function that finds the values that I have to put for OPTION_REG & TMR0
  11. n9352527

    AAC Fanatic!

    Oct 14, 2005
    Right, I understand. Datasheets are not always easy to understand or follow logical flow of writing. But they present complete information on the devices.

    You will get used reading them, it is just a matter of experience and a bit of practice.