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.

to generate 50hz pwm using 16f877

Status
Not open for further replies.

cgsumesh77

New Member
hi guys,

i am pretty new in dis field of micro-controllers, could you guys please help me by sharing how to generate a 50 hz PWM , am using 16f877 as pic and
20MHz crystal oscillator. can i generate this pwm using software methods?
actually my purpose is to control a servo motor with pwm 50 hz(20ms) and to vary between 1ms to 2ms duty cycle to obtain the angular motion of servo. we have budget constraints, so keen to know the software method that can be adopted.

thanks in advance....
 
Hi cgsumesh77,

If you were using a 4 MHz or 16 MHz crystal it would be relatively easy to use the PWM module plus some (interrupt) software for that solution. Unfortunately, a 20 MHz clock isn't the best frequency to use with the Timer 2 prescalers.

Still, here's one possible solution for a 16 MHz clock which you might like to study. Basically, you setup the PWM module with a 1 KHz (1 msec) period and you use 20 of these 1 msec PWM "frames" to make up your 20 msec Servo period. At the end of each "frame" you setup the duty cycle for the next PWM "frame". At the end of 20 "frames" (20 msecs) you start over.

Regards, Mike

Code:
;******************************************************************
;
;  //  setup a 1000 usec PWM period with PR2 = 249 and prescaler
;  //  16:1 (16 MHz clock) for 20 PWM 'frames' per 20 msec Servo
;  //  period and 1 usec pulse width resolution
;
;  int servo = 1500;            // 0..20000 in 1 usec 'ticks'
;  int width = 0;               // ISR work variable
;  int frame = 1;               // frame number 1..20
;
;  void ISR()
;  { PIR1bits.TMR2IF = 0;       // clear Timer 2 interrupt flag
;    if (--frame == 0)          // if end of the 20 msec period
;    { frame = 20;              // reset for new 20 msec period
;      width = servo;           // reset 'width' work variable
;    }
;    if ((width > 1000)         // if width > 1000 usecs
;    { CCPR1L = 250;            // do a 100% duty cycle frame
;      CCP1CONbits.CCP1Y = 0;   //
;      CCP1CONbits.CCP1X = 0;   //
;      width -= 1000;           // subtract 1000 usecs
;    }
;    else
;    { CCP1CONbits.CCP1Y = (width & 1);
;      CCP1CONbits.CCP1X = (width & 2);
;      CCPR1L = (width >> 2);   // 0..249 (0..999 usecs)
;      width = 0;               // force remaining frames to 0%
;    }
;  }
;
ISR_vect
;
;  save main program context
;
        movwf   W_ISR           ; save W-reg                      |B?
        swapf   STATUS,W        ; doesn't change STATUS bits      |B?
        movwf   S_ISR           ; save STATUS reg                 |B?
        clrf    STATUS          ; force bank 0                    |B0
;
        bcf     PIR1,TMR2IF     ; clear Timer 2 interrupt flag    |B0
;
;  check for start of new 20 msec servo period
;
        decfsz  frame,F         ; end of 20 msec period?          |B0
        goto    doframex        ; no, branch, else                |B0
        movlw   d'20'           ; reset pwm frame number          |B0
        movwf   frame           ;                                 |B0
        movf    servo,W         ; setup 'pulse' work variable     |B0
        movwf   width           ; for new 20 msec servo period    |B0
        movf    servo+1,W       ;                                 |B0
        movwf   width+1         ;                                 |B0
doframex
        movlw   low(1000)       ; width = width - 1000            |B0
        subwf   width,F         ;                                 |B0
        movlw   high(1000)      ;                                 |B0
        skpc                    ;                                 |B0
        movlw   high(1001)      ;                                 |B0
        subwf   width+1,F       ;                                 |B0
        movlw   d'250'          ; assume 100% duty cycle frame    |B0
        bcf     CCP1CON,CCP1Y   ;                                 |B0
        bcf     CCP1CON,CCP1X   ;                                 |B0
        bc      setdutyx        ; borrow? no, branch, else        |B0
        movlw   low(1000)       ;                                 |B0
        addwf   width,F         ;                                 |B0
        movlw   high(1000)      ;                                 |B0
        skpnc                   ;                                 |B0
        movlw   high(1001)      ;                                 |B0
        addwf   width+1,F       ;                                 |B0
        btfsc   width,1         ;                                 |B0
        bsf     CCP1CON,CCP1X   ;                                 |B0
        btfsc   width,0         ;                                 |B0
        bsf     CCP1CON,CCP1Y   ;                                 |B0
        rrf     width+1,F       ;                                 |B0
        rrf     width,F         ;                                 |B0
        rrf     width+1,F       ;                                 |B0
        rrf     width,W         ; W = 0..250                      |B0
        clrf    width           ; force 0% duty cycle for the     |B0
        clrf    width+1         ; remaining pwm frames            |B0
setdutyx
        movwf   CCPR1L          ; set duty cycle for next frame   |B0
;
;  restore main program context
;
        swapf   S_ISR,W         ;                                 |B0
        movwf   STATUS          ; restore STATUS                  |B?
        swapf   W_ISR,f         ; don't screw up STATUS           |B?
        swapf   W_ISR,W         ; restore W-reg                   |B?
        retfie                  ; return from interrupt           |B?
 
Last edited:
hi mike...
could i get the codes in c or assembly, or else can you please explain a bit more elaborated way, bcoz am still a bit unclear about how exactly does it works. i can generate a 1.22 khz instead of 1khz using 20Mhz frequency. then where should i connect my motor to.... am i going to get my 50 hz frequency from the pwm out pin of pwm module? is there a way that i can adjust this 1.22 khz to get a 1khz and then use the interrupt method to get a 50 hz frequency.. am using IAR work bench to compile my files... am really a beginer in dis stream...

thanks for the help
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top