Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   PIC Assembly Followup (http://www.chiefdelphi.com/forums/showthread.php?t=57564)

kitscuzz 19-05-2007 13:50

PIC Assembly Followup
 
1 Attachment(s)
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'


Mike Bortfeldt 19-05-2007 14:43

Re: PIC Assembly Followup
 
Kit,

I haven't taken a good look at your code, but I was wondering how you know that your processor is running at a 4mhz clock speed? Specifically, what are your configuration bits set for and if you are using the internal clock, what is the setting for the oscillator post scaler. In the manual, this would be chapter 12.1 and chapter 4.5.3 (oscillator configuration). It appears that the default bit setup for OSCCON is for a 31.25 khz frequency, not 4mhz. That would make your 5 millisecond interrupt actually more like 640 milliseconds. While I am certainly no expert in assembly language PIC programming, I did play around with it a little last year. Code that I developed usually had a line such as the following at the top of the code to ensure the configuration bits were set correctly

__config _INTOSCIO & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF

These flags are usually found in the .h file for the specific processor (this is for a PIC 12F683). If this doesn't help, let me know and I'll take a closer look at your code.

Mike

kitscuzz 19-05-2007 18:08

Re: PIC Assembly Followup
 
Thanks! Sure enough it was that I hadn't configured the oscillator properly. Though it didn't have to do with the __config block. If you don't use the linker then you just have to manually set the config block in your programmer. Anyway, thanks for the tip!

--Kit

FIRST JerseyKid 20-05-2007 15:15

Re: PIC Assembly Followup
 
Can you see the light blinking if your having it blink 50 times a second? I thought it was just look dimmer.

Also if you need any help with Pic programming e-mail me at FirstJerseyKid@comcast.net . I've programmed a bunch of Pics in assembly to do a bunch of hard projects.

Alan Anderson 20-05-2007 16:37

Re: PIC Assembly Followup
 
Quote:

Originally Posted by FIRST JerseyKid (Post 628130)
Can you see the light blinking if your having it blink 50 times a second? I thought it was just look dimmer.

Kit didn't describe the hardware in detail, but the code makes it look like there are multiple seven-segment displays, each enabled in turn. The light isn't simply blinking; it's moving from one display to the other to make it possible to show several numbers with only one set of outputs.

kitscuzz 26-05-2007 17:57

Re: PIC Assembly Followup
 
Yes, that's exactly what I'm doing. Now I'm trying to use the IR recievers from a few years ago to use the four seven-segment displays to show the information sent by remote controls (the kind you use with your TV). Anyway, the code is being written now. I'm not really too sure I know what the best way to go about it is though, or what protocol to code for. The main apprehension I'm having is that I know the internal oscillator is only accurate to about 15-20% of the calculated frequency, and I'm trying to figure out a good way to base the calculations I'm doing based on probability, rather than accuracy.

Anyway, I'll post some code later when I have the chance, but here's a video of the hardware doing it's thing with some very simple scrolling text:
Thanks Mike!

Mike Bortfeldt 29-05-2007 20:12

Re: PIC Assembly Followup
 
Kit,

Looks great! Glad I could help. While I haven't been able to find your reference to the 15-20% oscillator accuracy (I'm sure it's in the manual somewhere), you'll probably find that the accuracy is much better than that. I would expect 15-20% to be the absolute maximum. Also, if you have the testing equipment necessary to measure the actual frequency, you can adjust the internal frequency using the OSCTUNE register. A more crude measurement would be set up a timer to blink an led and count the number of times it turns on/off over a set interval (for example, a 1 second blink rate over a 100 second period would give you a good idea if your oscillator is way off - or in your case, a 1 second timer with the number of blinks outputted to your LEDs!)

Let me know how it works out.

Mike


All times are GMT -5. The time now is 00:22.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi