Since Roger is suggesting a roll-yer-own approach I thought I'd offer an example of a software only servo driver.
- written for a 16 Mhz AT (way back last century)...
32K of MASM source code Assembles to a 3k executable file. :)
There is some pretty cool code in there. Table driven keyboard parser, default parameter cloning, automatic servo ramp back and forth.
The table driven key parser equalizes the overhead a lot better than a long list of "IF key = ???" tests. More readable too.
Since it's Assembly, it's pretty straight forward to port to any micro.
But trimmed down here of all the support stuff, DOS keys, printing, number formatting, screen stuff, etc.
The heart of the servo driver is located at K9: and calls a software delay loop at Dlay_Ax
Basic bit fiddling... Set the bit high, count on fingers and toes as directed, set the bit low. That makes the PWM signal that goes to the servo (or ESC).
Just below Start: is the key loop... wait for a key translate it to a (possible) key handler do the handler (change position, set a parameter, clone the program, etc) send another pulse loop back to do it all over again.
There are 4 delay parameters used in this program: I would think these would be common to any software only servo driver.
PT is the delay between pulse trains. This is a single channel driver, so this part simulates the time an 8 channel system would spend servicing the other 7 channels.
LD is a 1 msec lead in delay.
SD is a short delay to make the pulse width happen. (SD = 00h is left, SD = 80h is centered, SD = FFh is right) This delay will vary from 0 to 1 msec to make the PWM data pulse vary from 1 to 2 msec. Or in other words, this is the PWM DATA part.
PD is the time delay between pulses in a pulse train.
At a later time and faster computer (33 Mhz 386) I had eight channels running via a single printer port using the system timer. Those were fun days...
I think it would be easier to port to a PIC, Stamp, or Propeller than to get this running on my 2.6 GIG hz Windows machine. (getting ANY Real Time Controls running on a Windows machine is a pain)
Well, anyway, presented here just to dig the C-hags... :)
page ,132
LPT1 EQU 0278H ' IO port addresses LPT2 EQU 0378H
;----------------------------------------------------;
CSEG SEGMENT 'CODE' ASSUME CS:CSEG, DS:CSEG, ES:CSEG ORG 100H ; FOR .COM FILE
SERVO PROC FAR
JMP START db cr,' ', cr,lf db tab,tab,tab,'Direct Control Servo Driver',cr,lf db tab,tab,tab,'Copyright Richard Lamb 1993', cr,lf db tab,tab,tab,'Demo: January 25, 1993', cr,lf db 26 ;================================================= ; PROGRAM DATA AREA ;=================================================
org servo+70h
; ---------------------------------------------------- ; these parameters are updated via clone proceedure | ; | PT DW 0300H ; PULSE TRAIN DELAY | LD DW 013DH ; LEAD-IN DELAY (1 MSEC) | SD DW 0007H ; SHORT DELAY TO MAKE PULSES | PD DW 0400H ; DELAY BETWEEN PULSES | PC DB 0AH ; PULSE TRAIN COUNT | PORT DB 2 ; which printer port | RAMPFLAG DB 00H ; 0 = on, non-zero = off | RAMPDIR DB 00H ; 0 = one way, 1 = the other | SRV DB 01H ; SERVO CHANNEL NUMBER | POS DB 80H ; ATTEMPTED POSITION | ; | ; ----------------------------------------------------
LPT dw 00 ; LPT1 I/O ADDRESS
F_NAME db 'SERVO.COM',0 ; for clone routing f_hand dw 0
X_ROW DB 0 ; CURSOR ROW FOR LOC_XY X_COL DB 0 ; CURSOR COLUMN FOR LOC_XY X_CSR DW 0 ; CURSOR SIZE
CRT_HGT DB 24h ; bottom line (0 based) CRT_WID DB 79 ; rightmost column (0 based) COLOR DB 1FH ; COLOR ATTRIBUTE FOR CLS
M_open db tab,tab,'Error Locating File ',bell, '$' M_move db tab,tab,'Error Locating Data',bell, '$' M_writ db tab,tab,'Error Writing Data ',bell, '$' M_clos db tab,tab,'Error Closing File ',bell, '$' m_good db tab,tab,'SERVO.COM Defaults Updated ',bell,'$' M_Key db tab, ' [ Press a key to resume.. ]$' m_blank db tab,tab, 39 dup(' '),'$' m_lpt1 db 'LPT1$' M_LPT2 db 'LPT2$'
SCRTXT DB ' SERVO.COM Servo Timing Parameters Demo',cr,lf DB ' Direct Drive Method Copyright R. Lamb 1993',cr,lf db lf SCRW DB tab,' t - Train Delay T + Train Delay PT ',cr,lf SCRL DB tab,' l - Long Delay L + Long delay LD ',cr,lf SCRS DB tab,' s - Short delay S + Short Delay SD ',cr,lf SCRP DB tab,' p - Position P + Position POS',cr,lf DB tab,' r Ramp OFF R Ramp ON ',cr,lf DB cr,lf db lf DB tab,tab,' 1 2 Select servo channel 1 or 2',cr,lf db tab,tab,' 0 3 Turn OFF servos, or run BOTH ',cr,lf db tab,tab,' F1 F2 Select printer port 1 OR 2',cr,lf DB tab,tab,' X move to Right limit ', cr, lf DB tab,tab,' Y move to Left limit', cr, lf DB tab,tab,' Z move to Zero (centered) ',cr,lf db tab,tab,' Arrow keys - Top row = fast',cr,lf db tab,tab,' Mid row = medium',cr,lf db tab,tab,' Bot row = slow',cr,lf db tab,tab,' ~ to clone new defaults ',cr,lf DB tab,tab,' ESC to terminate program ',cr,lf db '$'
M_ON db 'On $' M_OFF db 'Off $' M_Left db 'Left $' M_RIGHT db 'Right$'
P_F1 DB 'F1 $' P_F2 DB 'F2 $' P_F3 DB 'F3 $' P_F4 DB 'F4 $' P_F5 DB 'F5 $' P_F6 DB 'F6 $' P_F7 DB 'F7 $' P_F8 DB 'F8 $' P_F9 DB 'F9 $' P_F10 DB 'F10$'
FUN_TAB: ;-------------------------------; ; LIST OF KEY CODES TO LOOK FOR ; ;-------------------------------;
DB '12' db '30' DB 'tT' DB 'pP' DB 'zZ' DB 'lL' DB 'sS' DB 'xX' DB 'yY' DB 'rR' db '~~'
DB 71, 72, 73 ; 7 8 9 KEYPAD KEYS DB 75, 5, 77 ; 4 5 6 (ARROWS) DB 79, 80, 81 ; 1 2 3
DB 59, 60, 61 ; F: 1 2 3 FUNCTION KEYS DB 62, 63, 64 ; F: 4 5 6 DB 65, 66, 67 ; F: 7 8 9 DB 68 ; F: 10
DB 0 ; ARNOLD
FUN_ADDR: ;-------------------------------; ; JUMP TABLE FOR HANDLER CODE ; ;-------------------------------;
DW chan1, chan2 dw chan3, chan0 DW decT, incT DW decP, incP DW zero, zero DW decL, incL DW decS, incS DW left, left DW right, right DW rampoff, rampon dw clone, clone
DW KHOME, KUARR, KPGUP DW KLARR, KEY5, KRARR DW KEND, KDARR, KPGDN
DW KFUN1, KFUN2, KFUN3 DW KFUN4, KFUN5, KFUN6 DW KFUN7, KFUN8, KFUN9 DW KFUN10
DW 0
;=======================
START: mov bx, lpt1 cmp port, 1 jz P1
mov bx, lpt2
P1: mov lpt, bx
call Get_Rows_N_Cols CALL CLS CALL Screen
MOV DX, LPT ; SET DX TO POINT TO PRINTER PORT MOV AL, 0 OUT DX, AL ; SET ALL BITS LOW TO START
KEYLUP: CALL INKEY CALL UCASE
KESC: CMP AL, 27 ; ESCAPE KEY ? JNZ K1
QUIT: MOV ax, 1700h CALL loc_AX MOV AH,04CH ; MILLER TIME! MOV AL, 0 ; RETURN CODE INT 21H
;-------------------------------------------------
K1: MOV SI, OFFSET FUN_TAB ; SEARCH FUN_TABLE FOR KEY IN AL MOV BX, 0 ; CLEAR TABLE INDEX K3: CMP BYTE PTR [SI+BX], AL ; FIND HIM? JE K4 ; GOT HIM ! Jump to dispatcher... INC BX ; POINT TO NEXT BYTE CMP BYTE PTR [SI+BX], 0 ; CHECK END OF TABLE ? JE K0 ; END OF TABLE ! DON'T BOTHER. JMP SHORT K3 ; NO, KEEP LOOKIN...
;------------------------------------------------- K4: ; OK, AL HAS THE KEY - AND IT WAS IN THE LIST. ; BX HAS AN OFFSET COUNT (0 TO ?) BY ONESIES...
MOV AX, BX ; INDEX COUNT LEA BX, FUN_ADDR ; TABLE OF HANDLER ADDRESSES ADD AX, AX ; X2 ADD BX, AX ; OFFSET OF MATCHING HANDLER MOV BX, [BX] CALL BX ; DO HANDLER ROUTINE...
;--------------------------------------------------------- ;---------------------------------------------------------
K0: CMP rampflag, 0ffh ; no ramp if FF JZ k9 R0: CMP rampdir, 0 ; 0 is decrement JNZ r1 ; bif increment
CMP pos, 1 ; decrement pos JA r2
MOV rampdir, 1 ; change direction JMP r0 ;-------------
R2:
DEC pos ; decrememt pos call sho_pos JMP k8 ; doit
R1: CMP pos, 0ffh JB r3
MOV rampdir, 0 ; change dir JMP r0 ;-------------
R3: INC pos call sho_pos JMP k8 k8: MOV AX, 083BH ; show direction CALL LOC_AX ; locate screen row, col
lea dx, M_Right cmp rampdir, 0 jz k81
lea dx, M_Left k81: call print$
K9: ; test table driven pulse routine ================
MOV AL, POS ; DESIRED SERVO POSITION MOV BL, AL ; KEEP POSITION CODE IN BL
MOV DX, LPT ; ACTIVE PRINTER PORT MOV AL, SRV ; SELECT SERVO CHANNEL NUMBER
OUT DX, AL ; START OF THE PULSE ****
K10: MOV CX, LD ; lead-in delay (1 mSec)
K10B: NOP ; 3 clock cycles NOP LOOP K10B
MOV CH,0 ; 2ND HALF; MOV CL,BL ; BL HAS POSITION CODE FROM TABLE
K12: PUSH CX MOV CX, SD ; short delay (1mSec/# of table positions) K12B: NOP LOOP K12B
NOP NOP
POP CX LOOP K12
MOV AL,0 ; TURN BITS OFF OUT DX, AL ; END OF THIS PULSE ****
; end of pulse routine ===========================
MOV AX, PT ; delay between pulses CALL DLAY_AX JMP KEYLUP ; ROLL ANOTHER ONE.....
;--------------------------------------------------------- ;---------------------------------------------------------
SERVO ENDP
;--------------------------------------------------------- ;=========================================================
DLAY_AX PROC NEAR ; LONG DELAY - AX HAS TICK ITERATIONS PUBLIC DLAY_AX, LD_1, LD_2
PUSH CX PUSH AX LD_1: MOV CX, 0FH ; LONG 'NUF ? LD_2: LOOP LD_2 DEC AX CMP AX, 0 JNZ LD_1 POP AX POP CX RET
DLAY_AX ENDP
;=========================================================
;=========================================================
;=========================================================
;=========================================================
CSEG ENDS
END SERVO