1. 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.
    Dismiss Notice

Can CCP do this on 16F876A? :(

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

  1. bjox1

    bjox1 New Member

    Joined:
    Mar 7, 2008
    Messages:
    38
    Likes:
    0
    Location:
    UK
    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.
     
  2. mike50

    mike50 New Member

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

    bjox1 New 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. :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 (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'
            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: Mar 18, 2008
  4. dave

    Dave New Member

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


     
  5. bjox1

    bjox1 New Member

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

    Please can anyone offer me some help?? :eek:
     
  6. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    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'
            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.
     
  7. bjox1

    bjox1 New 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. mike50

    mike50 New 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. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    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. mike50

    mike50 New 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 Like x 1
  11. mike50

    mike50 New 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. mike50

    mike50 New 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. Pommie

    Pommie Well-Known Member Most Helpful Member

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

    Mike.
     
  14. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    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. mike50

    mike50 New 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
     

Share This Page