list p=16f877a
include "p16f877a.inc"
errorlevel -302
__config _LVP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BODEN_OFF & _DEBUG_OFF
cblock 0x020 ;start of general purpose registers
H1
H2
L1
L2
AnsH
AnsL
endc
; Start at the reset vector
org 0x000
goto Start
Start org 0x010
clrf PORTB
clrf PORTD
clrf PORTC
clrf H1
clrf H2
clrf L1
clrf L2
clrf AnsH
clrf AnsL
clrf TMR1H
clrf TMR1L
; clrf CCP1CON
clrf CCPR1H
clrf CCPR1L
bsf STATUS,RP0 ;bank 1
bcf STATUS,RP1
movlw b'00000100'
movwf TRISC
movlw b'00000000'
movwf TRISB ;portb [7-0] outputs
movlw b'00000000'
movwf TRISD ;portd output
movlw 0x06
movwf ADCON1
; all inputs DIGITAL
bcf STATUS,RP0 ;bank0
;**********************************************
Main:
movlw b'00000001' ;timer 1 using to capture, prescaler 1:1
movwf T1CON
movlw b'00000101'
movwf CCP1CON ;start with rising CAPTURE
bcf PIR1,CCP1IF
Wait:
btfss PIR1,CCP1IF
goto Wait
movf CCPR1H,W ;save the value in H2 and L2 {lower value}
movwf H2
movf CCPR1L,W
movwf L2
bcf PIR1,CCP1IF
;
movlw b'00000100' ;config CCP1 to faling
movwf CCP1CON
bcf PIR1,CCP1IF
Wait1:
btfss PIR1,CCP1IF
goto Wait1
movf CCPR1H,W ;save now the value in H1,L1
movwf H1
movf CCPR1L,W
movwf L1
bcf PIR1,CCP1IF ;clr flag CCP1
;SUB Higher value H2,L2 from current captured value H1,L1
SUB:
movf L2,W
subwf L1,W
movwf AnsL
movwf PORTB
btfss STATUS, C
goto BORROW
goto SUB_1
BORROW:
decf H1, F
SUB_1: movf H2,W
subwf H1,W
movwf AnsH
movwf PORTD
goto Main
;************************************************
end
Are you sure that your signal generator was set to 1KHz and 10KHz?bjox1 said:Hi Mike,
Mate, I have tried using the code below and I am getting some weird values on PORTD and PORTB.
Basically, I am using a signal generator with TTL square wave. When the input is 1kHz, the value on PORTD [HIGH byte] is 1 and the value on PORTB is 244 [in binary]. I was hoping to get a value of the half period [width of the signal] i.e. 2 msec. And when I am using a signal of 10kHz, the only value is on PORTB which is 51[in binary].
Please enlighten me on this.
Cheers.
Mike, i am getting 2kHz where I am supposed to get 500Hz. [1us times 500 =2kHz]frequency = 5,000,000 / time = 5,000,000 / 500 = 10,000 = 10 KHz
Mike, Just now I have double checked it using an oscilloscope.Are you sure that your signal generator was set to 1KHz and 10KHz?
bjox1 said:I think I made a fool of myself.
I guess,I am not sure, but 1kHz is 1000us in time. Halving it gives 500us. So half in time domain is double in freq domain. Thus 2kHz.
Mike, please advice me if I am correct.
Mike,Pommie said:As Mike50 isn't around, I'll answer your question.
As your crystal is 4MHz then the timer is clocked at 1MHz or every 1uS. Therefore your frequency calculation is,
frequency = 1,000,000 / time = 1,000,000 / 500 = 2,000 = 2 KHz
As you are only measuring half the waveform, from rising to falling edge, you are getting a value that is double the frequency. Hence your frequency is 1kHz.
Mike.
Well that depends on how much accuracy you need. But, best you can do will depend on how many instructions you execute between the time that CCP1IF turns on and the time that you are ready to read it again. In the code you have running that comes to about 13 instruction times. With your 4MHz clock, that is about 13 microseconds. From the time you copy out the capture register until the next time you could copy it out is about 13 microseconds. So the highest frequency you could detect would be about 77 KHz. But that is well above the highest frequency you said you needed to detect (which was 10 KHz).bjox1 said:Brilliant explanation guys!
I truly appreciate that.
-I was wondering what will be the max freq up to I can measure the width?
Well, what do you think? You could use it to round the answer, but personally I wouldn't worry about it.bjox1 said:and - While doing the 16 bit division, do I need the 16 bit remainder value as well??
mike50 said:With the 4 MHz clock and a 10 KHz signal, there are 100 clocks from leading edge to leading edge. So you wouldn't be able to measure the phase angle to a precision better than about 4 degrees. At 20 MHz you could measure it to within 1 degree.
Mike
bjox1 said:Thanks a trillion Mike. I really appreciate that.
But how did you calculate 4 deg??
list p=16f877a
include "p16f877a.inc"
errorlevel -302
__config _LVP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BODEN_OFF & _DEBUG_OFF
cblock 0x020 ;start of general purpose registers
CCP1aH
CCP1aL
CCP1bH
CCP1bL
CCP2H
CCP2L
topH
endc
cblock 0x070
topL
btmH
btmL
qH
qL
count
index
endc
; Start at the reset vector
org 0x000
goto Start
Start org 0x010
clrf PORTB
clrf PORTD
clrf PORTC
clrf CCP1aH
clrf CCP1aL
clrf CCP1bH
clrf CCP1bL
clrf CCP2H
clrf CCP2L
clrf TMR1H
clrf TMR1L
clrf count
clrf topH
clrf topL
clrf btmH
clrf btmL
; clrf CCP1CON
clrf CCPR1H
clrf CCPR1L
clrf CCPR2H
clrf CCPR2L
bsf STATUS,RP0 ;bank 1
bcf STATUS,RP1
movlw b'00000110'
movwf TRISC
movlw b'00000000'
movwf TRISB ;portb [7-0] outputs
movlw b'00000000'
movwf TRISD ;portd output
; all inputs DIGITAL
bcf STATUS,RP0 ;bank0
; bcf PIR1,CCP1IF
;**********************************************
Main:
movlw b'00000000' ;timer 1 using to capture, prescaler 1:1
movwf T1CON
bsf T1CON,TMR1ON
movlw b'00000101'
movwf CCP1CON ;start with rising CAPTURE
movlw b'00000101'
movwf CCP2CON ;start CCP2 with rising CAPTURE
bcf PIR1,CCP1IF
bcf PIR2,CCP2IF
Wait:
btfss PIR1,CCP1IF
goto Wait
movf CCPR1H,W ;save the value in H2 and L2 {lower value}
movwf CCP1aH
movf CCPR1L,W
movwf CCP1aL
bcf PIR1,CCP1IF
;
Wait1:
btfss PIR1,CCP1IF
goto Wait1
movf CCPR1H,W ;save now the value in H1,L1
movwf CCP1bH
movf CCPR1L,W
movwf CCP1bL
bcf PIR1,CCP1IF ;clr flag CCP1
Wait2
btfss PIR2,CCP2IF
goto Wait2
movf CCPR2H,W ;save now the value in H1,L1
movwf CCP2H
movf CCPR2L,W
movwf CCP2L
bcf PIR2,CCP2IF ;clr flag CCP1
;*********CCP1b-CCP1a*******************
SUB1:
;*******CCP2-CCP1b****************
SUB2:
;***********DIVISION***********************
Div:
call Divide
movf qL,w ;@@@@@ RESULTS @@@@@@
movwf PORTB
movf qH,w ; on LEDs connected to rb and rc.
movwf PORTD
goto Main ;-------LOOP BACK TO START----
Divide:
movf btmH,w ; Check for division by 0.
iorwf btmL,w
btfsc STATUS,Z
bsf PORTB,0 ; //**Error code If btm is Zero:PORTB PIN 0 Light LED//**
movlw d'1' ; Otherwise, initialize variables
movwf count
clrf index ; for the division.
clrf qH
clrf qL
Divide_sh_loop:
btfsc btmH,7 ; Shift divisor left
goto Divide_d1
bcf STATUS,C ; until msb is in
rlf btmL,1 ; btmH.7.
rlf btmH,1 ; count = no. of shifts+1.
incf count,1
goto Divide_sh_loop
Divide_d1:
bcf STATUS,C
rlf qL,1 ; Shift quotient left.
rlf qH,1
movf btmL,w ; top = top - btm.
subwf topL,1
btfsc STATUS,C ; If top - btm < 0 then
goto Divide_d2
movlw d'1' ; top = top + btm
subwf topH,1
btfsc STATUS,C ; The idea is to do the
goto Divide_d2
incf topH,1 ; the subtraction and comparison
movf btmL,w ; (top > btm?) in one step.
addwf topL,1
goto Divide_reentr ; Then, if btm > top, undo
Divide_d2:
movf btmH,w ; the subtraction by adding
subwf topH,1
btfss STATUS,C ; top and btm back together
goto Divide_less ;
bsf qL,0
Divide_reentr
bcf STATUS,C
rrf btmH,1
rrf btmL,1
decfsz count,1
goto Divide_d1
retlw 0h ; Return w/ remainder in top
; and result in q.&nsp;
Divide_less
movf btmL,w ; btm > top, so
addwf topL,1
btfsc STATUS,C ; undo the subtraction by
incf topH,1 ; adding them back together.
movf btmH,w
addwf topH,1
goto Divide_reentr ;
end
Yes, of course. Don't you remember that you need to multiply by 360 BEFORE you do the divide?bjox1 said:Mike,
Thank you once again for ur kind explanation.
Mate, After successfully doing the width exercise, I have attempted the actual code. The code is set to find the phase difference between CCP1 and CCP2 pin signals. I am not getting any values on the output LEDs.
I am feeding 1kHz signal on CCP1 pin and the CCP2 pin has the same signal with 150 us delay.
So CCP1- 1kHz signal
CCP2 pin – 1kHz with 150 usec delay.
My code does this:
- Capture CCP1a , CCP1b and CCP2.
- Sub -routine ‘SUB1’ subtracts CCP1a from CCP1b to give me the period of the signal. The 16 bit ans is then saved in memory reg btmH and btmL. i.e. Bottom H and Bottom L [bottom refers to the denominator in the Division sub- routine].
- Then sub-routine ‘SUB2’ subtracts CCP1b from CCP2 and the ans is saved in memory registers topH and topL [Top refers to the numerator].
- Then the sub-routine ‘Div’ performs 16 by 16 bit division and put the quotient [RESULTS] value in qH and qL thus on PORTD and PORTB.
Mike, I am not even getting any values on the LEDs.
Could you please look at my code. The division routine worked fine separately. I am guessing the division might be the wrong bit.
-As the numerator [delay value between 0-1000] is going to be always smaller than the denominator[the denominator,time period, is 1000], the quotient will always be less the 1. Is that the reason my code doesn’t work??
Hard to say what you are expecting, but if you had multiplied by 360 before doing the divide, I would expect that the result would be 54 degrees.bjox1 said:- Mike, with 150 usec delay, what value will I be expecting on the LEDs??
bjox1 said:I will be very very grateful if you could help me on this as well.
Thanks again mike.
Code:list p=16f877a include "p16f877a.inc" errorlevel -302 __config _LVP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BODEN_OFF & _DEBUG_OFF cblock 0x020 ;start of general purpose registers CCP1aH CCP1aL CCP1bH CCP1bL CCP2H CCP2L topH endc cblock 0x070 topL btmH btmL qH qL count index endc ; Start at the reset vector org 0x000 goto Start Start org 0x010 clrf PORTB clrf PORTD clrf PORTC clrf CCP1aH clrf CCP1aL clrf CCP1bH clrf CCP1bL clrf CCP2H clrf CCP2L clrf TMR1H clrf TMR1L clrf count clrf topH clrf topL clrf btmH clrf btmL ; clrf CCP1CON clrf CCPR1H clrf CCPR1L clrf CCPR2H clrf CCPR2L bsf STATUS,RP0 ;bank 1 bcf STATUS,RP1 movlw b'00000110' movwf TRISC movlw b'00000000' movwf TRISB ;portb [7-0] outputs movlw b'00000000' movwf TRISD ;portd output ; all inputs DIGITAL bcf STATUS,RP0 ;bank0 ; bcf PIR1,CCP1IF ;********************************************** Main: movlw b'00000000' ;timer 1 using to capture, prescaler 1:1 movwf T1CON bsf T1CON,TMR1ON movlw b'00000101' movwf CCP1CON ;start with rising CAPTURE movlw b'00000101' movwf CCP2CON ;start CCP2 with rising CAPTURE bcf PIR1,CCP1IF bcf PIR2,CCP2IF Wait: btfss PIR1,CCP1IF goto Wait movf CCPR1H,W ;save the value in H2 and L2 {lower value} movwf CCP1aH movf CCPR1L,W movwf CCP1aL bcf PIR1,CCP1IF ; Wait1: btfss PIR1,CCP1IF goto Wait1 movf CCPR1H,W ;save now the value in H1,L1 movwf CCP1bH movf CCPR1L,W movwf CCP1bL bcf PIR1,CCP1IF ;clr flag CCP1 Wait2 btfss PIR2,CCP2IF goto Wait2 movf CCPR2H,W ;save now the value in H1,L1 movwf CCP2H movf CCPR2L,W movwf CCP2L bcf PIR2,CCP2IF ;clr flag CCP1 ;*********CCP1b-CCP1a******************* SUB1: movf CCP1aL,W subwf CCP1bL,W movwf btmL ;movwf PORTB btfss STATUS, C goto BORROW1 goto SUB_1 BORROW1: decf CCP1bH, F SUB_1: movf CCP1aH,W subwf CCP1bH,W movwf btmH ;movwf PORTD ;*******CCP2-CCP1b**************** SUB2: movf CCP1bL,W subwf CCP2L,W movwf topL ;movwf PORTB btfss STATUS, C goto BORROW2 goto SUB_2 BORROW2: decf CCP2H, F SUB_2: movf CCP1bH,W subwf CCP2H,W movwf topH ; movwf PORTD ;***********DIVISION*********************** Div: call Divide movf qL,w ;@@@@@ RESULTS @@@@@@ movwf PORTB movf qH,w ; on LEDs connected to rb and rc. movwf PORTD goto Main ;-------LOOP BACK TO START---- Divide: movf btmH,w ; Check for division by 0. iorwf btmL,w btfsc STATUS,Z bsf PORTB,0 ; //**Error code If btm is Zero:PORTB PIN 0 Light LED//** movlw d'1' ; Otherwise, initialize variables movwf count clrf index ; for the division. clrf qH clrf qL Divide_sh_loop: btfsc btmH,7 ; Shift divisor left goto Divide_d1 bcf STATUS,C ; until msb is in rlf btmL,1 ; btmH.7. rlf btmH,1 ; count = no. of shifts+1. incf count,1 goto Divide_sh_loop Divide_d1: bcf STATUS,C rlf qL,1 ; Shift quotient left. rlf qH,1 movf btmL,w ; top = top - btm. subwf topL,1 btfsc STATUS,C ; If top - btm < 0 then goto Divide_d2 movlw d'1' ; top = top + btm subwf topH,1 btfsc STATUS,C ; The idea is to do the goto Divide_d2 incf topH,1 ; the subtraction and comparison movf btmL,w ; (top > btm?) in one step. addwf topL,1 goto Divide_reentr ; Then, if btm > top, undo Divide_d2: movf btmH,w ; the subtraction by adding subwf topH,1 btfss STATUS,C ; top and btm back together goto Divide_less ; bsf qL,0 Divide_reentr bcf STATUS,C rrf btmH,1 rrf btmL,1 decfsz count,1 goto Divide_d1 retlw 0h ; Return w/ remainder in top ; and result in q.&nsp; Divide_less movf btmL,w ; btm > top, so addwf topL,1 btfsc STATUS,C ; undo the subtraction by incf topH,1 ; adding them back together. movf btmH,w addwf topH,1 goto Divide_reentr ; end
Yes, of course. Don't you remember that you need to multiply by 360 BEFORE you do the divide?
You can do whatever you want to do. If you want to display the time lag that is fine with me. I don't know why you would ask me that...you should ask your instructor if that is okay. Of course, the time lag doesn't tell you the phase unless you also know the frequency.bjox1 said:Thanks again for the reply mike.
Mike, I was wondering if it is at all possible for me to display just the time lag rather than phase as it would certainly save another routine of 16 by 16 multiplication??
You could multiply by 256 instead of 360. That is easy to do...just set topH equal to topL and then set topL to zero before you do the divide. In that case your output will be from 0 to 255...dividing a circle into 256 parts instead of 360.bjox1 said:And if I skip the 360 multiplication part, will I be stuck as the numerator will be smaller than the denominator??
mike50 said:But I don't know why you wouldn't just add the code to do the multiply (get it from the same place you got the divide routine).
Mike
divide movlw 32 ; 32-bit divide by 16-bit
movwf bitcnt
clrf remdrH ; Clear remainder
clrf remdrL
dvloop clrc ; Set quotient bit to 0
; Shift left dividend and quotient
rlf divid0 ; lsb
rlf divid1
rlf divid2
rlf divid3 ; lsb into carry
rlf remdrL ; and then into partial remainder
rlf remdrH
skpnc ; Check for overflow
goto subd
movfw divisH ; Compare partial remainder and divisor
subwf remdrH,w
skpz
goto testgt ; Not equal so test if remdrH is greater
movfw divisL ; High bytes are equal, compare low bytes
subwf remdrL,w
testgt skpc ; Carry set if remdr >= divis
goto remrlt
subd movfw divisL ; Subtract divisor from partial remainder
subwf remdrL
skpc ; Test for borrow
decf remdrH ; Subtract borrow
movfw divisH
subwf remdrH
bsf divid0,0 ; Set quotient bit to 1
; Quotient replaces dividend which is lost
remrlt decfsz bitcnt
goto dvloop
return
mike50 said:Why would you want to re-write this divide code? Why not just use it as is?
I'm sure I could figure out how this divide code works if I wanted to spend the time, but I don't. You don't have to understand it to use it.
The simulator in MPLAB is a much better way to test out code like this to see if it does what you want than trying to run it on real hardware with LEDs for output.
Mike
; Quotient replaces dividend which is lost
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?