- Published: Sunday, 07 March 2010
- Written by Andyo
- Hits: 16853
Download the module: Servo.bas
Full credit is given to MichealM, whose method of controlling servos - posted here - forms the basis of this module.
This module controls between 1 and 8 hobby servos connected to PortB. The module will only affect the pins which have servos connected - if less than 8 servos are used then the remaining pins on PortB can be used for other I/O.
The module is interrupt driven and uses the Timer1 and the CCP1 modules of the PIC. Although the interrupt routine is pretty lightweight (the assembler is less than 40 instructions long), users should be aware that their main program will have its execution paused every now and then to service the servos. In most cases I haven't found this to be a problem. On an 8MHz clock, I've used the module to control 8 servos whilst sending continuous UART data and reading an analogue voltage without any problems. If you do have timing-sensitive code then there are ways to mitigate problems caused by the interrupt - see below.
Please Note: The module will only work correctly if the PIC is clocked at 4, 8, 16, or 32MHz
Using the Module
The module's options and their default values are:
Servo_NumberOfServos sets the number of servos which will be controlled. Valid values are 1 to 8.
Servo_Priority sets whether the module's interrupt will be run as high or low priority. For best results, this should be left as high priority.
Servo 0 should be connected to PortB.0; Servo 1 connected to PortB.1; and so on.
Setting Servo Positions
Servos are controlled by sending them a pulse of between 600uS and 2400uS duration every 20mS. The length of the pulse determines the servo's position, with 1500uS being approximately halfway.
The module stores the position of each servo in the word array ServoPosition. To set a particular servo's position, load the length of the desired pulse (in uS) into the array. i.e. to set Servo 3 to the maximum position, use ServoPosition(3) = 2400
Calling this routine will enable the interrupt and start sending pulses to the servos.
Calling this routine stops the interrupt from firing and stops sending pulses to the servos. Note: If they are not receiving control pulses then servos will only hold their current position if no force is acting on them. However, turning off the interrupt may be useful if you need to execute a piece of code which must not be interrupted.
This example program controls 3 servos. Servo 0 is controlled by an analog input on AN0 while Servos 1 & 2 constantly move through their full range of motion.
This Boolean variable is set to "True" when the interrupt has finished executing. The interrupt is only called at the end of each servo pulse. Therefore, if you have a piece of code which must not be interrupted then you can do something like this:
Once the flag is set to True, you know you have at least 600us (minimum servo pulse duration) to execute code before the interrupt will trigger again.