Olimex Support Forum

Microcontrollers => PIC => Topic started by: Cinderella on June 14, 2017, 12:57:16 pm

Title: Timing problem on my coding on PIC16F887
Post by: Cinderella on June 14, 2017, 12:57:16 pm
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


Title: Re: Timing problem on my coding on PIC16F887
Post by: kyrk.5 on June 14, 2017, 05:43:33 pm
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)