Welcome, Guest
Username: Password: Secret Key Remember me

TOPIC: Swordfish Module - Servo.bas

Re: Swordfish Module - Servo.bas 9 years 7 months ago #15287

Servo.bas

 

Full credit is given to MichealM, whose method of controlling servos - posted here - forms the basis of this module.

 

Overview

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.

Please Note: The module will only work correctly if the PIC is clocked at 4, 8, 16, or 32MHz

 

Using the Module

Options

The module's options and their default values are:




Options
#option Servo_NumberOfServos = 8                    'Number of servos (1 - 8)
#option Servo_Priority = ipHigh                     'Servo interrupt priority





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.

 

Connecting servos

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

 

Subroutines

Servo.On

Calling this routine will enable the interrupt and start sending pulses to the servos.

Servo.Off

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.

 

Example Program

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.



Device = 18F2520
Clock = 4
 
#option Servo_NumberOfServos = 3
 
Include "Servo.bas"
 
Dim Counter As Word
 
Function GetVoltage() As Byte
'Returns byte value representing voltage on AN0 pin (0 = 0V, 255 = 5V)
 
    ADCON0.0 = 1                        'Turn on A/D module
 
    ADCON0.5 = 0                        '}
    ADCON0.4 = 0                        '}Set A/D channel to AN0
    ADCON0.3 = 0                        '}
    ADCON0.2 = 0                        '}
 
    ADCON0.1 = 1                        'Start conversion
 
    While ADCON0.1 = 1                  '}Wait for conversion to finish
    Wend                                '}
 
    Result = ADRESH                     'Store result (8 MSBs only)
 
    ADCON0.0 = 0                        'Turn off A/D module
 
End Function
 
'===============================================================================
'Main Program
'-------------------------------------------------------------------------------  
'---Set-up analog to digital converter
ADCON1.5 = 0                            '}Set A/D Vref+ and Vref- to Vdd and Vss
ADCON1.4 = 0                            '}
 
ADCON1.3 = 1                            '}
ADCON1.2 = 1                            '}AN0 set to analog input
ADCON1.1 = 1                            '}
ADCON1.0 = 0                            '}
 
ADCON2.7 = 0                            'A/D result left justified
 
ADCON2.5 = 1                            '}
ADCON2.4 = 0                            '}Set A/D Aquisition time to 12 Tad
ADCON2.3 = 1                            '}
 
ADCON2.2 = 0                            '}Set A/D Converstion Clock to Fosc / 8
ADCON2.1 = 0                            '}This is the minimum possible with a
ADCON2.0 = 1                            '}clock speed of 4MHz (Tad = 2uS)
 
Input(PORTA.0)
 
Servo.On                                'Start sending servo control pulses
 
While True
 
    For Counter = 600 To 2400
 
        Servo.ServoPosition(0) = GetVoltage * 7 + 600
        Servo.ServoPosition(1) = Counter
        Servo.ServoPosition(2) = 3000 - Counter
 
        DelayMS(1)
 
    Next
 
    For Counter = 2400 To 600 Step -1
 
        Servo.ServoPosition(0) = GetVoltage * 7 + 600
        Servo.ServoPosition(1) = Counter
        Servo.ServoPosition(2) = 3000 - Counter
 
        DelayMS(1)
 
    Next
 
Wend



 

 

ServoInterruptComplete

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:




ServoInterruptComplete
Servo.ServoInterruptComplete = False
 
Repeat					'}Wait for the interrupt to complete
Until Servo.ServoInterruptComplete = True	'}
 
'Do important bit of code



 

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.
Read full article...
Time to create page: 0.250 seconds