16 bit PWM using CCP1


Closed Thread
Results 1 to 40 of 61

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default 2-CH Hardware Servo Driver

    And since you made me think of it ...

    Here's a 2 channel Hardware Servo Driver, that uses Timer1 and both CCP modules in Compare mode.
    With an 18F.

    Servo outputs are the CCP? pins.
    Pulses will be continuous at ~40hz, regardless of MainLoop activity.

    Cheers ...
    Code:
    '***************************************************************************
    '*  Name    : 2CH_Servo.pbp
    '*  Author  : Darrel Taylor
    '*  Date    : 12/13/2009
    '*  Notes   : 18F's only
    '***************************************************************************
    @ __CONFIG _CONFIG1H, _OSC_HSPLL_1H
    @ __CONFIG _CONFIG2L, _BOREN_OFF_2L
    @ __CONFIG _CONFIG2H, _WDT_OFF_2H
    @ __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L  
    
    CLEAR
     
    DEFINE OSC 40  
    DEFINE  INTHAND myint 
         
    ;----[User Selections]------------------------------------------------------    
    MoveSpeed CON 3                      ' movement speed smaller = faster
    PosRange  CON 900                    ' position is 0-900, 0.0-90.0 degrees
                                         '             450 is Center
    CCP1pin   VAR PORTC.2                ' Specify the pin that CCP1 uses
    CCP2pin   VAR PORTC.1                ' Specify the pin that CCP2 uses
    
    ;----[Variables and Aliases]------------------------------------------------    
    Servo1    VAR WORD                   ' Position for Servo1
    Servo2    VAR WORD                   ' Position for Servo2
    DutyHold1 VAR WORD BANK0 SYSTEM      ' holds next dutycycle, synch with PWM 
    DutyHold2 VAR WORD BANK0 SYSTEM      '
    TempW     VAR WORD                   ' temporary variable
    POS       VAR WORD                   ' loop counter variable
    
    TMR1IE    VAR PIE1.0                 ' Timer1 Interrupt Enable
    TMR1IF    VAR PIR1.0                 ' Timer1 Interrupt Flag
    TMR1ON    VAR T1CON.0                ' Timer1 ON bit
    GIE       VAR INTCON.7               ' Global Interrupt Enable
    PEIE      VAR INTCON.6               ' Peripheral Interrupt Enable
        
    ;----[Initialization]-------------------------------------------------------
    Init:
        T1CON   = %00100000              ' Timer1 off, Prescaler 1:4 (40mhz)
                                         '          1:2 (20mhz), 1:1 (10mhz)
        TMR1IE  = 1                      ' Enable TMR1 overflow interrupt 
        TMR1IF  = 0                      ' Clear  TMR1 interrupt flag
        PEIE    = 1                      ' Enable peripheral interrupts
        GIE     = 1                      ' Enable global interrupts
        CCP1CON = 9                      ' Low on match TMR1 with DUTY1
        CCP2CON = 9                      ' Low on match TMR1 with DUTY2
        OUTPUT CCP1pin                   ' Set CCP1 pin to output, starts High
        OUTPUT CCP2pin                   ' Set CCP1 pin to output, starts High
        
        Servo1 = PosRange/2              ' Start at Center Position
        Servo2 = PosRange/2
        GOSUB SetServos
        TMR1ON = 1                       ' turn ON TMR1
        PAUSE 2000                       ' allow time for servo to Home
    
    
    ;----[Main Program Loop]----------------------------------------------------
    Main:
        FOR POS = 0 TO PosRange          ' move both from one end to the other
            Servo1 = POS
            GOSUB SetServo1              ' Set servo1's position
            Servo2 = POS
            GOSUB SetServo2              ' Set servo2's position
            PAUSE MoveSpeed              ' movement speed
        NEXT POS
        
        FOR POS = PosRange TO 0 STEP -1  ' move servo1 back to home
            Servo1 = POS
            GOSUB SetServo1
            PAUSE MoveSpeed
        NEXT POS
        
        FOR POS = PosRange TO 0 STEP -1  ' move servo2 back to home
            Servo2 = POS
            GOSUB SetServo2
            PAUSE MoveSpeed
        NEXT POS
    
        PAUSE 1000
    Goto Main                            ' rinse and repeat
    
    ;----[Convert Position in degrees to dutycycle]-----------------------------
    SetServos:                           ' Set both Servo's dutycycles
        GOSUB SetServo1
        
    SetServo2:                           ' scale Posistion to 2500 Dutycycle
        TempW = Servo2 * 2500
        TempW = DIV32 PosRange + 2500
        GIE = 0                          ' no ints during variable update
        DutyHold2 = TempW
        GIE = 1
    RETURN
    
    SetServo1:
        TempW = Servo1 * 2500            
        TempW = DIV32 PosRange + 2500
        GIE = 0
        DutyHold1 = TempW
        GIE = 1
    RETURN
       
    ;----[Dual Servo Driver - Interrupt Service]--------------------------------
    Asm
    myint
        movlw     9                  ; %00001001 compare mode, low on match
        clrf      CCP1CON            ; clrf added per Bruce's suggestion
        movwf     CCP1CON            ; Set Pins to default state (High)
        clrf      CCP2CON            ; clrf added per Bruce's suggestion
        movwf     CCP2CON
        movf      DutyHold1+1,W      ; update current position's dutycycle
        movwf     CCPR1H             ; for both servos
        movf      DutyHold1,W
        movwf     CCPR1L
        movf      DutyHold2+1,W
        movwf     CCPR2H 
        movf      DutyHold2,W
        movwf     CCPR2L
        bcf       PIR1,0             ; Clear Timer Int Flag
        retfie    FAST               ; Return from interrupt with shadow regs
    EndAsm
    Last edited by Darrel Taylor; - 14th December 2009 at 03:01. Reason: Bruce's Fix
    DT

  2. #2
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Hi Darrel,

    Pretty cool stuff. Have you tested this on other 18F parts? I don't have a 4520 to test
    with, but I couldn't get this to work without clearing CCP1CON before moving 9 to it on
    a 452 or 4431.

    Had to do this;
    Code:
    ASM
    MyInt                    
        clrf CCP1CON         ; 18F452 & 18F4431 require this before it changes CCP1 output
        movlw 9
        movwf CCP1CON
        bcf PIR1,TMR1IF      ; clear TMR1 int flag
        retfie FAST          ; use RETFIE FAST to restore WREG, STATUS & BSR
    ENDASM
    On an 18F452 or 18F4431, the above works fine, but only if I clear CCP1CON first.

    This works on a 452 & 4431 with CCP1 & TMR1 ints enabled on any output pin;
    Code:
    ASM
    MyInt                    
        btfss PIR1,TMR1IF    ; TMR1 interrupt?
        bra CCP              ; no - service CCP interrupt
        bcf PIR1,TMR1IF      ; yes - clear TMR1 int flag
        bsf LATB,0           ; set RB0 on TMR1 interrupt
        retfie FAST          ; return
    CCP
        bcf PIR1,CCP1IF      ; clear CCP1 int flag
        bcf LATB,0           ; clear RB0 on compare interrupt
        retfie FAST          ; use RETFIE FAST to restore WREG, STATUS & BSR
    ENDASM
    I was just wondering if this might be a fluke with the 4520 part - since none of the other
    18F parts I've tested will toggle CCP1 with just the movlw 9, movwf CCP1CON?
    Last edited by Bruce; - 14th December 2009 at 02:34. Reason: 2nd version uses CCP1CON = %00001010
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  3. #3
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hmmm, very interesting.

    I had not tried it on any other chips, and with the 4520 you definitely don't have to clear it first.

    But I just tried an 18F452, and you are absolutely correct.
    It doesn't work unless you clear the CCPCON register first.

    Very interesting indeed,
    Thanks Bruce.
    <br>
    DT

  4. #4
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Thanks. I was just curious. I had fought with this one before on a servo driver, and just
    couldn't get it to work without both ints enabled, or clearing CCP1CON first.

    I'm thinking it may be due to the huge number of problems Mchip had (see erratas') on
    ECCP & CCP with this one?
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  5. #5
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Bruce View Post
    I'm thinking it may be due to the huge number of problems Mchip had (see erratas') on ECCP & CCP with this one?
    No doubt!

    BTW, I like the any Output Pin variation too.
    <br>
    DT

  6. #6
    Join Date
    Oct 2004
    Posts
    440


    Did you find this post helpful? Yes | No

    Default

    Works good!
    Thanks Darrel

    Would it be correct to say the maximum PWM frequency for a 40 MHz PIC is 152 Hz?
    To slow for music.
    Know of any > 10 bit PWM PIC's?

    Norm

  7. #7
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Yup, that's what mister-e's calculator says with 40mhz, 1:1, and 16-bit. 152 hz.

    The PIC18F2331/2431/4331/4431 series has a bunch of 14-bit PWM modules. But they are completely different from the CCP module.

    Bruce has done a few examples, but I don't think any of them were for music.

    best regards,
    DT

  8. #8
    Join Date
    May 2013
    Location
    australia
    Posts
    2,680


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    just tried your "red" code in the isr on a pic18f45k20

    you are right

    bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
    bsf PIE1,0 ; TMR1IE= 1 Enable TMR1

    these two lines lock it up. can't see why yet

    it looked harmless but its not ,its much worse than useless

  9. #9
    Join Date
    Jun 2009
    Location
    Sc*nthorpe, UK
    Posts
    333


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    The point of coming here is to learn and I am now comparing the architecture of the 18F452 and the 16F1827. They are completely different, not surprise there.

    I have found the sfrs are in bank 5 on the 16F1827 but I have no idea how to use this information.

  10. #10
    Join Date
    May 2013
    Location
    australia
    Posts
    2,680


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    CALLS TO ASM always set bank 0

    pbp has a macro you can use "chk?rp sfr" it will ckeck that the appropriate bank is set (see status or bank sfr)
    the mpasm assembler can also do a " BANKSEL SFR"

    BEFORE YOU RETURN T0 PBP YOU MUST SET BANK BACK TO BANK 0
    Last edited by richard; - 26th August 2014 at 11:23. Reason: still can't spell

  11. #11
    Join Date
    May 2013
    Location
    australia
    Posts
    2,680


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    bsf INTCON,7 ;GIE = 1
    bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
    bsf PIE1,0 ; TMR1IE= 1 Enable TMR1

    intcon bits 6 and 7 should already be set , setting them again should do no harm
    pie1.0 is also set , setting it again can't hurt

    it just wastes 12 cpu cycles

    the problem lies elsewhere, PWM_VAL must be > 30 ,values from 0-29 wont work could that have happened

  12. #12
    Join Date
    Jun 2009
    Location
    Sc*nthorpe, UK
    Posts
    333


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    intcon bits 6 and 7 should already be set , setting them again should do no harm
    pie1.0 is also set , setting it again can't hurt
    That is exactly what I thought and could not find anything to indicate otherwise in the datasheet.

    the problem lies elsewhere, PWM_VAL must be > 30 ,values from 0-29 wont work could that have happened
    No I started PWM_VAL for zero and incremented up in steps of 1 and it worked all the way rolling over and starting from 0. If 0-29 does not work I could not detect it with my voltmeter.

  13. #13
    Join Date
    May 2013
    Location
    australia
    Posts
    2,680


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    N
    o I started PWM_VAL for zero and incremented up in steps of 1 and it worked all the way rolling over and starting from 0. If 0-29 does not work I could not detect it with my voltmeter
    I'm using a cro those <30ish pwm's cause the output pin to be permanently high when you expect a very small pw , in real life that could be nasty
    try a loop range yourself of 0 to say 28

  14. #14
    Join Date
    Jun 2009
    Location
    Sc*nthorpe, UK
    Posts
    333


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    Quote Originally Posted by richard View Post
    N
    I'm using a cro those <30ish pwm's cause the output pin to be permanently high when you expect a very small pw , in real life that could be nasty
    try a loop range yourself of 0 to say 28
    Just tried it no problem 0 gave 0 volts 9 gave 3 mV.

  15. #15
    Join Date
    May 2013
    Location
    australia
    Posts
    2,680


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    not on a cro

    using a main loop like this
    MAIN:

    PWM_VAL = PWM_VAL+1
    PAUSE 500
    if pwm_val > 29 then pwm_val=0
    toggle portd.1
    Goto MAIN

  16. #16
    Join Date
    Jun 2009
    Location
    Sc*nthorpe, UK
    Posts
    333


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    Quote Originally Posted by richard View Post
    N
    I'm using a cro those <30ish pwm's cause the output pin to be permanently high when you expect a very small pw , in real life that could be nasty
    try a loop range yourself of 0 to say 28
    I will take your word for it as I have no instrument that will replicate your results, and as I have found in the past just because I can not see it does not mean it is not there.

  17. #17
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    .... Pulses will be continuous at ~40hz ....
    How do you get ~40-Hz?

    <added>

    Oops! Sorry! I see it. Timer 1 rollover every 26.2144 msecs (38.14697265625 Hz)... I need another cup o' coffee (grin)...
    Last edited by Mike, K8LH; - 28th October 2010 at 16:13.

  18. #18
    Join Date
    Nov 2009
    Posts
    14


    Did you find this post helpful? Yes | No

    Default Re: 16 bit PWM using CCP1

    Hi Everyone,
    Talat from Istanbul here. Please help wıth my PWM problem.
    My code is runnıng BUT I get only 1 or 2 output pulses from port B3 on startup then no output after that.
    What am ı doıng wrong?
    Thanks ın advance fo you help.
    Talat

    '************************************************* ***************
    '* Name : *
    '* Author : [select VIEW...EDITOR OPTIONS] *
    '* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
    '* : All Rights Reserved *
    '* Date : 09.08.2014 *
    '* Version : 1.0 *
    '* Notes : 16F1827 *
    '* : *
    '************************************************* ***************
    ' DEVİCE 16F1827

    ASM
    __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __config _CONFIG2, _PLLEN_ON & _LVP_OFF & _LVP_OFF & _STVREN_OFF; & _VCAPEN_OFF
    ENDASM
    CLEAR
    DEFINE OSC 32
    OSCCON=%01110000 '32

    DEFINE INTHAND PWM_INT

    PWM_VAL VAR WORD BANK0 SYSTEM
    VALUE VAR WORD

    INIT:
    APFCON0 = 0 'SET PORTB.3 TO CCP1
    T1CON = %00100000 'Prescaler 1:4

    PIE1.0 = 1 'TMR1IE TMR1 Interrupt Enable
    PIR1.0 = 0 'TMR1IF TMR1 Interrupt Flag
    INTCON.7 = 1 'GIE Global Interrupt Enable
    INTCON.6 = 1 'PEIE Peripheral Interrupt Enable
    CCP1CON = 9 'compare mode
    OUTPUT PORTB.3 'CCP PIN


    T1CON.0 = 1 'TMR1ON SET TMR1
    PAUSE 1000
    VALUE=1000

    MLOOP:
    VALUE=VALUE+1
    PWM_VAL = VALUE
    Goto MLOOP


    Asm
    PWM_INT
    movlw 9 ; compare mode
    clrf CCP1CON ; clear reg
    movwf CCP1CON ; Set reg
    movf PWM_VAL+1,W ; hb
    movwf CCPR1H ; put
    movf PWM_VAL,W ; lb
    movwf CCPR1L ; put
    bsf INTCON,7 ;GIE = 1
    bsf INTCON,6 ;PEIE = 1 Enable peripheral interrupts
    bsf PIE1,0 ; TMR1IE= 1 Enable TMR1
    bcf PIR1,0 ; TMR1IF = 0 Clear Timer1 Int Flag

    RETFIE ; Return from Interrupt
    EndAsm

    END

Similar Threads

  1. Bits, Bytes Words and Arrays
    By Melanie in forum FAQ - Frequently Asked Questions
    Replies: 24
    Last Post: - 14th June 2016, 07:55
  2. Half-bridge PWM with a 16F684 ?
    By Byte_Butcher in forum General
    Replies: 7
    Last Post: - 17th January 2010, 22:18
  3. PICBasic newbie problem
    By ELCouz in forum mel PIC BASIC Pro
    Replies: 32
    Last Post: - 12th February 2008, 00:55
  4. How to tell which PICs can handle 16 bit variables?
    By MikeTamu in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 31st August 2005, 08:44
  5. USART interrupt not interrupting right
    By Morpheus in forum mel PIC BASIC Pro
    Replies: 12
    Last Post: - 6th March 2005, 01:07

Members who have read this thread : 3

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts