# Can CCP do this on 16F876A? :(

Discussion in 'Microcontrollers' started by bjox1, Mar 7, 2008.

1. ### bjox1New Member

Joined:
Mar 7, 2008
Messages:
38
Likes:
0
Location:
UK
Mike,

Oh yes. I do know that.

Mike, I have done the 16 by 16 multiplication. I am just going to try the division now. I was wondering, after the division, which register values will I be looking for to find the phase ans [ reg divid0:3 has the result]??

Thanks again mike.

2. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
........
Mike

3. ### bjox1New Member

Joined:
Mar 7, 2008
Messages:
38
Likes:
0
Location:
UK
Mike,

I have finally managed to do the division part as well. It works absolutely fine.

I have two different codes. The first one does the 16 by 16 multiplication and the second one is for 32 by 16 bit division.

For the same delay signal value: at 1kHz freq CCP2 signal is delayed by 150 usec.

Thus, this can be achieved when CCP2-CCP1b =150
And, CCP 1b-CCP1a = 1000

So theoretically I have to multiply the numerator by 360 which is =54000 and divide it by 1000 and get the output as 54 degrees.

So I used multiplication code and division code [by putting the values manually] and it worked.

But as soon as I integrated it with the other code, I didn’t get any output.

The code is explained as:

-Sub-routine ‘SUB1’ performs CCP1b-CCP1a and the result is saved in divisH:divisL.

-then, sub-routine ‘SUB2’ performs CCP2-CCP1b and the result is saved in topH:topL.

-then, in sub-routine ‘Multiply’, value 360 is copied into b2:b1 and the numerator [topH:topL] are then multiplied to get 32 bit result in divid0:divid3

-and finally ‘divide’ routine divides divid0:divid3 by divisH:divisL and the last two bytes of the 32 bit results are displayed on PORTB and PORTD.

I am so puzzled and worried. Please advice me if you find anything missing. I will really appreciate that Mike.

Regards,

Ps: I tried formatting the code in this post but every time I save it, it doesn't work. I apologise if it doesn't appear good to you.

