Timing problem on my coding on PIC16F887

Started by Cinderella, June 14, 2017, 12:57:16 PM

Previous topic - Next topic

Cinderella

Hi, I have a timing problem on my coding on PIC16F887. (Datasheet for reference: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



kyrk.5

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)