Jump to content
Sign in to follow this  
Flutter

How to set up PWM with pic16f870/16f876

Recommended Posts

I hae been trying to control a standard servo for some time now, but I can't get my routines to work properly.

Can anyone give me a clue about the right config on

PR2

T2CON

CCPR1L

CCP1CON

just so I can get it to work. I only get a movement on the first interrupt, then

changing the value of CCPR1L gives me only a small tick, changing the position maybe 1deg. I most likely have configured the above registers wrong.....

I have read the theory, but obviously don't understand it in total...so some working values would be great!

Thanks!

Share this post


Link to post
Share on other sites

Using the hardware PWM features on the PIC for creating the servo PWM pulse is not a popular method. It is more common to use the 16-bit timer/counters and perhaps include the timer interrupt features.

But if you want to play with the PWM hardware to create a 50Hz framerate servo pulse, then here are the basics. This is just a educational tool and is not meant to be "real" code for controlling a servo. This psuedo code example is based on a 4Mhz Osc.

1) Create a Timer2 interrupt handler. All it will do is set the CCPR1L to 0x00, reset the T2 interrupt flag, and then return. This is used to synthesize the one-shot behavior that you will need.

2) Initialize Timer 2:

TCON2 = 0x05 (prescale 4, Timer on)

PR2 = 0xff (period set to 255)

CCPR1L = 0x00 (force PWM signal low)

<enable T2 interrupt here>

3) Create a main loop with a 50 Hz framerate. One PWM cycle will be produced with each iteration. It relies on the T2 interrupt to one-shot the servo pulse.

main:

CCPR1L = <0x00 to 0xff 8-bit time value> (the pulse width range)

delay 20mS (framerate)

Goto main

The above will give give you a precise 0.0mS to 1.0mS pulse, at a 50Hz framerate, that has 8-bit resolution (255 steps). For a normal 1.0mS to 2.0mS servo pulse width, you just need to add more code. I will leave that up to you.

Share this post


Link to post
Share on other sites

This is one of the sub routines. If I reset the pic I can push my 3rd test button, and the servo moves....but to the same pos. no matter what value I choose for the duty cycle CCPR1L.

void servo3(void){

TRISC = 0b.1000.0000; /* Config. PortC.2 for out put=0 */

CCP1CON =0b.00111111; /*Conf. CCP1 module for PWM operation */

T2CON =0b.00000100; /* Timer2 Prescale 1 (to obtain 19.53kHz) */

PR2 = 255; /*PWM period (0xFFh) */

CCPR1L = 100; /*about 40% duty cycle*/

led3=1; /*For identifyig the respective interrupt*/

del(); /*delay routine*/

}

Share this post


Link to post
Share on other sites

Thank you Mr. Rc Cam

I posted before I read your message. I guess I will have to go through this once more using your instructions.

So I guess that I will test the PWM hardware first, and then try on the 16bit counters.

Share this post


Link to post
Share on other sites

Just keep in mind that servos will not respond correctly without the lull time between each pulse. That is the purpose of the 50Hz framerate. In your example, the PWM is continuous (sort of a 1KHz framerate), so the servo just does not understand what to do.

With the 16-bit timer method, and a lowly 4 MHz Osc, you can easily achieve 1uS pulse resolution (effectively 10-bit) for silky smooth servo operation. This is much improved over the 4uS (8-bit) resolution that the hardware PWM example I show will allow.

When generating R/C pulses, it really helps to fire up the o-scope and see what you have created. I cannot imagine doing this stuff without one.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×