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