So a while ago I posted a thread about looking for help with assembly programming for the PIC16F819, and despite not getting a whole lot of response, I learned a lot of assembly and I’m pretty far along, but now I need some help.
I have, as I’ve said, a PIC16F819 running on the internal 4MHz clock, and yet I can’t seem to get the thing to work timer interrupts properly. Though the code I’m writing is actually a lot more complex than what I’m showing here, this is just the part that I’m obviously making mistakes on. This code should activate timer2 and timer0. Timer2 should go off every .440 milliseconds for a rather complex bit of code that isn’t implemented in this example. Timer0 should go off every 5ms. I have 4 displays so that means that each display should flicker approximately fifty times a second. But, this doesn’t happen. Not even a little bit. It’s almost as bad as 1 display for every half-second.
The setup I gave Timer0 was prescaler 1:32 and offset of 100. I tried fiddling with these values, going so far down as a 1:2 ratio and it was still going too slowly. If anyway can give me a hand, the code is attached (the reason the file is so big is because it includes the PIC16F819 manual).
;**********************************************************************
; *
; This program is a template for later, more complex programs *
; currently this should only use TIMER0 to display 0, 4, 8, and F *
; in the appropriate displays. *
; *
;**********************************************************************
; *
; Filename: timerplusdisplaytest.asm *
; Date: May 1st, 2007 *
; *
; Author: Kit Sczudlo *
; *
; *
;**********************************************************************
; *
; Files required: *
; none *
; *
; *
;**********************************************************************
; *
; Notes: *
; Currently will not properly fire the interrupt. *
; Goes at about 1/100 of the expected speed. *
; *
; *
;**********************************************************************
list p=16F819 ; list directive to define processor
#include <p16F819.inc> ; processor specific variable definitions
errorlevel -302 ; suppress message 302 from list file
cblock h'20' ; Define our variables starting at valid ram
w_temp ; variable used for context saving
status_temp ; variable used for context saving
curdisp ; Variable that contains the address of the current display routine
disp0 ; Variable that has the sevent segment info for disp0
disp1 ; Variable that has the sevent segment info for disp1
disp2 ; Variable that has the sevent segment info for disp2
disp3 ; Variable that has the sevent segment info for disp3
tmr2cnt ; current number of iterations since tmr2 was last reset
temp ; for calculating things in mid-signal retrieval
endc
;**********************************************************************
ORG 0 ; Reset Vector
goto main ; go to beginning of program
ORG 4 ; Interrupt Vector
goto isr ; Run an interrupt
ORG 8 ; Interrupt Service routines
isr:
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
; isr code goes here
btfsc INTCON,TMR0IF ; Check to make see if this was the timer 0 interrupt
goto tmr0 ; If so, jump up to the timer0 routine
btfsc PIR1,TMR2IF ; Check to see if the Timer2 flag is set
goto tmr2 ; If this is the timer2 flag, goto timer 2 routine
goto isrdone ; If we have no $@#$@#$@#$@#ing clue what interrupt it was, end the routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Timer 0 Code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tmr0:
bcf INTCON,TMR0IF ; Clear our interrupt request flag to avoid headache
movlw d'100' ; Get our offset setup for timer0
movwf TMR0 ; And put it into the timer0 count
clrf PORTA ; Turn off PORTA (no displays on)
movf curdisp,W ; Grab the address of the next display to jump to
movwf PCL ; Put that address into the instruction counter
display0:
movf disp0,W ; grab the current display info for display 0
movwf PORTB ; Set up PORTB so that our display works
bsf PORTA,0 ; Turn on the display
movlw #display1 ; grab the address of the next display routine
movwf curdisp ; and put it into the current display
goto isrdone ; Jump to the end
display1:
movf disp1,W ; grab the current display info for display 1
movwf PORTB ; Set up PORTB so that our display works
bsf PORTA,1 ; Turn on the display
movlw #display2 ; grab the address of the next display routine
movwf curdisp ; and put it into the current display
goto isrdone ; Jump to the end
display2:
movf disp2,W ; grab the current display info for display 2
movwf PORTB ; Set up PORTB so that our display works
bsf PORTA,2 ; Turn on the display
movlw #display3 ; grab the address of the next display routine
movwf curdisp ; and put it into the current display
goto isrdone ; Jump to the end
display3:
movf disp3,W ; grab the current display info for display 3
movwf PORTB ; Set up PORTB so that our display works
bsf PORTA,3 ; Turn on the display
movlw #display0 ; grab the address of the next display routine
movwf curdisp ; and put it into the current display
goto isrdone ; Jump to the end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; End Timer 0 Code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;**********************************************************************************************;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Timer 2 Code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tmr2:
bcf PIR1,TMR2IF ; Clear the timer 2 flag to avoid headaches
incf tmr2cnt,F ; increment the timer2 count
goto isrdone ; We've finished, so end the routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; End Timer 2 Code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
isrdone:
; end interrupt code section
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f ; To preserve status flags we use 2 swapf instructions instead of a movf
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lookup_7seg: ; lookup table for 7 segment display
addwf PCL,F ; Jump to the value specified in W (add to instruction counter)
retlw b'01110111' ; Return the correct seven segment setup for '0'
retlw b'01000010' ; for '1'
retlw b'00111011' ; for '2'
retlw b'01101011' ; for '3'
retlw b'01001110' ; for '4'
retlw b'01101101' ; for '5'
retlw b'01111101' ; for '6'
retlw b'01000111' ; for '7'
retlw b'01111111' ; for '8'
retlw b'01001111' ; for '9'
retlw b'01011111' ; for 'A'
retlw b'01111100' ; for 'B'
retlw b'00110101' ; for 'C'
retlw b'01111010' ; for 'D'
retlw b'00111101' ; for 'E'
retlw b'00011101' ; for 'F'
main:
;;;;;;;;;;;;;;;;;;;;;;;; Setup PIC ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BANKSEL PORTA ; move back to the regular bank
bcf ADCON0,ADON ; turn off the analog to digital converter
clrf PORTA ; Clear output data latches
clrf PORTB ; Clear output data latches
BANKSEL ADCON1 ; move to the right bank
movlw b'00000110' ; Prepare to mess with porta (set all as digital i/o ports)
iorwf ADCON1,F ; Load the configuration data, but leave everything else alone
BANKSEL TRISA ; move to the right bank
clrf TRISA ; make all of porta outputs
BANKSEL PORTA ; move back to the regular bank
BANKSEL TRISB ; move to the right bank
movlw b'10000000' ; Set up W with the correct values for a pin 8 being an input
movwf TRISB ; make all PORTB pins outputs, except for pin 8
BANKSEL INTCON ; We need to be in bank 0 for everything else
;;;;;;;;;;;;;;;;;;;;;;;; End PIC Setup ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;; Initialization ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
clrf PORTA ; Set all ports on PORTA 'off'
clrf PORTB ; Set all ports on PORTB 'off'
movlw #display0 ; get the address for the first display function
movwf curdisp ; and put it into the current display
clrw ; Make W = 0
call lookup_7seg ; And get the correct 7 segment display for W
movwf disp0 ; and put that display info into disp0,
movlw h'4' ; Put 5 in W
call lookup_7seg ; And get the correct 7 segment display for W
movwf disp1 ; disp1,
movlw h'8' ; Put 9 in W
call lookup_7seg ; And get the correct 7 segment display for W
movwf disp2 ; disp2,
movlw h'F' ; Put F in W
call lookup_7seg ; And get the correct 7 segment display for W
movwf disp3 ; and disp3
bsf T2CON,2 ; Enable our interrupt
; Setup our interrupt configuration information
movlw b'01000000' ; Enable peripheral interrupts
; But turn off timer0, rb0, and portb port change interrupts
movwf INTCON ; Store those new values in the interrupt configuration bits
; and blow out all registered interrupts
BANKSEL PIE1 ; Jump to the right bank
movlw b'00000010' ; Turn off all peripheral interrupts except Timer2
movwf PIE1 ; And store those values into the peripheral config bits
BANKSEL PIR1 ; Jump back to bank0
clrf PIR1 ; To destory all frivilous interrupt info
clrf PIR2 ; To destory all frivilous interrupt info
; Setup Timer2 to go off ~ every .440 milliseconds (a tiny bit less than half our expected ir signal time)
movlw d'220' ; Get our PR2 value set up in W
movwf PR2 ; and put it into PR2
movlw b'00001100' ; bits 6-3: Set Timer2 postscaler to 1:2,
; bit 2 : and turn it on
; bits 1-0: prescaler to 1:1,
movwf T2CON ; Put the configuration bits in Timer2 config
bcf PIR1,1 ; Clear the interrupt bit
; Setup Timer0 to go off every approx. 5 ms. This provides a good refresh rate for our displays (approximately 28 times a second)
clrwdt ; Clear the watchdogtimer (should be off, but it never hurts to check)
BANKSEL OPTION_REG ; We need to edit option_reg to mess with timer0, so get in the right bank
movlw b'11000000' ; We want to set up timer0 so
andwf OPTION_REG,F ; we mask everything off that we want off, and leave bits 6 and 7 alone
bsf OPTION_REG,PS2 ; Set the prescaler to 1:32 on Timer0
BANKSEL INTCON ; We need to be back in BANK0, so let's get there
movlw d'100' ; Get our offset setup for timer0
movwf TMR0 ; And put it into the timer0 count
bsf INTCON,TMR0IE ; Everything else in INTCON was set up earlier, so just turn on TIMER0
bsf INTCON,GIE ; Now activate the global interrupt info
goto $ ; Make an infinite loop here to double check display status
END ; directive 'end of program'
```<br><br><a class='attachment' href='/uploads/default/original/3X/c/2/c224ef466e53104f15474ad2c3595b3144ac10a4.zip'>testdisplay.zip</a> (1.73 MB)<br><br><br><a class='attachment' href='/uploads/default/original/3X/c/2/c224ef466e53104f15474ad2c3595b3144ac10a4.zip'>testdisplay.zip</a> (1.73 MB)<br>