Code (text):

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
divisL ;divisor Low byte[CCP1b-CCP1a]
divisH ;divisor high byte
b1
b2
bitcnt
remdrH
remdrL
divid0    ; lsb of divident [Used in Multiply as 4 quotient
divid1    ; and the same values are used in Divide a divident]
divid2
divid3    ; MSB
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    topH
clrf    topL
clrf    divisH
clrf    divisL
clrf    b1
clrf    b2
clrf    bitcnt
clrf    remdrH
clrf    remdrL
clrf    divid0    ; lsb of divident
clrf    divid1
clrf    divid2
clrf    divid3    ; MSB
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'
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 CCP1aH and CCP1aL {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 CCP1bH and CCP1bL
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 CCP2 H:L
movwf   CCP2H
movf    CCPR2L,W
movwf   CCP2L
bcf     PIR2,CCP2IF     ;clr flag CCP2

;*********CCP1b-CCP1a*******************
SUB1:
movf    CCP1aL,W
subwf   CCP1bL,W
movwf   divisL

btfss  STATUS, C
goto   BORROW1
goto   SUB_1
BORROW1:
decf   CCP1bH, F

SUB_1:
movf    CCP1aH,W
subwf   CCP1bH,W
movwf   divisH

;*******CCP2-CCP1b****************
SUB2:
movf    CCP1bL,W
subwf   CCP2L,W
movwf   topL

btfss  STATUS, C
goto   BORROW2
goto   SUB_2
BORROW2:
decf   CCP2H, F

SUB_2:
movf    CCP1bH,W
subwf   CCP2H,W
movwf   topH

;***********Multiply topH:topL X b2:b1[ b2:b1=360]***********************

;****INT b2:b1 as 360******

movlw d'1'
movwf b2
movlw d'104'
movwf b1

;*************Calling Multiply & Divide sub routine*********
;---------------------------------------------------------
call  Multiply
call  divide
nop
nop

movf divid0,w    ; Show result[LSB0,1] in binary on
movwf PORTB

;;;;;;FINALLLLLLLLL////*********

movf divid1,w    ; LEDs connected to ports.
movwf PORTD

; movf divid2,w    ; Show result[MSB2,3] in binary on
; movwf PORTB
; movf divid3,w    ; LEDs connected to ports.
; movwf PORTD

goto Main           ; Endless loop
;----------------------------------------------------
;************Multiply*********************************
Multiply
clrf    divid3
clrf     divid2
clrf    divid1
movlw  0x80
movwf  divid0

nextbit
rrf      topH,f
rrf      topL,f

btfss STATUS,C
goto  nobit_l
movf b1,w

movf  b2, w
btfsc    STATUS,C
incfsz   b2, w
btfsc    STATUS,C
incf divid3, f
bcf      STATUS,C

nobit_l
btfss    topL, 7
goto nobit_h
movf b1,w
movf b2, w
btfsc    STATUS,C
incfsz   b2, w

nobit_h
rrf   divid3,f
rrf   divid2,f
rrf   divid1,f
rrf   divid0,f

btfss   STATUS,C
goto   nextbit
return

;**************DIVIDE*******************************
divide
movlw d'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, 1    ; lsb
rlf divid1, 1
rlf divid2, 1
rlf divid3, 1    ; lsb into carry
rlf remdrL, 1    ; and then into partial remainder
rlf remdrH, 1

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
subwf remdrL,w

testgt
skpc              ; Carry set if remdr >= divis
goto remrlt

subd
movfw divisL      ; Subtract divisor from partial remainder
subwf remdrL, 1
skpc                ; Test for borrow

decf remdrH, 1    ; Subtract borrow
movfw divisH
subwf remdrH, 1
bsf divid0,0      ; Set quotient bit to 1
; Quotient replaces dividend which is lost

remrlt
decfsz bitcnt, 1
goto  dvloop
return

end

Last edited: Mar 18, 2008

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

5. ### bjox1New Member

Joined:
Mar 7, 2008
Messages:
38
Likes:
0
Location:
UK

Please can anyone offer me some help??

6. ### PommieWell-Known MemberMost Helpful Member

Joined:
Mar 18, 2005
Messages:
10,293
Likes:
356
Location:
Brisbane Australia
You appear to be capturing the edges in a strange order, shouldn't you capture from rising edge to rising edge on ccp1 and then from rising edge of ccp1 to rising edge of ccp2. The way your code is now ccp2 may have captured before ccp1.

I changed the name of some of your variables (so I could follow it) and swapped it around a little.
Does this make sense?
Code (text):

Main
movlw   b'00000000'     ;timer 1 using to capture, prescaler 1:1
movwf   T1CON
bsf T1CON,TMR1ON

movlw   b'00000101'
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 CCP1aH and CCP1aL {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 CCP1bH and CCP1bL
movwf   CCP1bH
movf    CCPR1L,W
movwf   CCP1bL
bcf PIR1,CCP1IF     ;clr flag CCP1

bcf PIR1,CCP1IF
WaitPhase
btfss   PIR1,CCP1IF
goto    WaitPhase
movf    CCPR1H,W        ;save the value in CCP1aH and CCP1aL {lower value}
movwf   PhaseStartHi
movf    CCPR1L,W
movwf   PhaseStartLo
bcf PIR1,CCP1IF
;
bcf PIR2,CCP2IF
WaitPhase2
btfss   PIR2,CCP2IF
goto    WaitPhase2

movf    CCPR2H,W        ;save now the value in CCP2 H:L
movwf   PhaseEndHi
movf    CCPR2L,W
movwf   PhaseEndLo
bcf PIR2,CCP2IF     ;clr flag CCP2

;*********CCP1b-CCP1a*******************
SUB1:
movf    CCP1aL,W
subwf   CCP1bL,W
movwf   divisL

btfss   STATUS, C
decf    CCP1bH, F

movf    CCP1aH,W
subwf   CCP1bH,W
movwf   divisH

;*******PhaseEnd-PhaseStart****************
SUB2:
movf    PhaseStartLo,W
subwf   PhaseEndLo,W
movwf   topL

btfss   STATUS, C
decf    PhaseEndHi, F

movf    PhaseStartHi,W
subwf   PhaseEndLo,W
movwf   topH

;***********Multiply topH:topL X b2:b1[ b2:b1=360]***********************
Mike.

7. ### bjox1New Member

Joined:
Mar 7, 2008
Messages:
38
Likes:
0
Location:
UK
Mike,

I could have never thought of it. You guys are such a gem!

Suddenly everything makes sense. I am very thankful to you for spending the time editing my code and for your suggestions and corrections. I am going to try this and hopefully this time I will be successful.

Thank you so much again.

Regards,

8. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
Mike,

I don't think that is the problem. He captured the rising edge of CCP1, then he captured the rising edge of CCP1 again and then captured the rising edge of CCP2. CCP2 could not be captured before the second capture of CCP1.

There is no need to capture CCP1 a third time.

Mike

9. ### PommieWell-Known MemberMost Helpful Member

Joined:
Mar 18, 2005
Messages:
10,293
Likes:
356
Location:
Brisbane Australia
I don't see why, the CCP2IF is only cleared once before the first CCP1 capture. Adding a bcf PIR2,CCP2IF before Wait2 would have fixed this.

Agreed, no need for third capture.

Mike.

10. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
Ah, yes, you are quite right. I missed that he left out clearing CCP2IF after the second capture of CCP1IF.

bjox1 - Remember the pseudo-code I showed you for this? Here it is:

Code (text):
- Inner loop 1
- If CCP1IH = 0 then goto Inner loop 1

- Copy CCPR1H to CCP1aH
- Copy CCPR1L to CCP1aL
- Set CCP1IH = 0

- Inner loop 2
- If CCP1IH = 0 then goto Inner loop 2

- Set CCP2IH = 0  ; make sure to capture CCP2 after second CCP1 capture
- Copy CCPR1H to CCP1bH
- Copy CCPR1L to CCP1bL
- Set CCP1IH = 0

- Inner loop 3
- If CCP2IH = 0 then goto Inner loop 3

- Copy CCPR2H to CCP2aH
- Copy CCPR2L to CCP2aL
- Set CCP2IH = 0
I don't know why, but you left out the line that sets CCP2IH to 0 (the one with the comment saying "make sure ..."

Mike

• Like x 1
11. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
I simulated your code, after adding in the clear of CCP2IF following the second CCP1 capture, and the capture part seems to work perfectly. But the arithmetic is bad. In particular your subtract routine doesn't work right.
Sometimes it doesn't borrow when it should.

I correct the answer from the subtract and then everything else worked perfectly. With a 1 KHz signal on CCP1 and the same signal delayed by 250 microseconds on CCP2, the result was 90, which is correct.

Mike

12. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
Well I see what is wrong. It isn't actually anything wrong in the subtract routine, it is that the subtract routine modifies the high byte of one of its inputs (if it borrows). But your second subtract uses that same value so it gets the wrong answer.

The simulator is your best friend for problems like these. It is way easier than trying to debug by reading the code and looking at output on some LEDs.

Mike

13. ### PommieWell-Known MemberMost Helpful Member

Joined:
Mar 18, 2005
Messages:
10,293
Likes:
356
Location:
Brisbane Australia
The irony of that is my third capture would have fixed the problem.

Mike.

14. ### PommieWell-Known MemberMost Helpful Member

Joined:
Mar 18, 2005
Messages:
10,293
Likes:
356
Location:
Brisbane Australia
A simple way to fix this would be,
Code (text):

movf    CCP1aL,W
subwf   CCP1bL,W
movwf   divisL

movf    CCP1aH[COLOR="Red"],W[/COLOR]
btfss   STATUS, C
incf    CCP1aH, W

subwf   CCP1bH,W
movwf   divisH

Mike.
Edit, noticed omission - in red.

Last edited: Mar 19, 2008
15. ### mike50New Member

Joined:
Jun 29, 2007
Messages:
103
Likes:
2
Location:
Rochester, Minnesota
Yes, that is an excellent way to fix it.

bjox1 - you might want to reconsider looping back to main after displaying the result in the LEDs. It might be better to just branch to self at the end. Then when you want a new measurement press the reset button.

Mike