;timer.asm ; This is a test of interrupt handling and the use of Timer0. It simply uses the timer ; to determine the time between changes in the LEDs as the red and yellow light are ; alternately on. LIST P=16F877, R=DEC INCLUDE "C:\MPLAB\P16F877.inc" ; Definitions ; The number of timeouts required to generate a switch in the LED display. A prescalar of ; 256 gives a "tick rate" of ; ; 5,000,000 ; tr = ----------- = 19531.5 ticks/sec ; 256 ; ; So each increment of the timer takes ; ; 1 ; tr = ----------- = 0.5119934465 usec ; 19,531.5 ; ; If Timer0 is set to 60, giving a count of 196 (256-60) between interrupts, the interrupt ; interval is ; ; 0.5119934465 usec x 196 = 0.010035071 sec ; ; Setting the LOOP_CT variable to 100 means that a change in the LED's will occur every ; 100 interrupts, or ; ; 0.010035071 x 100 = 1.0035071 s (call it 1 second for the sake of argument). #define TIMER0_CT 60 #define LOOP_CT 100 ; __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ; Define start of vars ScratchPad EQU 0x20 ; Variables Temp EQU ScratchPad+0 T0Count EQU ScratchPad+2 ; Counter to use to count interrupts Timeout EQU ScratchPad+3 ; flag to indicate its time to change lights ; Temps for interrupt handling. Put in 0x70 to 0x7F as they are available across all ; RAM banks. W_Temp EQU 0x70 Stat_Temp EQU 0x71 ; Start of the Program ORG 3 goto Start ; ======================================================================= ISR Routine ORG 4 isr ; Save the current state movwf W_Temp swapf STATUS,W CLRF STATUS movwf Stat_Temp ; We are only handling Timer 0 here, so no really need to poll for interrupts. However, ; its always a good idea to make sure. Check to see if Timer 0 has expired. btfss INTCON,T0IF goto restore ; if not, we are done decfsz T0Count,F goto restore ; Restore the counter for next time. movlw LOOP_CT movwf T0Count ; Do what we came to do, set a flag. bsf Timeout,0 restore ; Restore the Timer0 count. Note, this is not always a good idea. It could also be done ; in the main program. This scheme is a repeating timer that keeps doing its thing. The ; other scheme is a non-repeating timer that time's out once and is done unless the ; main program causes it to repeat by resetting the timer. If you are going to only ; allow the interrupt to occur once, you should also disable the interrupts and reset ; any unneeded flags. bcf INTCON, T0IF ; Clear T0IF movlw TIMER0_CT ; Reset the count movwf TMR0 ; Restore the prior system state swapf Stat_Temp,W movwf STATUS swapf W_Temp,F swapf W_Temp,W retfie ; ========================================================================= Main program ORG 0x50 Start ; Set A4-A0 to be output and RD0-RD7 to be output. bsf STATUS, RP0 clrf TRISA clrf TRISD bcf STATUS, RP0 ; Initialize the leds to red on, green and yellow off movlw 0x03 movwf PORTD movlw 0x11 movwf PORTA ; Initialize the loop counter. We change the LED's every T0Count timeouts movlw LOOP_CT movwf T0Count ; Initialize the flag movlw 0x00 movwf Timeout ; Initialize the timer call InitTimer0 ; In the loop, watch for the flag indicating that a timeout has occurred. When it does, ; reverse the polarity of the red and yellow leds. Reset the Timeout flag. mainloop btfss Timeout,0 ; if not timeout, hang around here goto mainloop movlw 0x06 ; swap red and yellow leds xorwf PORTD,F movlw 0x11 movwf PORTA bcf Timeout,0 ; reset the timeout flag goto mainloop ; Initialize Timer 0 InitTimer0 ; Set up Timer0 to use the internal clock, assign the prescaler to Timer0 and set ; the prescaler value to 256. bsf STATUS, RP0 ; OPTION_REG is in bank 1 bcf OPTION_REG,T0CS ; internal clock bcf OPTION_REG,PSA ; prescaler to Timer 0 movlw 0xF8 ; set the PSA bits for 256 bit prescaler andwf OPTION_REG,F movlw 0x07 iorwf OPTION_REG,F bcf STATUS, RP0 ; Set the count for the desired delay movlw TIMER0_CT movwf TMR0 ; Enable the interrupts bsf INTCON,GIE bsf INTCON,T0IE return END