View Single Post
  #1   Spotlight this post!  
Unread 19-05-2007, 13:50
kitscuzz's Avatar
kitscuzz kitscuzz is offline
Not alotta posts
AKA: Kit
FRC #1389 (Worst Case Scenario)
Team Role: Programmer
 
Join Date: Jan 2006
Rookie Year: 2005
Location: Home
Posts: 47
kitscuzz will become famous soon enough
PIC Assembly Followup

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).

Code:
;**********************************************************************
;																	  *
;	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'
Attached Files
File Type: zip testdisplay.zip (1.73 MB, 82 views)

Last edited by kitscuzz : 19-05-2007 at 13:54.