Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Can CCP do this on 16F876A? :(

Status
Not open for further replies.
Mike,

You do know the words dividend, divisor and quotient, right?

Oh yes. I do know that. :D

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.
 
bjox1 said:
Mike,

Oh yes. I do know that. :D

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.
........
mike50 said:
The output is in divid0, divid1, divid2 and divid3. Again with the least significant byte in divid0.

Mike
 
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. :confused:

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.


Thanks in advance.

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:
	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'
		movwf 	CCP1CON          ;start with CCP1 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 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
	               addwf	divid1,f

	              movf	b2, w
	               btfsc	STATUS,C
	               incfsz	b2, w	
	               addwf	divid2, f	
	               btfsc	STATUS,C
	               incf	divid3, f
	               bcf		STATUS,C
	
nobit_l	
	               btfss	topL, 7
	               goto	nobit_h
	               movf	b1,w
	               addwf	divid2,f
	               movf	b2, w
	               btfsc	STATUS,C
	               incfsz	b2, w
	               addwf	divid3, f	

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:
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:
Main
		movlw	b'00000000'   	;timer 1 using to capture, prescaler 1:1 
		movwf	T1CON 
		bsf	T1CON,TMR1ON

		movlw	b'00000101'
		movwf	CCP1CON       	;start with CCP1 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 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.
 
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,
 
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
 
mike50 said:
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.

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.
 
Pommie said:
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.
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:
   - 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
 
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
 
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
 
mike50 said:
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

The irony of that is my third capture would have fixed the problem. :D

Mike.
 
A simple way to fix this would be,
Code:
		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:
Pommie said:
A simple way to fix this would be,
Code:
		movf	CCP1aL,W
		subwf	CCP1bL,W
		movwf	divisL

		movf	CCP1aH
		btfss	STATUS, C
		incf	CCP1aH, W

		subwf	CCP1bH,W
		movwf	divisH

Mike.
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
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top