🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: sci.electronics
Article #10282

Servo driver

#10282
From: Richard E Lamb
Date: Tue, 19 Feb 1991 16:30
330 lines
13511 bytes
   Please, don't anybody hit me for wasting bandwidth with this LONG
posting!  There have been so many people requesting info about using
these little servo motors that I thought it would be ok to post the
driver.  Also, check the comment section at the end of the code re:
why I used a table driven approach vs calculated delays.  Hope this
will help those interested in tinkering with servos get started.
If you use this code as a starting point, how 'bout some feedback?

      (And PL-Ease, no more requests to translate this to C - I
      don't use C, I don't like C, an' I ain't gonna do it!  OK?)



        page    ,132
;------------------------------------------------------------------------
;
;  SERVO2C.ASM  - (C) R. LAMB 1988
;  Jan 7, 1989
;  Posting this for all those who asked how it was done.
;  This program will drive a servo in a demo pattern.
;  No wild claims are made about the coding style except that it works.
;------------------------------------------------------------------------
;OVERVIEW:
;       This program sends a Pulse Width Modulated pulse train
;       suitable for Radio Control type miniature servos.
;       LPT1: is used as the interface port.  It is suggested
;       that a buffer circuit be added to the printer port to
;       help protect the computer from dire disasters.
;       A small regulated +5 volt power supply is also recommended
;       to prevent motor EMF from feeding back into the computer.
;
;       For what it's worth, I didn't use a scope or even a calculator
;       to develop this - just a bit of "FEEL" for what I was after.
;	I simply started shipping different width pulses to the servo.
;       Once the servo started responding, the delay loops were tweaked
;       to locate the "ENDS" of the pulse widths for full travel.
;       The difference between full left and full right were divided
;       into 15 equal pieces - and it was done.
;
;       I have noticed that a 4.77 MHz PC tends to "jitter" the servo
;       a bit.  We spent some effort trying to track down the cause and
;       decided it was probably due to dRAM refresh (?).  Curiouser...
;
;	The code uses software delay loops to produce the pulses.
;	OK, it ain't "elegant", but it is cheap and simple.  If you
;	play aroung with it on a faster machine, you will have to 
;	tweek the loops to match.  On the origional (a 6 mhz Z80),
;	the delays were managed by the task supervisor, which used
;	a counter-timer for the delay tics.  True multi-tasking stuff.
;
;       For an 8 Mhz XT, the delay loops look something like this:
;
;         PW = 160      = pulse width
;         first "half" of pulse = 1 Msec lead-in
;               mov ch,0	
;               mov cl,bl
;               2 nop's
;               loop
;         second "half" of pulse = PWM position = 0 to 1 Msec
;               mov ch,0
;               mov cl,bl
;               push ax
;               pop  ax
;               2 nop's
;               loop
;
;-----------------------------------------------------------
;
;       Minimal Interface for Printer Port:
;       One 7404 Hex inverter can provide 2 servo channels.
;
;                                   Regulator
;                                    _______
;         9 v DC in                 |       | 5 v DC out
;       >-------------------*-------| 7805  |--------*---, 
;                           |       |_______|        |  ===
;                          ===         |             |   |
;                           |          |             |   V    
;                           V          |             |
;                                      |      ,------*---<] Motor +5 volts
;       Printer bit   1|\ 2    3|\ 4   |      |
;    2  >--------------| >o--*--| >o---------.|.---------<] Servo PWM Signal
;       Printer ground |/    |  |/     |      |
;    25 >-------------------.|.--------*-----.|.---------<] Ground
;                            |         |      |            Wire this connector
;                            |        ___     |            to match your servo.
;                            |         -     ,-,
;                            |               |R|
;                            |               |_| 320 ohms
;                            |11|\ 12    //   |
;                            `--| >o----|>|---'
;                               |/
;                                       LED
;	The regulator is fed from a AC adapter, but a diode bridge and
;	transformer can also be used.  
;	The LED shows activity, and suprisingly, also shows the PULSE WIDTH!
;
;-----------------------------------------------------------
;EQUATES:
;
cr	equ	10h		; carrage return
lf	equ	13h		; line feed
PW      EQU     160             ; PULSE WIDTH DELAY
PC      EQU     100             ; PULSE TRAIN COUNT
PD      EQU     512		; DELAY BETWEEN PULSES
LPT1    EQU     0278H           ; PRINTER PORT 1 I/O ADDRESS
LPT2    EQU     0378H		; PRINTER PORT 2 I/O ADDRESS
LPT     EQU     LPT2            ; LPTn I/O ADDRESS (pick one)
wait_1  EQU     1000h           ; lunch duration (between pulse trains)
;----------------------------------------------------------------
cseg	segment 'code'
	assume	cs:cseg, ds:cseg, es:cseg
	org	100h		; for .COM file
servo	proc	far
	jmp	start

;----------------------------------------------------------------
;LOCAL STORAGE: 
CMD     DB       000H           ; where we want servo to go
SRV     DB       001H           ; servo channel number
POS     DB       0FFH           ; attempted position

Hello	db	'Servo demo 22C: $'  
p_mes   db      13,10,'Position: $'
c_mes   db      ' Code: $'
;----------------------------------------------------------------
start:	
	lea	dx, Hello
	call	print_msg
	call	newlin
	mov	dx, lpt		;get address of the port 
	mov	al, 0
        out     dx, al          ;set all bits low to start
 
s1:     mov     pos,0           ; init to the "HOME" position
 
feed:	mov	ah, 0bh		; see if it's time to quit
        int     21h             ; any key will stop us
	cmp	al, 0ffh	; key pressed
	jnz	go
 
        mov     al, 0           ; all bits low when quitting
	out	dx, al
	int	20h		; return to DOS
                                ;----------------
go:     inc     pos		; step to next position in the table
        cmp     pos, 0fh	; last pos done?
        jg      s1              ; if yes, wrap back to table pos 0
        lea     dx, p_mes	; show position message
        call    print_msg	;
 
        mov     al,pos          ; save next command position
        mov     cmd, al         ; where we want it to go
        mov     ah,0
        call    hex2con  	; show where we's at
        lea     dx, c_mes       ; say something nice
        call    print_msg
;                               ;----------------------
        mov     srv, 01         ; channel 1
        call    train           ; make a pulse train happen
        mov     ax, wait_1      ; wait loop iterations
        call    l_dlay          ; take a short coffee break
        mov     cmd, 0          ; move it back to HOME pos
        call    train           ; catch a train for the coast
        mov     al, pos         ; recover current pos
        mov     cmd,al          ; restore next command position
        mov     cx, 1           ;
HOLD:   PUSH    CX              ; delay between position cycles
        mov     ah, 25          ;  wait some
        call    l_dlay          ;   more
        POP     CX              ;    and
        LOOP    HOLD            ;     more
                                ;
        jmp     feed            ;
;                               ;-----------------------
servo	endp
;----------------------------------------------------------------
TRAIN	proc	near
 
;       CMD is table entry for positioning servo        AL
;	SRV is servo channel number			AH
;	BL is servo position code (after XLAT)
;	BH is the number of pulses to make		PC
 
	LEA	bx, srvtab	; POINT TO POSITION TABLE
	mov	al, CMD		; servo channel number
	XLAT			; XLAT POSITION CODE TO AL
 
        push    ax
        call    hex2con		; show n tell
        pop     ax
 
        MOV     BL, AL          ; MOVE POSITION CODE IN BL
	MOV	BH, PC		; NUMBER OF PULSES TO MAKE 
 
T_2:    PUSH    BX              ; SAVE POSITION/COUNT
	CALL	PULSE		;   MAKE A BIG ONE
 
        POP     BX              ; GRAB OUR GOODIES BACK
        DEC     BH              ; COUNT THAT PULSE OFF (COUNT DOWN)
	CMP	BH,0		; ALL PULSES SENT ?
	JNZ	T_2		; BIF NOT YET ...
 
        RET                     ; BACK TO CALLER !!!
;
PULSE:
        MOV     DX, LPT         ; ACTIVE PRINTER PORT
        MOV     AL, SRV         ; SELECT SERVO CHANNEL NUMBER
				; if doing several channels at once, you
				; need to preserve the current context
				; of the output port.  (74LS259's are BEST!)
;-------------------------------,
        OUT     DX, AL          ;     START OF THE PWM SIGNAL TO THE SERVO
PF_1:   mov     ch,0
        mov     cl,pw           ;     1st millisec half
PF_2:   nop                     ;
        nop                     ;
        loop    pf_2            ;
P_1:
        mov     ch,0            ;     2nd half
        mov     cl,bl           ;     BL HAS POSITION CODE FROM TABLE
P_2:    nop                     ;
        nop                     ;     SITTIN' ON THE DOCK
        push    ax              ;       OF THE BAY
        pop     ax              ;         WASTIN' TI-III-IME
        loop    p_2             ;
P_3:
        MOV     AL,0            ;     TURN PWM BITS OFF
        OUT     DX, AL          ; END OF THIS PULSE
;-------------------------------'
        MOV     AL, 05          ; OUTTER LOOP DELAY BETWEEN PULSES
PT_1:   MOV     CX, PD          ; INNER LOOP (PERIOD) DELAY VALUE
PT_2:
        LOOP    PT_2            ; INNER LOOP ITSELF
        DEC     AL              ; COUNT OUTTER LOOP
        CMP     AL, 0           ; ARE WE DONE YET ?
        JNZ     PT_1            ; BIF NOT YET ...

        RET                     ; ROLL ANOTHER ONE ...
TRAIN	endp
;----------------------------------------------------------------
L_DLAY  PROC    NEAR            ; LONG DELAY - Ax has tick iterations
	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
L_DLAY	ENDP
;----------------------------------------------------------------
HEX2CON         PROC    NEAR
        PUSH    AX                      ;Save reg for second digit
        PUSH    CX                      ;Save CX for use in shift
        MOV     CL,4                    ;Shift 4 bits
        SHR     AL,CL                   ;Get high 4 bits in low end
        POP     CX                      ;Restore register
        CALL    H2C                     ;Print the digit in AL
        POP     AX                      ;Get back original AL
        AND     AL,0FH                  ;Take second digit
 
H2C:    ADD     AL,90H                  ;Convert AL to ASCII
        DAA
        ADC     AL,40H
        DAA
        MOV     AH,0EH                  ;Write TTY
        INT     10H                     ; Thru BIOS
        RET                             ;Double duty
HEX2CON ENDP
;----------------------------------------------------------------
newlin  proc    near
        push    ax
        push    dx
        mov     ah, 02h
        mov     dl, 13
        int     21h
        mov     ah, 02h
        mov     dl, 10
        int     21h
        pop     dx
        pop     ax
        ret
newlin  endp
;
PRINT_MSG	PROC	NEAR
	mov	ah, 9
	int	21h
        RET
PRINT_MSG	ENDP
 
;----------------------------------------------------------------
 
SRVTAB:
;       THIS PROGRAM USES A POSITION TABLE TO DETERMINE THE SERVO
;       PULSE WIDTH.  FOR THIS SIMPLE DEMO, IT MAY NOT BE APPARENT
;       WHY I WANTED THIS, BUT CONSIDER:
;       WHAT IF YOU NEEDED A NON-LINEAR FUNCTION?  SUPPOSE YOU WANTED
;       A _LOGRYTHMIC_ RESPONSE? OR SOME FUNKY ARBITRARY KINDA THING TO
;	TURN THE TUNING KNOB ON YOUR RADIO (hey, I don't know what you want!).
;       BY PLUGGING DELAY VALUES INTO THE TABLE THAT ARE NOT STRICTLY
;       LINEAR, YOU CAN CUSTOM TAILOR THE SERVO RESPONSE CURVE EASILY.
;       _AND_ NO MESSY FLOATING POINT CALCULATIONS TO FUSS WITH!
;
HOME:   DB       077H   ; HOME = POS 0  = CENTERED - FOR NOW ...
;
        DB       010H   ; RIGHT = 1 = CW
        DB       020H   ; 2
        DB       030H   ; 3
        DB       040H   ; 4
        DB       050H   ; 5
        DB       060H   ; 6
        DB       070H   ; 7
        DB       077H   ; CENTERED = 8
        DB       080H   ; 9
        DB       090H   ; 10
        DB       0A0H   ; 11
        DB       0B0H   ; 12
        DB       0C0H   ; 13
        DB       0D0H   ; 14
        db       0E0h   ; LEFT = 15 = CCW       ;
;------------------------------------------------------------------------
cseg	ends
;
	end	servo
Technical Details
Message-ID: <18861@brahms.udel.edu>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!elroy.jpl.nasa.gov!ncar!gatech!udel!brahms.udel.edu!lamb

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!elroy.jpl.nasa.gov!ncar!gatech!udel!brahms.udel.edu!lamb
From: lamb@brahms.udel.edu (Richard E Lamb)
Newsgroups: sci.electronics
Subject: Servo driver
Message-ID: <18861@brahms.udel.edu>
Date: 19 Feb 91 16:30:20 GMT
Distribution: all
Organization: University of Delaware
Lines: 330