Help with PWM and servo with Pic16F690

Thread Starter

johnnyinwa

Joined Jun 24, 2013
61
My servo is a basic hobby model driven by a 5 volt supply. The period is 10 mSeconds and the duty cycle is 1mSecond (zero degrees) to 2mSeconds (180 degrees). I am using a Pic16F690 to drive the servo. I was wondering if you guys could draw me a simple schematic and a code example in C to show me the correct way to solve the problem. Any help you smart guys could give me would be much appreciated!! Thanks ;)
 

sagor

Joined Mar 10, 2019
903
It may depend on what crystal/clock frequency you are running at. A period of 10ms means it is 100Hz frequency, with either a 10% or 20% duty cycle.
Online PWM calculators do not allow 100Hz PWM with a 4Mhz clock using the PWM module of the PIC, minimum is approximately 244Hz.
You can create a 100Hz PWM with some short interval (like 1ms) timer interrupt, which counts interrupts and sets the high/low state of an I/O line to your liking.
 

AlbertHall

Joined Jun 4, 2014
12,343
It may depend on what crystal/clock frequency you are running at. A period of 10ms means it is 100Hz frequency, with either a 10% or 20% duty cycle.
Online PWM calculators do not allow 100Hz PWM with a 4Mhz clock using the PWM module of the PIC, minimum is approximately 244Hz.
You can create a 100Hz PWM with some short interval (like 1ms) timer interrupt, which counts interrupts and sets the high/low state of an I/O line to your liking.
Yes, I recently wrote code for an RC servo using a PIC12F675 which doesn't have built in PWM. I used timer 0 for the cycle time and timer 1 for the pulse width.
 

djsfantasi

Joined Apr 11, 2010
9,156
What C compiler are you using and how are you programming the Pic?

I don’t have my reference sheet available, but if you’re using the Arduino IDE, the servo library takes care of all the calculations and timings for you. And is proven code to accomplish what you’re looking for with simple function calls.
 

John P

Joined Oct 14, 2008
2,025
The PIC16F690 was my favorite processor for a while, but the PIC16F18345 has the same pinout and it can do much more, is faster, and costs less. Typical Microchip marketing.

And does your servo really take pulses at a 100/sec rate? 50 is more common.

You could do this project with a single timer, if you're willing to reload it at every interrupt. Just alternate "high time" with "low time", and make sure the two together add up to whatever your pulse interval should be.
 
Last edited:

MrSalts

Joined Apr 2, 2020
2,767
Is this homework? Who is still using PIC16F690? I think one came with the PICKIT2 + development board and a CD with the ASM compiler about 15-years ago.
 

John P

Joined Oct 14, 2008
2,025
Now that my memory has been jogged I did a video back in 2011 showing a PIC16F690 driving a stepper motor to create intermediate positions (60 per rev, for a 48 step/rev motor), using a PWM procedure. It operated in the audio range, as you can clearly hear!
 

MrSalts

Joined Apr 2, 2020
2,767
Now that my memory has been jogged I did a video back in 2011 showing a PIC16F690 driving a stepper motor to create intermediate positions (60 per rev, for a 48 step/rev motor), using a PWM procedure. It operated in the audio range, as you can clearly hear!
I see (LEDs) and hear tone that indicate a sequence of..
- 1 (faint buzz)
- 1+2 (buzz)
- 2+3 (buzz)
- 3+4 (buzz)
- 4 (silent)

was that intentional? Or am I misunderstanding something?
 

John P

Joined Oct 14, 2008
2,025
I see (LEDs) and hear tone that indicate a sequence of..
- 1 (faint buzz)
- 1+2 (buzz)
- 2+3 (buzz)
- 3+4 (buzz)
- 4 (silent)

was that intentional? Or am I misunderstanding something?
I thought if I mentioned the number of desired steps versus the number the motor is constructed for, it would be a clue for anyone who's curious about what's happening! The 60:48 or 5:4 ratio is important. It means that for the 60 desired steps, 1 in 5 will correspond with one of the motor's 48 steps, while 4 out of 5 will have to be synthesized. So the silent interval is that time when the motor is delivering an exact location. The other 4 times, there is some ratio of pulse-width-modulation of two adjacent phases of the motor, to position the output shaft between the motor's normal steps. The motor has 4 phases, and there are 4 LEDs to show when each one is being driven. It is quite correct that a single LED is on during every 5th step, and that's when there is no buzz.

