Start_Timer1:
banksel PIE1 ;Bank 1
bsf PIE1, CCP1IE ;enable Timer1 compare mode interrupt
;Set Generate Software Interrupt Mode in Timer1 Compare Mode
;CCP1CON: CCP1 CONTROL REGISTER
; P1M | DC1B | CCP1M |
; 7 6 5 4 3 2 1 0
banksel CCP1CON ;bank 5
movlw b'00001010'
movfw CCP1CON
;Set Timer1 to count controlled by the Timer1 gate function
;T1GCON: TIMER1 GATE CONTROL REGISTER
; TMR1GE | T1GPOL | T1GTM | T1GSPM | T1GGO-/DONE | T1GVAL | T1GSS |
; 7 6 5 4 3 2 1 0
banksel T1GCON ;Bank 0
movlw b'10000000'
movfw T1GCON
;Clearing the interrupt flag and the counter before starting Timer1 is
;recommended by the datasheet
clrf PIR1 ;clear all peripheral interrupt flags
clrf TMR1L ;clear both bytes of the
clrf TMR1H ;Timer1 counter
;and lastly, set Timer1 parameters and turn it on
;T1CON:
; TMR1CS | T1CKPS |T1OSCEN| /T1SYNC | - | TMR1ON|
; 7 6 5 4 3 2 1 0 |
;Clock source is pin or oscillator (10) TMR1CS
;Prescaler is 1:1 (00) T1CKPS
;Oscillator circuit enabled (1) T1OSCEN
;External Clock Input Sync disabled (0) /T1SYNC
;bit 1 is not used (0) -
;Timer1 start (1) TMR1ON
movlw b'10001101'
movwf T1CON
return
I forgot that article by Roman. It’s perfectly applicable.
It doesn't have to. In the Software Interrupt Mode - interrupt when timer matches the CCP register (CCPIM = 1010) - or the Special Event Trigger - Interrupt and clear TIMER 1 on a match (CCPIM = 1011) - the output pin is not used. See 24.2.3 and 24.2.4 in the datasheet.I think I found the culprit... according to this document, if one wishes to enable CCP-Compare Mode, the TRIS bit for the CCPx pin must be cleared to place said pin in output mode.
; This sample program sets timer 1 / CCP1 up to interrupt when the timer
; reaches a count of 32768. It ALSO interrupts when the timer overflows
; after another 32768 counts. When uses with a 32768Hz oscillator, the
; result is that the OneSecondTik flag gets set once each 32768 counts
; i.e. once each second.
; Using both interrupts this way means you don't have to use the special
; event trigger to reset TIMER1 and interfere with any ADC operations you
; might have running. If you are not using ADC, you can just use the
; special event trigger and delete the TMR1 interrupt stuff.
; NOTE: on MPSIM, there is a little jitter between the interrupt
; service time for CCPIF and TMR1IF. The jitter averages out and the
; total time for one CCP, TMR1 interrupt cycle is 2x32768 counts meaning
; average, the flag gets set once each second.
; I haven't run it on actual hardware to see if that is a sim issue or
; something else.
; This runs on MPASM 5.87 / MLABX 5.10. MPLABX 5.40 has a stripped down
; assembler that may not like some of the switches/defines..
INCLUDE <p16lf1823.inc>
ERRORLEVEL -302 ; suppress cross bank messages
;----------------
UseInternalOSC equ 1 ; for simulator initial tests, set to 0 for ext osc.
; see below
;----------------
cblock 20h ; RAM
TimerFlags : 1 ; declare a byte of flags
endc
#define OneSecondTik TimerFlags,0 ; LS bit is the flag
ORG 0
nop
goto main
;--------------- INTERRUPT SERVICE ---------------------
; Services interrupts from CCP1 and TIMER1 overflow.
; Expects those as only sources of interrupts as there is
; no testing of the flags - expand as req'd
; Expects standard PIC16F1xxx context saving
ORG 0004h
banksel TimerFlags
bsf OneSecondTik ; indicate that a tik happened
banksel PIR1
bcf PIR1,TMR1IF ; only one will be set at a time
bcf PIR1,CCP1IF
retfie
;------------------ INIT --------------------------------
; Set up TIMER 1 for interrupt on compare AND timer overflow
Start_Timer1:
; Because this is callable, kill TMR/CCP interrupts while starting up.
; Can be ommitted iff this routine is only executed after a full reset
banksel PIE1 ; kill interrupts while starting up
bcf PIE1,CCP1IE
bcf PIE1,TMR1IE
banksel T1CON ; be sure timer is off while configuring
clrf T1CON
banksel CCP1CON ; bank 5
movlw b'00001010' ; software interrupt on match
movwf CCP1CON
movlw low .32768 ; set initial compare value
movwf CCPR1L
movlw high .32768
movwf CCPR1H
MESSG "Start_Timer1: GATE mode disabled"
if UseInternalOSC
MESSG "Start_Timer1: Using internal Fosc"
movlw b'00000000' ; Sim: internal Tcyc, 1:1 prescale, OFF
movwf T1CON
else
MESSG "Start_Timer1: Using external oscillator"
movlw b'10001100' ; Ext oscillator, 1:1 prescale, no sync, OFF
movwf T1CON
endif
;Clearing the interrupt flag and the counter before starting Timer1 is
;recommended by the datasheet
banksel PIR1
clrf TMR1L ; clear both bytes of the
clrf TMR1H ; Timer1 counter
bcf PIR1,TMR1IF ; clear interrupt flags
bcf PIR1,CCP1IF
banksel PIE1 ; Bank 1
bsf PIE1, CCP1IE ; enable Timer1 compare mode interrupt
bsf PIE1, TMR1IE ; enable TMR1 overflow interrupt
banksel T1CON ; bank 0
clrf TimerFlags ; clear flags
bsf INTCON,PEIE ; enable peripheral interrupts
bsf T1CON,TMR1ON ; start the timer
return
;--------------- MAIN ----------------------------------
main:
call Start_Timer1 ; configure timer
bsf INTCON,GIE ; finally, enable interrupts
banksel TimerFlags
wait_loop:
nop
nop
nop
btfss OneSecondTik
goto wait_loop
bcf OneSecondTik ; one second has elapsed
nop
nop
goto wait_loop
END
;FILE: Cmartinez_ChangeCCP.asm
; This sample program sets CCP1 up to interrupt when the timer
; reaches a nominal count of 32768. It then adds 32768 to the CCP
; register value for the next IRQ after another 32768 counts.
; See BONUS below for more control over the interval.
; As written, when used with a 32768Hz oscillator, the
; result is that the OneSecondTik flag gets set once each 32768 counts
; i.e. once each second.
; This version does not exhibit the simulator jitter that the one using
; both CCP and TIMER1 interrupts did.
; A BONUS is that the number of counts between interrupts is not limited
; to 32768. The number of counts can be tuned at build time by changing
; CCPcountsN.
; There is no reason why the number of counts couldn't be determined on
; the fly or fetched for each cycle from a list of values to implement
; some of the fine tuning described earlier in the thread.
; On the sim, the cycle count follows exactly the value of CCPcountsN.
; As before:
; Changing the CCP value means you don't have to use the special
; event trigger to reset TIMER1 and interfere with any ADC operations you
; might have running. If you are not using ADC, you can just use the
; special event trigger and delete the TMR1 interrupt stuff.
; This runs on MPASM 5.87 / MLABX 5.10. MPLABX 5.40 has a stripped down
; assembler that may not like some of the switches/defines..
INCLUDE <p16lf1823.inc>
ERRORLEVEL -302 ; suppress cross bank messages
;----------------
UseInternalOSC equ 1 ; for simulator initial tests, set to 0 for ext osc.
; see below
;----------------
cblock 20h ; RAM
TimerFlags : 1 ; declare a byte of flags
endc
#define OneSecondTik TimerFlags,0 ; LS bit is the flag
CCPcountsN equ .32768 ; how much to advance CCPR1 on each IRQ
ORG 0
nop
goto main
;--------------- INTERRUPT SERVICE ---------------------
; Services interrupts from CCP1 and TIMER1 overflow.
; Expects those as only sources of interrupts as there is
; no testing of the flags - expand as req'd
; Expects standard PIC16F1xxx context saving
ORG 0004h
banksel TimerFlags
bsf OneSecondTik ; indicate that a tik happened
banksel CCPR1L
movlw low CCPcountsN ; move CCP ahead by N counts
addwf CCPR1L,F
movlw high CCPcountsN
addwfc CCPR1H,F
banksel PIR1
bcf PIR1,TMR1IF ; only one will be set at a time
bcf PIR1,CCP1IF
retfie
;------------------ INIT --------------------------------
; Set up TIMER 1 for interrupt on compare AND timer overflow
Start_Timer1:
; Because this is callable, kill TMR/CCP interrupts while starting up.
; Can be ommitted iff this routine is only executed after a full reset
banksel PIE1 ; kill interrupts while starting up
bcf PIE1,CCP1IE
bcf PIE1,TMR1IE
banksel T1CON ; be sure timer is off while configuring
clrf T1CON
banksel CCP1CON ; bank 5
movlw b'00001010' ; software interrupt on match
movwf CCP1CON
movlw low CCPcountsN ; set initial compare value
movwf CCPR1L
movlw high CCPcountsN
movwf CCPR1H
MESSG "Start_Timer1: GATE mode disabled"
if UseInternalOSC
MESSG "Start_Timer1: Using internal Fosc"
movlw b'00000000' ; Sim: internal Tcyc, 1:1 prescale, OFF
movwf T1CON
else
MESSG "Start_Timer1: Using external oscillator"
movlw b'10001100' ; Ext oscillator, 1:1 prescale, no sync, OFF
movwf T1CON
endif
;Clearing the interrupt flag and the counter before starting Timer1 is
;recommended by the datasheet
banksel PIR1
clrf TMR1L ; clear both bytes of the
clrf TMR1H ; Timer1 counter
bcf PIR1,TMR1IF ; clear interrupt flags
bcf PIR1,CCP1IF
banksel PIE1 ; Bank 1
bsf PIE1, CCP1IE ; enable Timer1 compare mode interrupt
; bsf PIE1, TMR1IE ; don't enable TMR1 overflow interrupt
banksel T1CON ; bank 0
clrf TimerFlags ; clear flags
bsf INTCON,PEIE ; enable peripheral interrupts
bsf T1CON,TMR1ON ; start the timer
return
;--------------- MAIN ----------------------------------
main:
call Start_Timer1 ; configure timer
bsf INTCON,GIE ; finally, enable interrupts
banksel TimerFlags
wait_loop:
nop
nop
nop
btfss OneSecondTik
goto wait_loop
bcf OneSecondTik ; one second has elapsed
nop
nop
goto wait_loop
END
Those are typos... I don't like to use the movfw either, I'd rather stick to natural and unaltered code instead of macros.... but the compiler is accepting that crap... dang it! ... is there a way to turn that off?Also, you used movfw in a couple of places instead of movwf to store W in the register
Worth a try...#undefine movfw ??
Depends on where it’s defined I would guess.Worth a try...

