1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

PIC16F628A - All About Timer 0

Blog entry posted in 'Uncategorised', Aug 11, 2011.

The on chip timer on PICs is confusing to some. But not to worry...it's probably one of the simplest on chip peripherals to use on a PIC. We'll use the PIC16F628A as our example PIC for this article.

Basically, Timer 0 (TMR0) is one of 3 timers available on the 16F628A that is running at all times (there is no way to turn it off). It is basically an 8 bit wide register in the SFRs and its value is controlled by a clock source. The clock source for TMR0 can be either an external strobe signal fed in on pin RA4/T0CKI (T0CKI = Timer 0 ClocK Input) or it can be the internal instruction cycle clock. When operating with an external strobe, it can be used as a counter that "counts" the strobe pulses of an external strobe source. When operating with the instruction cycle clock, it works as a timer. You will hear some refer to TMR0 as the "timer/counter" for this reason.

The value residing in the TMR0 register starts at 0x00, then is incremented by a factor of 1 upon every low to high transition of the clock source (can be configured to increment on the high-low or the low-high transition if using an external clock source). Basically it's just a register that counts pulses from 1 of 2 possible clock pulse sources and it can count as high as 0xFF (decimal 255). For this explanation we will be using the instruction clock so it is operating as a timer.

The instruction clock runs at 1/4th the Fosc frequency. This means that if Fosc = 4MHz, our instruction clock runs at 1MHz, or one instruction per microsecond. In this scenario, assuming the prescaler is not assigned to TMR0, TMR0's value is incremented on every pulse of the instruction clock. At a 1MHz instruction clock frequency, this increments the value in register TMR0 once every microsecond (1/uS).

Because the TMR0 register is only 8 bits wide, the maximum value that TMR0 can be incremented to is 0xFF, or decimal 255. Once TMR0 is incremented to 0xFF, it will roll over back to 0 upon the next clock pulse. Once this rollover occurs, the Timer 0 interrupt flag in the INTCON register gets set (T0IF). This flag must be cleared in software.

Since TMR0 is currently running at 1 increment per uS, this means that this rollover occurs and the T0IF flag gets set once every 256uS (0x00 - 0xFF or 0-255 for a total of 256 increments). If we wanted to know when a period of 256uS has passed, we can clear TMR0, clear the T0IF flag, then poll interrupt flag T0IF until T0IF goes high (rollover occurred), then continue on with our program.

Of course a timer wouldn't be useful without some way to slow it down to different increment rates. This is the job of the "prescaler". The prescaler allows us to prescale the timer so that instead of it being incremented on every clock pulse, we can have it increment every 2 clock pulses, every 4, every 8, etc etc...all the way up to every 256 clock pulses. If we were to set the prescaler to 1:256 with a 1MHz instruction clock, this means the timer would be incremented once every 256uS. Since our TMR0 register can count up to 256, it would count how many times a 256uS period passes up to 256 times. This means T0IF would get set every 65.5mS (milliseconds...256uS x 256 = 65.5mS).

There are 4 registers associated with TMR0 -


Register TMR0 holds the value that is being incremented by the clock source. Any writes to this register (i.e. clrf TMR0, movwf TMR0, bsf TMR0,X) will also clear the prescaler back to a 1:2 prescale. This means you will have to reset the prescaler back to where you had it everytime you write to register TMR0 if you had it set anywhere other than 1:2.

| RBPU |INTEDG| T0CS | T0SE | PSA | PS2 | PS1 | PS0 |

The OPTION register holds the control bits for -

Timer 0 Clock Source (T0CS)
Timer 0 Source Edge Select Bit (TOSE)
Prescaler Assign Bit (PSA)
Prescaler Rate Select Bits (PS2-PS0)

T0CS - Selects the clock source for TMR0. Default is 1/T0CKI. Clearing this bit will select the instruction clock as the TMR0 clock source.

T0SE - Selects whether TMR0 is incremented on the rising or falling edge of T0CKI. Default is 1/Increment on falling edge. Only applies when T0CKI is the clock source.

PSA - This sets whether the prescaler is assigned to TMR0 or the Watchdog Timer. Default is 1/Prescaler assigned to WDT. When assigned to the WDT, TMR0 runs on a 1:1 prescale (increments on every pulse of the clock source).

PS2-PS0 - Sets the prescaler rate between 1:2 - 1:256 in bit divisible values. Default is 111/1:256 (1:128 if assigned to the WDT).

To set up TMR0 with the instruction clock as the clock source and a 1:4 prescaler -

Code (text):

        banksel     OPTION_REG  ;bank 1
        movlw       b'11000001' ;TMR0 clock source = instruction clock
        movwf       OPTION_REG  ;1:4 prescaler
        banksel     0x00        ;bank 0

The interrupt control register INTCON contains both the TMR0 interrupt control bit (T0IE) as well as the TMR0 interrupt flag bit (T0IF). If TMR0 interrupt is enabled (T0IE = 1...disabled by default), the program counter will jump to the interrupt handler code upon TMR0 overflow when T0IF gets set (T0IF must be cleared in software prior to exiting the interrupt). However, since T0IF continues to run normally whether the TMR0 interrupt is enabled or disabled, it is always available for polling if you do not want TMR0 to trigger an interrupt.

To set up a TMR0 interrupt -

Code (text):

        bcf     INTCON,T0IF ;clear TMR0 interrupt flag
        bsf     INTCON,T0IE ;enable TMR0 interrupt
        bsf     INTCON,GIE  ;enable unmasked interrupts
If you use multiple interrupts, you will have to poll all of your interrupt flags to determine which interrupt triggered the interrupt condition, then jump it to the applicable code.


The TRISA register contains the port direction bit for RA4/T0CKI. To configure RA4 as the TMR0 clock source input, TRISA bit 4 must be set to configure it as input.

So for a complete TMR0 setup with interrupt, instruction clock as the clock source and 1:4 prescaler -

Code (text):

        clrf        TMR0        ;clear timer 0
        banksel     OPTION_REG  ;bank 1
        movlw       b'11000001' ;TMR0 clock source = instruction clock
        movwf       OPTION_REG  ;1:4 prescaler
        banksel     0x00        ;bank 0
        bcf     INTCON,T0IF ;clear timer 0 interrupt flag
        bsf     INTCON,T0IE ;enable TMR0 interrupts
        bsf     INTCON,GIE  ;enable all unmasked interrupts
Now if we omit the bottom two lines of code so that we're not working with a TMR0 interrupt, we can still poll the TMR0 interrupt flag to know when the overflow happens like so -

Code (text):

        clrf        TMR0        ;reset timer 0
        banksel     OPTION_REG  ;bank 1
        movlw       b'11000001' ;set prescaler to 1:4
        movwf       OPTION_REG
        banksel     0x00        ;bank 0
        clrf        INTCON,T0IF ;clear TMR0 interrupt flag
        btfss       INTCON,T0IF ;has overflow occured?
        goto        $-1     ;no, check again
        clrf        INTCON,T0IF ;yes, clear TMR0 interrupt flag
        <continue with rest of program>

Using TMR0 As A Counter

TMR0 can also be configured as a pulse counter. To set it up as a pulse counter, you would configure T0CKI as the clock source by setting bit T0CS in OPTION_REG. Bit T0SE in OPTION_REG would then control whether the TMR0 register gets incremented on the falling edge of the pulse source (1) or on the rising edge of the pulse source (0).

You could then either implement one of the other two hardware timers to set up a sample interval or you could do it in software with delay loops. Then set up the code where the delay loop is called, then TMR0 is sampled to see how many pulses were counted during the set delay interval.

And that's pretty much all there is to know about TMR0. Pretty simple right?
Cribcat and House0Fwax like this.
  1. ElectroMaster
    This is a great post Jon. Very well written, easy to follow!
    ElectroMaster, Aug 11, 2011
  2. kylemaes
    Hey now I dont have to keep asking about this! LOL, Thanks Jon... I searched your blog because you were AFK at chat...
    kylemaes, Nov 26, 2011