The PIC16F690 has only a single PWM output, and it's only available on one particular pin. More sophisticated chips have more PWM's, and they may allow the signals to appear on different output pins. But because of that limitation in the PIC16F690's design, I thought I had to write a "software PWM" routine so that I could operate whichever pins needed to deliver an output at any particular time. Compared wih the processor's built-in PWM, it was pretty slow, and resulted in a system with a lot of audible noise, but it was just done as a demonstration of how a 48-step motor could be made to drive a clock hand, making a full turn using steps once per second.
 

MrSalts

Joined Apr 2, 2020
2,767
I thought if I mentioned the number of desired steps versus the number the motor is constructed for, it would be a clue for anyone who's curious about what's happening! The 60:48 or 5:4 ratio is important. It means that for the 60 desired steps, 1 in 5 will correspond with one of the motor's 48 steps, while 4 out of 5 will have to be synthesized. So the silent interval is that time when the motor is delivering an exact location. The other 4 times, there is some ratio of pulse-width-modulation of two adjacent phases of the motor, to position the output shaft between the motor's normal steps. The motor has 4 phases, and there are 4 LEDs to show when each one is being driven. It is quite correct that a single LED is on during every 5th step, and that's when there is no buzz.

The PIC16F690 has only a single PWM output, and it's only available on one particular pin. More sophisticated chips have more PWM's, and they may allow the signals to appear on different output pins. But because of that limitation in the PIC16F690's design, I thought I had to write a "software PWM" routine so that I could operate whichever pins needed to deliver an output at any particular time. Compared wih the processor's built-in PWM, it was pretty slow, and resulted in a system with a lot of audible noise, but it was just done as a demonstration of how a 48-step motor could be made to drive a clock hand, making a full turn using steps once per second.
I had mentored several robotics clubs and there was always one student trying to make some type of clock from one or more stepper motors. They never like the idea of just using the natural number of steps from the stepper motor (48 or 200 typically) - 60 was their magic number. I was wondering if this was your goal. I like your solution but it would definitely be a challenge to explain to a 15- to 17-year-old. It was usually easier and more interesting for them to use gears and toothed belts.

Unfortunately, school policies don't allow me to mentor after my kids graduated - it was really fun to see the kids build things.
 

MMcLaren

Joined Feb 14, 2010
861
It may depend on what crystal/clock frequency you are running at. A period of 10ms means it is 100Hz frequency, with either a 10% or 20% duty cycle.
Online PWM calculators do not allow 100Hz PWM with a 4Mhz clock using the PWM module of the PIC, minimum is approximately 244Hz.
You can create a 100Hz PWM with some short interval (like 1ms) timer interrupt, which counts interrupts and sets the high/low state of an I/O line to your liking.
The PWM frequency can be reduced to a ridiculously low value (ridiculously long period) by simply breaking up the period into shorter PWM 'frames" and using an interrupt 'helper' to load the PWM duty cycle register for each 'frame'. Very little overhead and very decent resolution... For example, with a 4-MHz clock;

C:
unsigned char frame = 1;        // pwm "frame" counter
unsigned char dutycycle = 0;    // isr work variable
unsigned int servo = 1500;      // 0..10000, 1-usec duty cycle steps

/*
 *  setup PWM module for a 250-usec period (PR2 = 249, prescale 1)
 *
 *  © 2010, Michael McLaren, Micro Application Consultants
 */
  void interrupt()               // 250 usec (250 cycle) interrupts
  { TMR2IF = 0;                  // clear TMR2 interrupt flag
    if(--frame == 0)             // if end of 10-msec Servo period
    { dutycycle = servo;         // refresh duty cycle work variable
      frame = 40;                // reset 10-msec "frame" counter
    }
   /*
    *  set duty cycle for next 250-usec PWM period "frame"
    */
    if(dutycycle > 250)          // if duty cycle > 250-usecs then
      ccpr1l = 250;              // do a 100% duty cycle frame
    else                         // else
      ccpr1l = dutycycle;        // do a 0..100% duty cycle frame
    dutycycle -= ccpr1l;         // adjust dutycycle
  }
 
Last edited:
Top