Hi, I have a timing problem on my coding on PIC16F887. (Datasheet for reference:http://www.kynix.com/uploadfiles/pdf8798/PIC16F887-I2fPT_95093.pdf (http://www.kynix.com/uploadfiles/pdf8798/PIC16F887-I2fPT_95093.pdf))My code want to have exact 3 second for testing and 4 second for delay. But at the end come out with the problem that the timing ain't accurate. Can anyone point out my mistake? Thank you very much. Below is my coding:
; Description: ;
; -SW simulates door switch, and should allow 3s delay for disarming before triggering the alarm. ;
; -Double click SW simulates the "disarm" switch that allows the legitimate user to avoid the alarm. ;
; -Triple click SW simulate the "arm" switch that starts the armed state after 4s. ;
; -LEDs show the present state of the system (use separate LED for every state if possible) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include "prologue.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Declaring Variable used
cblock 0x20
Value ; Assign an address 0x20 to label Value
Read ; Assign an address 0x21 to label Read
Value1 ; Assign an address 0x22 to label Value1
Read1 ; Assign an address 0x23 to label Read1
Delay1 ; Assign an address 0x24 to label Delay1
Delay2 ; Assign an address 0x25 to label Delay2
Delay3 ; Assign an address 0x26 to label Delay3
Counter ; Assign an address 0x27 to label Counter
Direction
LookingFor
Time
Test
SwitchPressed
LastStableState
Memory
Delay
Mem
endc
Start:
bsf STATUS,RP0 ; select Register Bank 1
clrf TRISD ; Make PortD all output
movlw 0x01 ; Bit one to work register
movlw 0xFF ; b'11111111'
movwf TRISA ; Make PortA all input
movwf TRISB ; Make RBO pin input (switch)
movlw b'10000010' ; PortB pull up is disable, Interrupt on rising edge of INT pin, Internal instruction cycle clock (FOSC/4)
movwf OPTION_REG ; Timer0 increment from internal clock with a prescale of 1:16
bsf STATUS,RP1 ; select Register Bank 3
movlw 0x00 ; move b'00000000' to work register
movwf ANSELH ; PortB pins are digitial (important as RB0 is switch)
bcf STATUS,RP0 ; select Register Bank 2
bcf STATUS,RP1 ; select Register Bank 0
clrf PORTD ; clear value in PORTD
clrf Counter ; clear value in Counter
movlw 1
movwf LastStableState
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MainLoop:
clrf Memory
btfsc PORTB,0
goto MainLoop
movlw b'10000000'
movwf PORTD
call DelayThreeSecond
call PressTwo
call PressThree
goto MainLoop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for Dots and Pause between the dash and dots
DelayThreeSecond:
clrf Time
WaitThreeSecond
clrf Mem ; clear value in Mem register
OneSecondWait:
clrf TMR0 ; clear Timer0
LoopTMR0:
call CheckButton
call NumberPress
movf TMR0,w ; move value in TMR0 register to work register
xorlw .250 ; wait for 4ms (250x16us)
btfss STATUS,Z ; check whether zero present in STATUS
goto LoopTMR0 ; loop back to LoopTMR0
incf Mem,f ; increase the value of Mem register by 1 and store in counter register
movlw .250 ; wait for 1s (250x4ms)
xorwf Mem,w ; move value in Mem register to work register
btfss STATUS,Z ; check whether zero present in STATUS
goto OneSecondWait ; loop back to OneSecondWait
incf Time,f ; increase the value of Time register by 1 and store in counter register
movlw .3 ; wait for 3s (3x1s)
xorwf Time,w ; move value in Time register to work register
btfss STATUS,Z ; check whether zero present in STATUS
goto WaitThreeSecond ; loop back to WaitThreeSecond
return ; return back to the next instruction after function call
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for Button Check
CheckButton:
btfsc LastStableState,0
goto ButtonNotPress
ButtonPress:
clrw
btfss PORTB,0 ; test if the switch is press
incf Counter,w ; if switch press, increase the counter
movwf Counter ; store either the 0 or incremented value
goto EndDebounce
ButtonNotPress:
clrw
btfsc PORTB,0
incf Counter,w
movwf Counter
goto EndDebounce
EndDebounce:
movf Counter,w ; have we seen 5 in a row?
xorlw 5
btfss STATUS,Z
goto Delay1mS
comf LastStableState,f ; after 5 straight, reverse the direction
clrf Counter
btfss LastStableState,0 ; Was it a key-down press?
goto Delay1mS ; no: take no action
bsf SwitchPressed,0
Delay1mS:
movlw .71 ; delay ~1000uS
movwf Delay
decfsz Delay,f ; this loop does 215 cycles
goto $-1
decfsz Delay,f ; This loop does 786 cycles
goto $-1
btfss LastStableState,0 ; Was it a key-down press?
return
goto CheckButton
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for Number Button Press
NumberPress:
btfss SwitchPressed,0
return
incf Memory
clrf SwitchPressed
return
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for Number Button Press 2 times
PressTwo:
movlw .3 ; wait for 1s (250x4ms)
xorwf Memory,w ; move value in Mem register to work register
btfss STATUS,Z ; check whether zero present in STATUS
return
movlw b'00000000'
movwf PORTD
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for Number Button Press 3 times
PressThree:
movlw .4 ; wait for 1s (250x4ms)
xorwf Memory,w ; move value in Mem register to work register
btfss STATUS,Z ; check whether zero present in STATUS
return
movlw b'00000000'
movwf PORTD
call DelayFourSecond
movlw b'01000000'
movwf PORTD
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function Delays for 4 Second
DelayFourSecond:
clrf Time
WaitFourSecond
clrf Mem ; clear value in Mem register
OneSecondDelay:
clrf TMR0 ; clear Timer0
WaitTMR0:
movf TMR0,w ; move value in TMR0 register to work register
xorlw .250 ; wait for 4ms (250x16us)
btfss STATUS,Z ; check whether zero present in STATUS
goto WaitTMR0 ; loop back to LoopTMR0
incf Mem,f ; increase the value of Mem register by 1 and store in counter register
movlw .250 ; wait for 1s (250x4ms)
xorwf Mem,w ; move value in Mem register to work register
btfss STATUS,Z ; check whether zero present in STATUS
goto OneSecondDelay ; loop back to OneSecondWait
incf Time,f ; increase the value of Time register by 1 and store in counter register
movlw .4 ; wait for 4s (4x1s)
xorwf Time,w ; move value in Time register to work register
btfss STATUS,Z ; check whether zero present in STATUS
goto WaitFourSecond ; loop back to WaitThreeSecond
return ; return back to the next instruction after function call
end
What does it exactly mean not accurate? You calculated for example 1 seconds but when you measure it is always 1,2 seconds? Or always less?
I think the problem is this:
movf TMR0,w ; move value in TMR0 register to work register
xorlw .250 ; wait for 4ms (250x16us)
btfss STATUS,Z ; check whether zero present in STATUS
goto LoopTMR0 ; loop back to LoopTMR0
incf Mem,f ; increase the value of Mem register by 1 and store in counter register
movlw .250 ; wait for 1s (250x4ms)
xorwf Mem,w ; move value in Mem register to work register
btfss STATUS,Z ; check whether zero present in STATUS
goto OneSecondWait ; loop back to OneSecondWait
You read the timer value, then you do some instructions. So you wait not only 4ms but 4ms + time of some instructions. You need to compensate the run time of your own code. Or use interrupts instead of synchronous blocking loops. Use C instead of asm, because in C you will find much more examples and help, also this microcontroller is big enough to be programmed quite reasonable in C. Also interrupthandling becomes much more easier in C if the compiler gives support for it (you do not need to save the context by hand or so)