assemblypic

PIC Assembly: Configure Timer1 for particular time interval


I'm currently learning PIC assembly language, and I have come to the topic of timers. I understood that timer increments a value in its register according to a prescaler until overflow occurs in which case it will send an interrupt.

What I don't understand is how I should configure a prescaler so that timer would send an interrupt with time interval that I choose (say, 1 second). Example code would be appreciated.

(I'm using Timer1 in PIC16F877A.)


Solution

  • I understood that timer increments a value in its register according to a prescaler until overflow occurs in which case it will send an interrupt.

    This is partially correct. The value is incremented based on the selected clock input and the prescaler. The prescaler simply divides the clock input into different units of time. I will use an example from Microchip's Application Note AN580.

    Assuming you have selected an external clock source (TMR1CS set) and that clock source is 32.768 kHz, the frequency that is input into your prescaler function block is 32.768 kHz. Your prescaler is selectable between the following ratios: 1:1, 1:2, 1:4, and 1:8 by setting T1CKPS1 and T1CKPS0 to the desired value. The frequency of the clock that will increment the TIMER1 register can be any of the following:

    Prescale....T1CKPS1....T1CKPS0....FREQUENCY [kHz]
    1..................0..................0.................32.768
    2..................0..................1.................16.384
    4..................1..................0.................8.192
    8..................1..................1.................4.096

    The overflow time is the time it takes for TIMER1 to count to its max value. With a 16-bit counter, you have a maximum count of 2^16 = 65536 counts. The overflow time is simply the number of counts, divided by the frequency. This gives us the following overflow times based on the prescale values:

    Prescale....FREQUENCY [kHz]....TIME [s]
    1..................32.768........................2
    2..................16.384........................4
    4..................8.192..........................8
    8..................4.0961........................16

    Finally, TIMER1 has match registers TMR1H and TMR1L. This allows us to set a value below the maximum count which will produce the same overflow time effect. Again, you simply divide the number of counts by the frequency. For example, we can now produce the following times assuming that we selected Prescale 1:

    TMR1H....TMR1L....TIME [s]
    0x80..........0x00.........1
    0xC0..........0x00.........0.5
    0xE0..........0x00.........0.25
    0xF0..........0x00.........0.125

    The following code snippet is from Microchip's Application Note AN580 and it gives an example of setting up a 1-second interrupt on TIMER1. I would recommend that you read through the application note in its entirety and realize that this is an example of using an external oscillator. You also have the option of using your internal clock frequency as well - which will probably give you more granular timing.

    START
        CLRF    STATUS            ; Do initialization (Bank0)
        BCF     T1CON, TMR1ON     ; Timer1 is NOT incrementing
        :
        :                         ; Do initialization stuff here
        :
        MOVLW   0x80              ; TIM1H:TMR1L = 0x8000 gives 1 second
        MOVWF   TMR1H             ;     overflow, at 32kHz.
        CLRF    TMR1L
    ;
        CLRF    INTCON
        CLRF    PIR1
        BSF     STATUS, RP0       ; Bank1
        CLRF    PIE1              ; Disable all peripheral interrupts
    ;
        BSF     PIE1, TMR1IE      ; Enable TMR1 Interrupts
    ;
    ; Initialize the Special Function Registers (SFR) interrupts
    ;
        BCF     STATUS, RP0       ; Bank0
        CLRF    PIR1
        BSF     INTCON, PEIE      ; Enable Peripheral Interrupts
        BSF     INTCON, GIE       ; Enable all Interrupts
    ;
        MOVLW   0x0E
        MOVWF   T1CON             ; Enable T1 Oscillator, Ext Clock, Async, prescaler = 1
        BSF     T1CON, TRM1ON     ; Turn Timer1 ON
    ;
    zzz SLEEP
        GOTO    zzz               ; Sleep, wait for TMR1 interrupt
    

    What I don't understand is how I should configure a prescaler so that timer would send an interrupt with time interval that I choose (say, 1 second).

    You can use this formula to determine your time: Time = Count / (Frequency / Prescale)