I stripped out the extraneous stuff and verified that this test code compiles and gives the same strange results as the whole program. It's running on a 16F1518 with an external 4MHz crystal. I watched the interrupt speed by copying the LSB of the interrupt counter variable to an output pin, and watching it on an oscilloscope.
Things to note:
- I tried Henrik's suggestion of slowing the interrupts down. Worked fine, and this stub shows missed interrupts at 725Hz, but not at 700Hz. I wanted to get to 1mS, which had worked with 2.60a and other PICs.
- I tried subbing in a different statement with the same variables (n, Value), and found that it worked fine to at least 2000Hz.
- All I can guess at is that Value is a WORD variable, and maybe the use of DIG takes longer on words. I didn't try it with a BYTE variable.
I'm well aware that I make silly mistakes in programs, but it looks to me like the use of the DIG function is what does this.
Code:
' Name : DIG Interrupt statement test
' Compiler : PICBASIC PRO 3.0
' Target PIC : 16F1518
' Oscillator : set to 4MHz external crystal
' =======================================
' RA4 = output test pin
' RA6 = Oscillator/crystal pin
' RA7 = Oscillator/crystal pin
'
DEFINE OSC 4 ; use external 4MHz crystal
' Includes for interrupts
wsave VAR BYTE $20 SYSTEM
wsave1 VAR BYTE $A0 SYSTEM
'
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
' Variable Declarations
i Var Byte ' counter for which digit is being displayed in the display Mpx
n Var Byte ' transfer variable for converting digit number to segments in lookup table
Value Var WORD '
'===============config bits=================
#CONFIG
__config _CONFIG1, _FOSC_XT & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _WDTE_OFF & _FCMEN_OFF
__config _CONFIG2, _WRT_OFF & _VCAPEN_OFF & _BORV_19 & _LPBOR_OFF & _LVP_OFF
#ENDCONFIG
'================================
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, ReloadTMR1, ASM, no ; MUST be first
INT_Handler TMR1_INT, _T1handler, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
' ============================================================
;--- Change these to match the desired interrupt frequency ----------
;*** found that 700 works, 725 or greater frequency does not***
@Freq = 725 ; Frequency of Interrupts in Hz
@Prescaler = 1 ; Timers Prescaler setting
T1CON = $00 ; $30 = Prescaler 1:8, TMR1 OFF
; $00=1:1, $10=1:2, $20=1:4, $30=1:8 -- Must match @Prescaler value
@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
GOSUB StartTimer ; Start the Timer
'======== pre- main loop code here =================
' Initialization
OSCCON = $68 ' set oscillator control for 4MHZ, external
ANSELA = 0
ANSELB = 0
ANSELC = 0
TRISB = 000000
TRISC = 111111
TRISA = 000000
PORTB = 111111
PORTA = 110111
Value = 100
'============ main loop starts here=================
mainloop:
Value = Value + 1
IF Value > 299 THEN Value = 0 ' Value increments from 0 to 299, rolls over to 0
Pause 300
GOTO mainloop
'============================================================
T1handler:
i = i +1
IF i > 3 THEN i = 0 ' force i to be 0..2 and roll over to 0
i = i & 000011
PORTA.4 = i.0 ' wiggle the output bit for debug purposes
n = Value DIG i ' this statement causes missed interrupts after four are caught
' n = Value & 000111 ' this alternative statement works fine at 2000Hz
@ INT_RETURN ' done with this interrupt pass
;---[TMR1 reload - interrupt handler]-----------------------------------------
ASM ; Calculate Timer Reload Constant
ReloadInst = 8 ; # of Intructions used to reload timer
if ((Prescaler == 1)||(Prescaler == 2)||(Prescaler == 4)||(Prescaler == 8))
MaxCount = 65536 + (ReloadInst / Prescaler)
TimerReload = MaxCount - (OSC*1000000/4/Prescaler/Freq)
if ((TimerReload < 0) || (TimerReload > (65535-ReloadInst)))
error Invalid Timer Values - check "OSC", "Freq" and "Prescaler"
endif
else
error Invalid Prescaler
endif
ENDASM
@Timer1 = TMR1L ; map timer registers to a word variable
Timer1 VAR WORD EXT
TimerReload CON EXT ; Get the External Constant
TMR1ON VAR T1CON.0 ; Alias the Timers ON/OFF bit
;---Reload Timer1------
ASM
ReloadTMR1
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(TimerReload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(TimerReload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
INT_RETURN
ENDASM
;---Start/Stop controls -----
StartTimer:
Timer1 = TimerReload ; Load Timer
TMR1ON = 1 ; start timer
RETURN
StopTimer:
TMR1ON = 0 ; stop timer
RETURN
Bookmarks