How to use TIMR0 in PIC16F84A using assembly language PLZ I need help

Thread Starter

andrew132

Joined Feb 2, 2017
96
That is correct. The timer works by counting system cycles (Tcyc). The 'time' in timer comes from the fact that it takes time to count a bunch of Tcyc. Also, be very clear on the difference between a subroutine and an interrupt. You call the subroutine. The interrupt is called automatically in response to an event, in this case TMR0 rolling over from FF->00. See 5.3 in the datasheet. It is critical to realize that since the interrupt can happen at any time, the interrupt routine must save any registers it uses then restore them just before returning to the system. Failure to to that will cause endless problems.

The reason to use interrupt-driven timing is that you can do other processing in-between interrupts. When you use delay loops, you consume 100% of your CPU time in mindless counting. It doesn't matter if all you are doing is flashing one LED but it gets ugly fast when you want to do other things.

The reason the code won't assemble is that it is incomplete. You have to fill in the blanks and replace those comment lines like ;handle LED output with code that does that. What I wrote was just a framework.
TimerPostScaler is a byte in RAM (a variable) that you have to declare. TimerPostScalerValue is a defined (names) value that is what the post scaler is loaded to. It is named so that it is consistent across the whole program. Observe that it is used twice. If you used literal values, it would be easy to miss one when you changed the value.

BTW: when you post code, use the CODE tags available on the toolbar 'Insert->Code Tags' of the posting window. Don't post code with line numbers as it make it impossible to copy/paste into MPLAB to test.
Ok thank you
 

absf

Joined Dec 29, 2010
1,968
Wow, so much has been going on in one night.:)

I woke up at 7.30 and after preparing breakfast for my family..... I sat down and though why should I reinvent. So I just make use of John's template and just fill in the blanks. And the result is as in the next post.

BTW, andrew132, have you made it working already using John's HELP?

If you have done it, I don't need to show my work. Just the simulation in proteus...

16f84a tmr0 timer sim.PNG

Sorry, I have no idea how to make a video and post it in YouTube.....:D
Allen
 
Last edited:

absf

Joined Dec 29, 2010
1,968
andrew132: Here's the program as promised..

Code:
#include <p16f84a.inc>

;----VARIABLES----
    cblock 0x14
W_TEMP
STATUS_TEMP
TimerPostScaler
    endc
TimerPostScalerValue EQU 31    ;65mS counter

;----PROGRAM STARTS HERE---
    ORG 000h
    GOTO InitSystem ; jump over the interrupt vector

;
; (Interrupt Service Routine (ISR) )
;
    ORG 004h
InterruptService:
;save context ; save W, STATUS and any other register that the
;copied from "Mid-Range PIC MCU Reference" from microchip

    MOVWF W_TEMP         ; Copy W to a Temporary Register regardless of current bank
    SWAPF STATUS,W         ; Swap STATUS nibbles and place into W register
    MOVWF STATUS_TEMP     ; Save STATUS to a Temporary register in Bank0
; decrement TimerPostScaler
; if not Zero, goto to IRQdone

    decf  TimerPostScaler,f    ;counter number of 65mS
    skpz                    ;counted 31 times?
    goto  IRQdone            ;not yet

; 2 sec have elapsed, toggle the LED and reload the seconds timer
; restore value of TimerPostScaler
    MOVLW TimerPostScalerValue ; reload post scaler
    movwf TimerPostScaler

; handle LED output
    movlw 02        ;00000010 RB1
    xorwf PORTB,f    ;toggle LED  
IRQdone:
    BCF INTCON,T0IF ; clear interrupt flag

; restore context
; the values of W, STATUS and other registers used in the
; service routine must be restored to their EXACT values before the interrupt occurred

    SWAPF STATUS_TEMP,W ; Swap original STATUS register value  into W (restores original bank)
    MOVWF STATUS         ; Restore STATUS register from W register
    SWAPF W_TEMP,F         ; Swap W_Temp nibbles and return value to W_Temp
    SWAPF W_TEMP,W         ; Swap W_Temp to W to restore original W value without affecting STATUS

    RETFIE ; return and re-enable interrupts

