The moving gif above shows the 3-axis robot arm going through its paces
A closer look at the 3-axis robot arm, showing servos, pushrods, circuit board mounting and switch.
A closer look at the circuit board
The following is the source code for this project.
$mod2051
CR EQU 0dh ; carriage return
LF EQU 0ah ; line feed
BAUD_9600 EQU 0fdh ; 9600 baud
;eeprom equates
FADDR EQU 0a0h ; fixed address for AT24Cxx EEPROMs
PADDR EQU 0 ; programmable address (0..7)
; Register definitions for serial eeprom
zdata EQU r1 ; data register
addr_lo EQU r2 ; 2-byte address register
addr_hi EQU r3 ;
;register definitions for hex to dec routine
count equ r0
;register definitions for robot position
xpos equ r4
ypos equ r5
zpos equ r6
;
total equ r7 ;total number of positions in the sequence
;
; Microcontroller connections to AT24Cxx serial bus lines.
SCL BIT p3.5 ; serial clock
SDA BIT p3.7 ; serial data
;servo connections
x bit p1.0 ;rotation
y bit p1.1 ;elevation
z bit p1.2 ;grip
switch bit p1.4 ;push button switch
DSEG AT 20H
delay_value: ds 1
ORG 40H ; stack origin
stack: DS 20H ; stack depth
CSEG
ORG 0000H ; power on/reset vector
jmp cold_start
ORG 0003H ; external interrupt 0 vector
reti ; undefined
ORG 000BH ; timer 0 overflow vector
call pulse
reti
ORG 0013H ; external interrupt 1 vector
reti ; undefined
ORG 001BH ; timer 1 overflow vector
reti ; undefined
ORG 0023H ; serial I/O interrupt vector
reti
ORG 40H ; begin constant data space
mess: DB CR,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF
db LF,LF,LF,LF,LF,LF,LF,LF,LF,LF
db 'Robot Test Program',LF,CR
db '________________________',LF,CR
db 'Written by Peter Averill',LF,LF,LF,CR
db 'Press:-',LF,CR
db ' x to enter rotation value 001-255',CR,LF
db ' y to enter elevation value 001-255',CR,LF
db ' z to enter grip value 001-255',CR,LF
db ' s to store position',CR,LF
db ' d to store the position delay value 01-255',cr,lf
db ' n to enter the number of positions in sequence 01-99',CR,LF
db ' l to load a sequence from the PC',cr,lf
db ' u to upload a sequence to the PC',cr,lf
db ' q to quit setup',CR,LF,LF,LF,0
mess1: db cr,lf,'x= ',0
mess2: db ' y= ',0
mess3: db ' z= ',0
mess4: db cr,lf,'Input value ',0
mess5: db cr,lf,'Save position in sequence number ? 01-30',0
mess6: db ' n= ',0
mess7: db ' d= ',0
mess8: db cr,lf,0
USING 0 ; register bank zero
cold_start:
mov sp, #(stack-1) ; initialize stack pointer
call initialize ; initialize controller registers
mov p1, #0 ; write zeros to displays
mov p3, #0ffh ; port d inputs
setb switch ;make input
setb TI
setb ES
mov xpos,#0ffh
mov ypos,#0ffh
mov zpos,#0ffh
mov acc,#07fh
call delay_5mS
top: jnb ri,m1
clr es
mov a,sbuf
clr ri
call setup
setb es
m1: clr a
mov addr_lo,a
call read_random
mov total,a
mov addr_lo,#1
clr a
call read_random
mov delay_value,a
mov count,#1
m2: mov a,count
mov b,#03h
mul ab
mov addr_lo,a
clr a
call read_random
mov xpos,a
inc addr_lo
clr a
call read_random
mov ypos,a
inc addr_lo
clr a
call read_random
mov zpos,a
mov acc,delay_value
call delay_5mS
inc count
djnz total,m2
jb switch,$
jmp top
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pulse:
push acc
push b
push dpl
push dph
push psw
mov acc,#1
setb x
mov acc,#0e0h
call delay
mov acc,xpos
call delay
clr x
setb y
mov acc,#0e0h
call delay
mov acc,ypos
call delay
clr y
setb z
mov acc,#0e0h
call delay
mov acc,zpos
call delay
clr z
mov th0,#0b9h
mov tl0,#0afh
pop psw
pop dph
pop dpl
pop b
pop acc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
setup:
mov dptr, #mess
call send_string
su1: call disp_pos
mov dptr, #mess8
call send_string
call getch
call send_char
cjne a,#'x',su2
call ipmess
call get_num
mov xpos,a
su2: cjne a,#'y',su3
call ipmess
call get_num
mov ypos,a
su3: cjne a,#'z',su4
call ipmess
call get_num
mov zpos,a
su4: cjne a,#'s',su5
call store
su5: cjne a,#'n',su6
call store_nu
su6: cjne a,#'d',su7
call store_dv
su7: cjne a,#'l',su8
call download
su8: cjne a,#'u',su9
call upload
su9: cjne a,#'q',su1
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
upload:
clr a
mov addr_lo,a
call read_random
call send_char
mov total,a
inc addr_lo
clr a
call read_random
call send_char
inc addr_lo
clr a
call read_random
call send_char
mov count,#1
ul: mov a,count
mov b,#03h
mul ab
mov addr_lo,a
clr a
call read_random
call send_char
inc addr_lo
clr a
call read_random
call send_char
inc addr_lo
clr a
call read_random
call send_char
inc count
djnz total,ul
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
download:
clr a
mov addr_lo,a
call getch
mov total,a
mov zdata,a
clr a
call write_byte
inc addr_lo
call getch
mov zdata,a
clr a
call write_byte
inc addr_lo
call getch
mov zdata,a
clr a
call write_byte
mov count,#1
dl: mov a,count
mov b,#03h
mul ab
mov addr_lo,a
call getch
mov zdata,a
clr a
call write_byte
inc addr_lo
call getch
mov zdata,a
clr a
call write_byte
inc addr_lo
call getch
mov zdata,a
clr a
call write_byte
inc count
djnz total,dl
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
store_dv:
mov dptr,#mess4
call send_string
call get_num
mov ADDR_LO,#1
mov zdata,a
mov delay_value,a
clr a
call write_byte
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
store_nu:
mov dptr,#mess4
call send_string
call get2d
mov ADDR_LO,#0
mov total,a
mov zdata,a
clr a
call write_byte
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
store:
mov dptr,#mess5
call send_string
mov dptr,#mess4
call send_string
call get2d
mov b,#03h
mul ab
mov ADDR_LO,a
mov a,xpos
mov zdata,a
clr a
call write_byte
mov acc,#0ah
call delay_5ms
inc ADDR_LO
mov a,ypos
mov zdata,a
clr a
call write_byte
mov acc,#0ah
call delay_5ms
inc ADDR_LO
mov a,zpos
mov zdata,a
clr a
call write_byte
mov acc,#0ah
call delay_5ms
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getch:
setb es ;enable reception
jnb ri,$ ;wait for key press
clr es
mov a,sbuf
clr ri
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_num:
call getch
call send_char
subb a,#30h
mov b,#64h
mul ab
mov count,a
get2d: call getch
call send_char
subb a,#30h
mov b,#0ah
mul ab
add a,count
mov count,a
get1d: call getch
call send_char
subb a,#30h
add a,count
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ipmess: mov dptr,#mess4
call send_string
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
disp_pos:
mov dptr, #mess1
call send_string
mov a,xpos
call dispdec
mov dptr, #mess2
call send_string
mov a,ypos
call dispdec
mov dptr, #mess3
call send_string
mov a,zpos
call dispdec
mov dptr, #mess6
call send_string
clr a
mov addr_lo,a
call read_random
mov total,a
call dispdec
mov dptr, #mess7
call send_string
mov a,delay_value
call dispdec
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dispdec: push acc
mov b,#0
mov count,b
again: mov b,#0ah
div ab
push b
inc count
jz wayout
jmp again
wayout: pop acc
add a,#30h
call send_char
djnz count,wayout
pop acc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
initialize:
; Initialize controller registers.
mov PCON, #0 ; initialize power control register
mov IE, #0 ; deactivate all interrupts
mov SCON, #01000000b ; serial port mode one
mov TMOD, #00100001b ; timer one 8-bit auto-reload,
; timer zero 16-bit
mov TH1, #BAUD_9600 ; timer one reload value
mov TCON, #01010000b ; start timer one & zero
mov th0,#0b9h
mov tl0,#0afh
setb et0
setb REN ;enable rx int
setb EA ;global int enable
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
send_string:
; Transmit string pointed to by DPTR.
; String may be of any length, but must be null-terminated.
push acc
push dpl
push dph
ss1:
clr a
movc a, @a+dptr ; get character
jz ss2 ; check for terminator
call send_char ; send character
inc dptr ; point to next character
jmp ss1
ss2:
pop dph
pop dpl
pop acc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
send_char:
; Wait for transmitter to clear, add even parity bit to character
; in accumulator and transmit it. Does not wait for transmitter
; to clear before returning.
jnb TI, $ ; wait here for transmitter to clear
clr TI ; clear transmit flag
push acc ; save char
mov SBUF, a ; load character into transmitter
pop acc ; restore char
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
delay:
push acc
push acc
djnz acc, $ ; 500 uS @ 12 MHz
pop acc
djnz acc, $
pop acc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
delay_5mS:
; Delay for 5mS times the value in the accumulator.
push acc
push b
mov b, a
ddd:
mov a, #0
call delay ; 1mS
call delay ; 2mS
call delay ; 3mS
call delay ; 4mS
call delay ; 5mS
djnz b, ddd
pop b
pop acc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
write_byte:
; AT24Cxx Byte Write function.
; Called with programmable address in A, byte address in
; register pair ADDR_HI:ADDR_LO, data in register XDATA.
; Does not wait for write cycle to complete.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A.
call start
jc x49 ; abort if bus not available
rl a ; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
clr acc.0 ; specify write operation
call shout ; send device address
jc x48 ; abort if no acknowledge
mov a, addr_lo ; send low byte of address
call shout ;
jc x48 ; abort if no acknowledge
mov a, zdata ; get data
call shout ; send data
jc x48 ; abort if no acknowledge
clr c ; clear error flag
x48:
call stop
x49:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
read_current:
; AT24Cxx Current Address Read function.
; Called with programmable address in A. Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
call start
jc x45 ; abort if bus not available
rl a ; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
setb acc.0 ; specify read operation
call shout ; send device address
jc x44 ; abort if no acknowledge
call shin ; receive data byte
call NAK ; do not acknowledge byte
clr c ; clear error flag
x44:
call stop
x45:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
read_random:
; AT24Cxx Random Read function.
; Called with programmable address in A, byte address in
; register pair ADDR_HI:ADDR_LO. Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
push b
mov b, a ; save copy of programmable address
; Send dummy write command to set internal address.
call start
jc x47 ; abort if bus not available
rl a ; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
clr acc.0 ; specify write operation
call shout ; send device address
jc x46 ; abort if no acknowledge
mov a, addr_lo ; send low byte of address
call shout ;
jc x46 ; abort if no acknowledge
; Call Current Address Read function.
mov a, b ; get programmable address
call read_current
jmp x47 ; exit
x46:
call stop
x47:
pop b
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
start:
; Send START, defined as high-to-low SDA with SCL high.
; Return with SCL, SDA low.
; Returns CY set if bus is not available.
setb SDA
setb SCL
; Verify bus available.
jnb SDA, x40 ; jump if not high
jnb SCL, x40 ; jump if not high
nop ; enforce setup delay and cycle delay
clr SDA
nop ; enforce hold delay
nop ;
nop ;
nop ;
nop ;
clr SCL
clr c ; clear error flag
jmp x41
x40:
setb c ; set error flag
x41:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
stop:
; Send STOP, defined as low-to-high SDA with SCL high.
; SCL expected low on entry. Return with SCL, SDA high.
clr SDA
nop ; enforce SCL low and data setup
nop
setb SCL
nop ; enforce setup delay
nop ;
nop ;
nop ;
nop ;
setb SDA
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
shout:
; Shift out a byte to the AT24Cxx, most significant bit first.
; SCL, SDA expected low on entry. Return with SCL low.
; Called with data to send in A.
; Returns CY set to indicate failure by slave to acknowledge.
; Destroys A.
push b
mov b, #8 ; bit counter
x42:
rlc a ; move bit into CY
mov SDA, c ; output bit
nop ; enforce SCL low and data setup
setb SCL ; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL ; drop clock
djnz b, x42 ; next bit
setb SDA ; release SDA for ACK
nop ; enforce SCL low and tAA
nop ;
setb SCL ; raise ACK clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
mov c, SDA ; get ACK bit
clr SCL ; drop ACK clock
pop b
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
shin:
; Shift in a byte from the AT24Cxx, most significant bit first.
; SCL expected low on entry. Return with SCL low.
; Returns received data byte in A.
setb SDA ; make SDA an input
push b
mov b, #8 ; bit count
x43:
nop ; enforce SCL low and data setup
nop ;
nop ;
setb SCL ; raise clock
nop ; enforce SCL high
nop ;
mov c, SDA ; input bit
rlc a ; move bit into byte
clr SCL ; drop clock
djnz b, x43 ; next bit
pop b
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ACK:
; Clock out an acknowledge bit (low).
; SCL expected low on entry. Return with SCL, SDA low.
clr SDA ; ACK bit
nop ; enforce SCL low and data setup
nop ;
setb SCL ; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL ; drop clock
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NAK:
; Clock out a negative acknowledge bit (high).
; SCL expected low on entry. Return with SCL low, SDA high.
setb SDA ; NAK bit
nop ; enforce SCL low and data setup
nop ;
setb SCL ; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL ; drop clock
ret
END