Here it is! Control 8 servo's with your PC and an 18F2550 PIC using USB. It uses the USB_HID library and is built around the HID example provided in the mikroBASIC folder for the 18F2550. You will need my Visual Basic program to run on the PC side.
The program runs 8 independent 50Hz servos from PORTB with a resolution of 256 steps! The servo PWM on-time routine takes a mere 2200us. The rest of the time out of a 20ms period is totally for the pleasure of the programmer to do what he likes with the PIC.
Below is the mikroBASIC sourcecode including the sourcecode parts you need to set in the "USBdsc.pbas" file which must be included in the same folder as the main mB code if you intend to compile. The "USBdsc.pbas" can be found in the mikroBASIC Examples folder for the 18F2550 HID example.
PC SERVO CONTROLLER PROGRAM
HEX FILE (for those of you who don't have the registered version of mB)
Required values for these constants in the USBdsc.pbas module:
Code: Select all
const HID_INPUT_REPORT_BYTES = 1
const HID_OUTPUT_REPORT_BYTES = 8
const DeviceDescr as byte[USB_DEVICE_DESCRIPTOR_LEN*2] = (
USB_DEVICE_DESCRIPTOR_LEN, 0, ' bLength - Length of Device descriptor (always 0x12)
USB_DEVICE_DESCRIPTOR_TYPE, 0, ' bDescriptorType - 1 = DEVICE descriptor
0x00, 0, ' bcdUSB - USB revision 2.00 (low byte)
0x02, 0, ' (high byte)
0x00, 0, ' bDeviceClass - Zero means each interface operates independently (class code in the interface descriptor)
0x00, 0, ' bDeviceSubClass
0x00, 0, ' bDeviceProtocol
EP0_PACKET_SIZE, 0, ' bMaxPacketSize0 - maximum size of a data packet for a control transfer over EP0
0x34, 0, ' idVendor - Vendor ID (low byte)
0x12, 0, ' (high byte)
0x01, 0, ' idProduct - Product ID (low byte)
0x00, 0, ' (high byte)
0x01, 0, ' bcdDevice - ( low byte)
0x00, 0, ' (high byte)
0x01, 0, ' iManufacturer - String1
0x02, 0, ' iProduct - String2
0x00, 0, ' iSerialNumber - ( None )
0x01, 0 ' bNumConfigurations - 1
)
Code: Select all
'***************************************************************************************
'* 18F2550 PIC USB_HID 50Hz PWM SERVO CONTROLLER *
'* by W. Schroeder alias "xor" -- July 4, 2006 *
'* *
'* Compiled with mikroBASIC 4.03 and demonstrated on EasyPIC3 Development Board *
'* Uses mikroBASIC USB_HID Library and needs "USBdsc.pbas" and "HID_Constant.pbas" *
'* Also required is the Visual Basic Demo program included with this file. *
'* *
'* Configuration settings are same as the mikroBASIC HID example for the 18F2550 *
'* with an 8MHz crystal oscillator. *
'* *
'* The EasyPIC3 board facilitates an easy connection to the PIC via USB and was *
'* chosen to demonstrate this project. The 18F2550 uses an 8MHz crystal oscillator. *
'* Internally, the PLL is set to bump up the PIC's speed to 48MHz to enable USB comm. *
'* *
'* For the purposes of this demo all output pins of PORTB are utilized. *
'* Servo0 is PORTB.0, Servo1 is PORTB.1, ......, Servo7 is PORTB.7 *
'* *
'* The range of PWM on-time is 800us to 2200us analogous with a resolution of 0 to 255 *
'* A value of 127/128 is considered 50% of servo rotation with an on-time of 1500us *
'* *
'* USB connections to the 18F2550 are D+ = RC5 and D- = RC4 *
'***************************************************************************************
'***************************************************************************************
include "USBdsc"
dim T0 as word absolute $FD6
dim old as byte
dim servoport as ^byte
dim _s0,_s1,_s2,_s3,_s4,_s5,_s6,_s7 as byte
dim
wrbuf as byte[2]
servo as byte[9]
wr_adr as word
sub procedure delay_810us
delay_us(810)
end sub
sub procedure interrupt
If INTCON.TMR0IF = 1 Then
servoport^ = 255 ' turn on all servos
_s0 = servo[0] + 1 ' set up temp variables
_s1 = servo[1] + 1
_s2 = servo[2] + 1
_s3 = servo[3] + 1
_s4 = servo[4] + 1
_s5 = servo[5] + 1
_s6 = servo[6] + 1
_s7 = servo[7] + 1
old = 0
FSR0L = servoport
FSR0H = hi(servoport)
delay_810us
TMR0L = 0
For old = 0 to 255 ' manage 256 positions
ASM
movlw 0
decfsz main_global__s0, 1,0
iorlw 1
decfsz main_global__s1, 1,0
iorlw 2
decfsz main_global__s2, 1,0
iorlw 4
decfsz main_global__s3, 1,0
iorlw 8
decfsz main_global__s4, 1,0
iorlw 16
decfsz main_global__s5, 1,0
iorlw 32
decfsz main_global__s6, 1,0
iorlw 64
decfsz main_global__s7, 1,0
iorlw 128
andwf INDF0, 1,0
END ASM
While TMR0L = old
Wend
Next old ' all servo outputs are off at this point
T0= -3600 ' time to complete balance of time for 20ms cycle
INTCON.TMR0IF = 0 ' get ready to interrupt again
Else
HID_InterruptProc
End If
end sub
sub procedure Init_Main
INTCON2 = 0xF5
INTCON3 = 0xC0
RCON.IPEN = 0 ' Disable Priority Levels on interrupts
PIE1 = 0
PIE2 = 0
PIR1 = 0
PIR2 = 0
ADCON1 = 15 ' digital IO
TRISA = 0
TRISB = 0
TRISC = 0
LATA = 0
LATB = 0
LATC = 0
end sub
sub procedure SERVO8_INIT(dim byref servo_port as byte,
dim port_config as byte)
servoport = @servo_port + 18 ' PORT TRIS ADDRESS
servoport^ = servoport^ And Not(port_config) ' SET TRIS
servoport = servoport - 9 ' PORT LATCH ADDRESS
T0CON = %00000101 ' prescaler = 64 or ~5us per increment
T0 = -4000 ' preset for 20ms
INTCON = %10100000 ' Timer0 Interrupt Enabled and Flag Cleared
T0CON.7 = 1 ' Timer0 On
end sub
main:
Init_Main
SERVO8_INIT(PORTB, 255)
HID_Enable(@servo, @wrbuf)
Delay_mS(1000)
while true
If HID_READ <> 0 Then ' if USB package has arrived
wrbuf[0] = 255 ' servo positions are in Read_Buffer
HID_WRITE(@wrbuf, 1) ' reply with verification
End If
wend
HID_Disable
'** This code is necessary in order to make linker load the variables and HID_InterruptProc routine.
'** In real time it will never execute.
if false then
HID_InterruptProc
wr_adr = @DeviceDescr
wr_adr = @ConfigDescr
wr_adr = @InterfaceDescr
wr_adr = @HID_Descriptor
wr_adr = @EP1_RXDescr
wr_adr = @EP1_TXDescr
wr_adr = @HID_ReportDesc
wr_adr = @LangIDDescr
wr_adr = @ManufacturerDescr
wr_adr = @ProductDescr
wr_adr = @StrUnknownDescr
end if
end.