Price IS an issue... but so is accuracy. Your suggestion looks promising, and I'll be taking a serious look at it. Many thanks!I would be very surprised if your oscillator is running within 5ppm of 32.768kHz. Although the crystal is specified to give you this stability (at 25C), this only specifies the stability of the series resonance frequency with a 12.5pF load. Rough calculations suggest that fractions of a pF in your loading capacitance will cost you the full 5ppm. Your board layout is one thing - I can see spare picofarads all over the place, but also important is the loading provided by the PIC. Maybe it is well defined enough and stable to give you the stability you want, but I'm skeptical.
Unless price is an issue, low ppm stability is best left to the experts, a quick look on Digikey shows devices like:
View attachment 222337
for less than $2 for 5ppm you will sleep easier!
I have a scribble project and tried #undefine movfw to remove it. That does not work as intended. That is, the code assembles fine and continues to work as expected if movfw is used.Depends on where it’s defined I would guess.
Genius.I have a scribble project and tried #undefine movfw to remove it. That does not work as intended. That is, the code assembles fine and continues to work as expected if movfw is used.
If instead, you use #define movfw but do not use "movfw," it also assembles fine and the code works as expected. But, if you should happen to use movfw in the code, you get an error during assembly:
Error(15)...Duplicate label ("Old" or redefining symbol that cannot be redefined).
No way. I must admit I am getting ready for dinner...Genius.
11: #define movfw movwf
12: ;*******************************************************************************
13: cblock 0x20
14: Old
15: New
16: endc
17:
18: ;*******************************************************************************
19: org 0x0000
0000 3180 MOVLP 0 20: pagesel Start
0001 2802 GOTO 0x2 21: goto Start
22: Start
0002 3028 MOVLW 0x28 23: movlw 40
0003 00A1 MOVWF 0x21 24: movwf New
0004 03A1 DECF 0x21, F 25: decf New
0005 00A0 MOVWF 0x20 26: movfw Old
0006 0000 NOP 27: nop
28: