PWPS (Pulse Width Position Servo)


This program is a modification of the SSPWM program. The only real difference is in the way it calculates the number of timer ticks that are required in each period. This version can get very accurate results by simply adding uS together instead of doing the process of converting Frequency and Dutycycle with integer math like SSPWM.

Using Timer1 interrupts it will run in the Background of PicBasic Pro, creating a continuous stream of pulses without the programs intervention. You only need to update the Position as needed to cause movement.

The range of pulses it produces is:

  • 1.05ms to 1.95ms in 900 steps, starting at 0.

Each step represents a .1 rotation or 1us change in pulse width. 0 is fully counterclockwise, 450 is center position 45, 900 is Full travel Clockwise 90 (Assuming you have a 90 servo)

Servos can vary widely, as a result these numbers may not reflect the way the output will work with any given motor. Check the manufacturers data sheet to better determine actual position angles.

Output frequency remains a constant 50 Hz.

The routine calculates PulseTicks1ms as a starting point of 1.05ms, then calculates how many timer ticks to add to it according to the Position value. This way it can maintain a 1us accuracy across the entire range of pulse widths.

Position gets limited to 900 to keep things from going too far accidentally.

This is all it takes to use it in your program.

PWPSpin       var PORTB.0     ' Output Pin for PWPS
include "PWPS_Servo.INC"      ' Output Pin must be Defined before Include file

Position = 450                ' Set Center Position of Servo (word) 0-900
gosub StartPWPS               ' Start the PWM output

Then, anytime you want to change the pulse width, do this:

Position = 100                ' Set Position of Servo to 10 (word) 0-900
Gosub SetPWPS                 ' Set new Pulse Width

If you need to stop the PWM output:

Gosub StopPWPS

That's about all there is to it. Well, except for one little problem ... If you get an error when compiling that looks like this

    ERROR: Variable wsave3 position request 392 beyond RAM_END 255.
ERROR: Variable wsave2 position request 276 beyond RAM_END 255.

Then you are using one of the smaller Pic chips that has fewer banks of RAM. This is where the W register would be saved if the current bank was 2 or 3 when the interrupt gets called. But since the chip doesn't have that many banks, it causes an error. Simply comment out the line that causes the error. If you use the program again on a larger chip, you'll need to Un-Comment those lines again, or it can cause some very strange bugs.

NOTE: This program uses Interrupts and Timer1. If you are using this in an existing program that is also using interrupts you will probably have Conflicts. -- More Info --

Thoroughly tested on 16F877 @ 4Mhz on a LAB-X2.

Thanks to Michael J. Pawlowsky, it was found that by changing 2 lines of code, the range could be extended to 0.9ms - 2.1ms in 1200 steps, starting at 0 Each step still represents a 1us change in pulse width. This corresponds to 120% gain setting on a transmitter.

' Change these two lines in "PWPS_Servo.INC" to extend range to  0.9ms - 2.1ms
LookUp2  y,[ 900, 1800, 2250, 2700, 3600, 4500, 5400, 5625, 7200, 7425, 9000],PulseTicks1ms

Position = Position min 1200


Page last modified on March 05, 2018, at 02:35 AM