InitSystem:
    BSF STATUS,RP0        ;switch to bank 1
    BCF OPTION_REG,T0CS    ;clock source
    BCF OPTION_REG,3    ;psa=0 select tmr0 for clocks
    BSF OPTION_REG,0    ;PS2:PS0=111,  selects 1:256 prescaler
    BSF OPTION_REG,1
    BSF OPTION_REG,2
    CLRF TRISB            ;make port B all o/p
    BCF STATUS,RP0        ;bank 0 again

    BSF    PORTB,RB1        ;switch on LED at PORTB,1

    MOVLW TimerPostScalerValue; counts enough interrupts to make 2 sec
    movwf TimerPostScaler

    BCF     INTCON, T0IF     ; clear stray interrupts
    BSF     INTCON, T0IE     ; enable timer interrupt
    BSF     INTCON, GIE     ; enable general interrupt

Main_loop:
    nop ; do something while the interrupt runs the LED
    nop
    nop
    goto Main_loop

    END
 

Thread Starter

andrew132

Joined Feb 2, 2017
96
andrew132: Here's the program as promised..

Code:
#include <p16f84a.inc>

;----VARIABLES----
    cblock 0x14
W_TEMP
STATUS_TEMP
TimerPostScaler
    endc
TimerPostScalerValue EQU 31    ;65mS counter

;----PROGRAM STARTS HERE---
    ORG 000h
    GOTO InitSystem ; jump over the interrupt vector

;
; (Interrupt Service Routine (ISR) )
;
    ORG 004h
InterruptService:
;save context ; save W, STATUS and any other register that the
;copied from "Mid-Range PIC MCU Reference" from microchip

    MOVWF W_TEMP         ; Copy W to a Temporary Register regardless of current bank
    SWAPF STATUS,W         ; Swap STATUS nibbles and place into W register
    MOVWF STATUS_TEMP     ; Save STATUS to a Temporary register in Bank0
; decrement TimerPostScaler
; if not Zero, goto to IRQdone

    decf  TimerPostScaler,f    ;counter number of 65mS
    skpz                    ;counted 31 times?
    goto  IRQdone            ;not yet

; 2 sec have elapsed, toggle the LED and reload the seconds timer
; restore value of TimerPostScaler
    MOVLW TimerPostScalerValue ; reload post scaler
    movwf TimerPostScaler

; handle LED output
    movlw 02        ;00000010 RB1
    xorwf PORTB,f    ;toggle LED 
IRQdone:
    BCF INTCON,T0IF ; clear interrupt flag

; restore context
; the values of W, STATUS and other registers used in the
; service routine must be restored to their EXACT values before the interrupt occurred

    SWAPF STATUS_TEMP,W ; Swap original STATUS register value  into W (restores original bank)
    MOVWF STATUS         ; Restore STATUS register from W register
    SWAPF W_TEMP,F         ; Swap W_Temp nibbles and return value to W_Temp
    SWAPF W_TEMP,W         ; Swap W_Temp to W to restore original W value without affecting STATUS

    RETFIE ; return and re-enable interrupts

InitSystem:
    BSF STATUS,RP0        ;switch to bank 1
    BCF OPTION_REG,T0CS    ;clock source
    BCF OPTION_REG,3    ;psa=0 select tmr0 for clocks
    BSF OPTION_REG,0    ;PS2:PS0=111,  selects 1:256 prescaler
    BSF OPTION_REG,1
    BSF OPTION_REG,2
    CLRF TRISB            ;make port B all o/p
    BCF STATUS,RP0        ;bank 0 again

    BSF    PORTB,RB1        ;switch on LED at PORTB,1

    MOVLW TimerPostScalerValue; counts enough interrupts to make 2 sec
    movwf TimerPostScaler

    BCF     INTCON, T0IF     ; clear stray interrupts
    BSF     INTCON, T0IE     ; enable timer interrupt
    BSF     INTCON, GIE     ; enable general interrupt

Main_loop:
    nop ; do something while the interrupt runs the LED
    nop
    nop
    goto Main_loop

    END
Thank you very much
 
Top