This blog post is about our current EV3 robot we're planning to use in the 2023/2024 FLL competition. Some features: 2 large motors for steering. 2 medium motors for attachments. 2 colour sensors for picking up the white and black lines, also used for line squaring. 1 gyro sensor. To enable attachments to be changed as quickly as possible we're using gravity to keep the gears connected, i.e. you don't need to fasten anything to the robot. Every attachment has 2x 12 tooth double bevel gear (part 32270) which comes in contact with the 2x 20 tooth double bevel gears (part 32269) on the robot. The medium motors are horizontally aligned on the robots, but we use 12 tooth double bevel gears to convert that to vertical alignments. These in turn are connected to 20 tooth double bevel gears, and the attachments in turn connect to these 20 tooth double bevel gears with their 12 tooth double bevel gears. The complete robot is modelled in Bricklink Studio 2 . You can download the rob
NumBytes equ 040h
Choice equ 041h
CRC equ 042h
LineCount equ 043h
Counter equ 044h
Counter2 equ 045h
BaseH equ 046h ; Base address of SRAM
BaseL equ 047h
HexCount equ 048h ; 16 hex chars/line counter
Endflag equ 20h
Hexflag equ 21h
org 0000h
ljmp Main
org 0020h
Main:
lcall Init ; Initialise hardware
mov BaseH, #0E0h ; Set default base E000h
mov BaseL, #000h
mov dptr, #WelcomeMessage
lcall SendString ; Print welcome message
lcall SendCRLF
MenuLoop:
mov dptr, #MenuMessage
lcall SendString ; Show options
Wait:
jnb RI, Wait ; Wait until a char is received from serial port
lcall Receive ; Get char in accumulator
mov choice, a ; save choice
mov dptr, #OptionList ; Points to valid options string
lcall Position ; determine if char is a valid choice
jz Invalid
dec a ; 0 is first option
push acc
lcall SendCRLF
pop acc
lcall Branch ; Execute option
lcall SendCRLF
sjmp MenuLoop ; Start menu again
Invalid:
mov a, choice ; retreive choice
lcall Send ; send char back
mov dptr, #InvalidMessage
lcall SendString ; Show that choice is invalid
sjmp Wait ; Wait for a valid char
SetBase:
mov dptr, #BaseAskMessage
lcall SendString
lcall ReceiveHex
mov BaseH, a
lcall SendHex
lcall ReceiveHex
mov BaseL, a
lcall SendHex
lcall SendCRLF
ret
Download:
mov dptr, #DownloadMessage
lcall SendString ; Show message
mov LineCount, #0
clr EndFlag
StartLine:
inc LineCount
WaitColon:
lcall Receive
cjne A, #':', WaitColon
ProcessLine:
mov CRC, #0
lcall ReceiveHex
mov NumBytes, a
lcall ReceiveHex
add a, BaseH ; adjust for RAM mapping
mov dph, a
lcall ReceiveHex
add a, BaseL ; adjust for RAM mapping
mov dpl, a
jnc ContinueProcess
inc dph ; correct pointer
ContinueProcess:
lcall ReceiveHex
jz ReceiveData
setb EndFlag
mov NumBytes, #0
ReceiveData:
mov a, NumBytes
jz CheckSum
lcall ReceiveHex
movx @dptr, a
inc dptr
dec NumBytes
sjmp ReceiveData
CheckSum:
lcall ReceiveHex
mov a, CRC
jnz ChecksumError
jnb EndFlag, StartLine
ReceivedOK:
mov dptr, #DownloadOK
lcall SendString
lcall SendCRLF
lcall Receive ; Eat last byte
ret
CheckSumError:
mov dptr, #DownloadErr
lcall SendString
mov a, LineCount
lcall SendASCII
lcall SendCRLF
ret
ReceiveHex:
lcall Receive
lcall Hex2Num
mov B, #010h
mul AB
mov r7, a
lcall Receive
lcall Hex2Num
add a, r7
push acc
add a, CRC
mov CRC, a
pop acc
ret
Hex2Num:
clr c
subb A, #030h ; Convert 0-9
cjne A, #009h, AdjustNumber
ret
AdjustNumber:
jc EndConvert
subb A, #007h ; convert A-F
EndConvert:
ret
Verify:
mov hexcount, #10h
mov dptr, #VerifyMessage
lcall SendString ; Show message
lcall ReceiveHex ; Get size
mov Counter, a
lcall SendHex
lcall ReceiveHex
mov Counter2, a
lcall SendHex
lcall SendCRLF
mov dptr, #DumpMessage
lcall SendString
lcall Receive ; Hex or ASCII mode
clr HexFlag
cjne a, #'H', ASCIIDump
setb HexFlag ; Hex mode
ASCIIDump:
lcall SendCRLF
mov dph, BaseH
mov dpl, BaseL
VerifyByteLoop:
mov a, Counter2
jz Counter1Loop
dec Counter2
ajmp VerifyOutput
Counter1Loop:
mov a, Counter
jz VerifyEnd
dec Counter
mov Counter2, #0FFh
ajmp VerifyOutput
VerifyEnd:
ret
VerifyOutput:
movx a, @dptr ; read ram
jb HexFlag, VerifyHex
lcall Send ; send char
ajmp OutputEnd
VerifyHex:
lcall SendHex ; send char in HEX format
djnz HexCount, HexSpace
mov HexCount, #10h ; 16 chars / line
lcall SendCRLF
ajmp OutputEnd
HexSpace:
mov a, #' '
lcall Send
OutputEnd:
inc dptr
ajmp VerifyByteLoop
;============================================================================
;Hardware initialisation
;============================================================================
Init: ; Setup all hardware
mov ip, #00000010b ; Interrupt priority: T0,SER,T1,INT1,INT0
; effectivly T0,INT1 - others not used
mov tmod, #00100010b ; set timer 0 & 1 to 8-bit auto-reload mode
mov th1, #0fdh ; timer 1 reload value: 256-253=3
; 11.0592Mhz / 12 / 32 / 3 = 9600 baud
mov pcon, #10000000b ; double baudrate : 19.2k
mov scon, #01010000b ; 8-bit UART & enable reception
mov tcon, #01000000b ; run timer 1
mov ie, #00000000b ; Disable all interrupts
ret
;============================================================================
;3-way branching routine
; use r7
;============================================================================
Branch:
clr c
rlc a ; Multiply by 2 (2 bytes)
mov r7, a ; Save choice in r7
mov dptr, #OptionTable ; Point to base of table
inc a
movc a, @a+dptr ; Read MSB in acc
push acc
mov a, r7 ; Reload choice
movc a, @a+dptr ; Read LSB in acc
push acc
ret ; branch to address
;========================================================================
; Determine position of char (in acc) in a string pointed by DPTR.
; Position returned in accumulator, 1=first char, 0 = not found
; Use r6 & r7
;========================================================================
Position:
mov r7, a ; Store char in R7
mov r6, #0 ; set index to 0
Compare:
mov a, r6 ; load index
inc r6 ; increase index to next char
movc a, @a+dptr ; read in char
jz ExitPosition ; exit if at end of string
clr c ; clear carry for subtraction
subb a, r7 ; subtract char from acc
jnz Compare ; no match
mov a, r6 ; return with index in acc
ret
ExitPosition:
ret
;========================================
;Convert char in acc to uppercase
;========================================
UpperCase:
cjne a, #60h, Greatera ; Test if char >= 'a'
sjmp OtherChar ; char equal to 60h
Greatera:
jc OtherChar ; not >= 'a'
cjne a, #7Bh, Lessz ; test if char <= 'z'
sjmp OtherChar
Lessz:
jnc OtherChar ; not <= 'z'
clr c ; clear carry for subtraction
subb a, #20h ; convert to uppercase
OtherChar:
ret
;============================================================================
;Sends char in accumulator out the serial port
;============================================================================
Send:
clr TI ; Clear transmit interrupt flag
mov sbuf, a ; Put char in transmit buffer
SendSerialLoop:
jnb TI, SendSerialLoop ; Wait until char is transmitted
ret
;============================================================================
;Receives a char from the serial port and stores it in the accumulator
;============================================================================
Receive:
jnb RI, Receive ; Wait until char is received
mov a, sbuf ; Read char into accumulator
clr RI ; Clear receive interrupt flag
lcall Uppercase ; Convert char to uppercase
ret
;============================================================================
;Sends number in accumulator out the serial port in HEX format
; Use r7
;============================================================================
SendHex:
mov r7, a ; Save accumulator in R7
swap a ; Most significant 4 bits first
lcall Lookup_Send ; Send first hex digit
mov a, r7 ; Reload original value
lcall Lookup_Send ; Send second hex digit
ret
;============================================================================
;Sends number in accumulator out the serial port in ASCII format
; Use r6 & r7
;============================================================================
SendASCII:
mov r7, a ; Save accumulator in R7
mov b, #100d
div ab ; divide acc by 100
lcall Lookup_Send ; send first digit
mov b, #100d
mul ab ; value of byte send
mov r6, a ; store value in r6
mov a, r7 ; restore original value
clr c ; clear carry bit
subb a, r6 ; remaining value to send
mov r7, a ; save remaining value in r7
mov b, #10d
div ab ; divide acc by 10
lcall Lookup_Send ; send second digit
mov b, #10d
mul ab ; value of byte send
mov r6, a ; store value in r6
mov a, r7 ; restore original value
clr c ; clear carry bit
subb a, r6 ; remaining value to send
lcall Lookup_Send ; send last digit
ret
Lookup_Send: ; Convert a decimal/hex digit to ASCII
push acc ; save acc on stack
anl a, #00001111b ; Mask off 4 bits
add a, #0f6h ; overflow if digit > 9
jnc NoAdjust ; no overflow digit <= 9
add a, #07h ; Adjust for hex digits (A-F)
NoAdjust:
add a, #3ah ; Adjust for ASCII
lcall send ; Send char to serial port
pop acc ; reload acc from stack
ret
;============================================================================
;Sends a null-terminated string to the serial port. DPTR=Begin address
; - modifies a & dptr
;============================================================================
SendString:
clr a ; no offset from DPTR
movc a, @a+dptr ; input first char in acc
jz SendString_End ; null-termination
inc dptr ; point to next char
lcall Send ; send current char
sjmp SendString
SendString_End:
ret
;============================================================================
;Send Carriage Return and Line Feed to the serial port
;============================================================================
SendCRLF:
mov a, #0dh ; send CR
lcall Send
mov a, #0ah ; send LF
lcall Send
ret
;============================================================================
;Menu choices & addresses
;============================================================================
OptionList:
db "BDV", 0h
OptionTable:
dw SetBase
dw Download
dw Verify
;============================================================================
;Message strings
;============================================================================
WelcomeMessage:
db "MCS51 Hex File Download program", 0dh, 0ah, "Johan Bijker - Jun 2000", 0h
MenuMessage:
db "(B)ase, (D)ownload, (V)erify: ", 0h
InvalidMessage:
db " is invalid! ", 0h
BaseAskMessage:
db "Enter base address (4 hex bytes): ", 0h
DownloadMessage:
db "Downloading... ", 0h
DownloadOK:
db "Download completed!", 0h
DownloadErr:
db "Error in line ", 0h
VerifyMessage:
db "Enter size (4 hex bytes): ", 0h
DumpMessage:
db "(H)ex or (A)SCII? ", 0h
end ; End of HEX downloader
Choice equ 041h
CRC equ 042h
LineCount equ 043h
Counter equ 044h
Counter2 equ 045h
BaseH equ 046h ; Base address of SRAM
BaseL equ 047h
HexCount equ 048h ; 16 hex chars/line counter
Endflag equ 20h
Hexflag equ 21h
org 0000h
ljmp Main
org 0020h
Main:
lcall Init ; Initialise hardware
mov BaseH, #0E0h ; Set default base E000h
mov BaseL, #000h
mov dptr, #WelcomeMessage
lcall SendString ; Print welcome message
lcall SendCRLF
MenuLoop:
mov dptr, #MenuMessage
lcall SendString ; Show options
Wait:
jnb RI, Wait ; Wait until a char is received from serial port
lcall Receive ; Get char in accumulator
mov choice, a ; save choice
mov dptr, #OptionList ; Points to valid options string
lcall Position ; determine if char is a valid choice
jz Invalid
dec a ; 0 is first option
push acc
lcall SendCRLF
pop acc
lcall Branch ; Execute option
lcall SendCRLF
sjmp MenuLoop ; Start menu again
Invalid:
mov a, choice ; retreive choice
lcall Send ; send char back
mov dptr, #InvalidMessage
lcall SendString ; Show that choice is invalid
sjmp Wait ; Wait for a valid char
SetBase:
mov dptr, #BaseAskMessage
lcall SendString
lcall ReceiveHex
mov BaseH, a
lcall SendHex
lcall ReceiveHex
mov BaseL, a
lcall SendHex
lcall SendCRLF
ret
Download:
mov dptr, #DownloadMessage
lcall SendString ; Show message
mov LineCount, #0
clr EndFlag
StartLine:
inc LineCount
WaitColon:
lcall Receive
cjne A, #':', WaitColon
ProcessLine:
mov CRC, #0
lcall ReceiveHex
mov NumBytes, a
lcall ReceiveHex
add a, BaseH ; adjust for RAM mapping
mov dph, a
lcall ReceiveHex
add a, BaseL ; adjust for RAM mapping
mov dpl, a
jnc ContinueProcess
inc dph ; correct pointer
ContinueProcess:
lcall ReceiveHex
jz ReceiveData
setb EndFlag
mov NumBytes, #0
ReceiveData:
mov a, NumBytes
jz CheckSum
lcall ReceiveHex
movx @dptr, a
inc dptr
dec NumBytes
sjmp ReceiveData
CheckSum:
lcall ReceiveHex
mov a, CRC
jnz ChecksumError
jnb EndFlag, StartLine
ReceivedOK:
mov dptr, #DownloadOK
lcall SendString
lcall SendCRLF
lcall Receive ; Eat last byte
ret
CheckSumError:
mov dptr, #DownloadErr
lcall SendString
mov a, LineCount
lcall SendASCII
lcall SendCRLF
ret
ReceiveHex:
lcall Receive
lcall Hex2Num
mov B, #010h
mul AB
mov r7, a
lcall Receive
lcall Hex2Num
add a, r7
push acc
add a, CRC
mov CRC, a
pop acc
ret
Hex2Num:
clr c
subb A, #030h ; Convert 0-9
cjne A, #009h, AdjustNumber
ret
AdjustNumber:
jc EndConvert
subb A, #007h ; convert A-F
EndConvert:
ret
Verify:
mov hexcount, #10h
mov dptr, #VerifyMessage
lcall SendString ; Show message
lcall ReceiveHex ; Get size
mov Counter, a
lcall SendHex
lcall ReceiveHex
mov Counter2, a
lcall SendHex
lcall SendCRLF
mov dptr, #DumpMessage
lcall SendString
lcall Receive ; Hex or ASCII mode
clr HexFlag
cjne a, #'H', ASCIIDump
setb HexFlag ; Hex mode
ASCIIDump:
lcall SendCRLF
mov dph, BaseH
mov dpl, BaseL
VerifyByteLoop:
mov a, Counter2
jz Counter1Loop
dec Counter2
ajmp VerifyOutput
Counter1Loop:
mov a, Counter
jz VerifyEnd
dec Counter
mov Counter2, #0FFh
ajmp VerifyOutput
VerifyEnd:
ret
VerifyOutput:
movx a, @dptr ; read ram
jb HexFlag, VerifyHex
lcall Send ; send char
ajmp OutputEnd
VerifyHex:
lcall SendHex ; send char in HEX format
djnz HexCount, HexSpace
mov HexCount, #10h ; 16 chars / line
lcall SendCRLF
ajmp OutputEnd
HexSpace:
mov a, #' '
lcall Send
OutputEnd:
inc dptr
ajmp VerifyByteLoop
;============================================================================
;Hardware initialisation
;============================================================================
Init: ; Setup all hardware
mov ip, #00000010b ; Interrupt priority: T0,SER,T1,INT1,INT0
; effectivly T0,INT1 - others not used
mov tmod, #00100010b ; set timer 0 & 1 to 8-bit auto-reload mode
mov th1, #0fdh ; timer 1 reload value: 256-253=3
; 11.0592Mhz / 12 / 32 / 3 = 9600 baud
mov pcon, #10000000b ; double baudrate : 19.2k
mov scon, #01010000b ; 8-bit UART & enable reception
mov tcon, #01000000b ; run timer 1
mov ie, #00000000b ; Disable all interrupts
ret
;============================================================================
;3-way branching routine
; use r7
;============================================================================
Branch:
clr c
rlc a ; Multiply by 2 (2 bytes)
mov r7, a ; Save choice in r7
mov dptr, #OptionTable ; Point to base of table
inc a
movc a, @a+dptr ; Read MSB in acc
push acc
mov a, r7 ; Reload choice
movc a, @a+dptr ; Read LSB in acc
push acc
ret ; branch to address
;========================================================================
; Determine position of char (in acc) in a string pointed by DPTR.
; Position returned in accumulator, 1=first char, 0 = not found
; Use r6 & r7
;========================================================================
Position:
mov r7, a ; Store char in R7
mov r6, #0 ; set index to 0
Compare:
mov a, r6 ; load index
inc r6 ; increase index to next char
movc a, @a+dptr ; read in char
jz ExitPosition ; exit if at end of string
clr c ; clear carry for subtraction
subb a, r7 ; subtract char from acc
jnz Compare ; no match
mov a, r6 ; return with index in acc
ret
ExitPosition:
ret
;========================================
;Convert char in acc to uppercase
;========================================
UpperCase:
cjne a, #60h, Greatera ; Test if char >= 'a'
sjmp OtherChar ; char equal to 60h
Greatera:
jc OtherChar ; not >= 'a'
cjne a, #7Bh, Lessz ; test if char <= 'z'
sjmp OtherChar
Lessz:
jnc OtherChar ; not <= 'z'
clr c ; clear carry for subtraction
subb a, #20h ; convert to uppercase
OtherChar:
ret
;============================================================================
;Sends char in accumulator out the serial port
;============================================================================
Send:
clr TI ; Clear transmit interrupt flag
mov sbuf, a ; Put char in transmit buffer
SendSerialLoop:
jnb TI, SendSerialLoop ; Wait until char is transmitted
ret
;============================================================================
;Receives a char from the serial port and stores it in the accumulator
;============================================================================
Receive:
jnb RI, Receive ; Wait until char is received
mov a, sbuf ; Read char into accumulator
clr RI ; Clear receive interrupt flag
lcall Uppercase ; Convert char to uppercase
ret
;============================================================================
;Sends number in accumulator out the serial port in HEX format
; Use r7
;============================================================================
SendHex:
mov r7, a ; Save accumulator in R7
swap a ; Most significant 4 bits first
lcall Lookup_Send ; Send first hex digit
mov a, r7 ; Reload original value
lcall Lookup_Send ; Send second hex digit
ret
;============================================================================
;Sends number in accumulator out the serial port in ASCII format
; Use r6 & r7
;============================================================================
SendASCII:
mov r7, a ; Save accumulator in R7
mov b, #100d
div ab ; divide acc by 100
lcall Lookup_Send ; send first digit
mov b, #100d
mul ab ; value of byte send
mov r6, a ; store value in r6
mov a, r7 ; restore original value
clr c ; clear carry bit
subb a, r6 ; remaining value to send
mov r7, a ; save remaining value in r7
mov b, #10d
div ab ; divide acc by 10
lcall Lookup_Send ; send second digit
mov b, #10d
mul ab ; value of byte send
mov r6, a ; store value in r6
mov a, r7 ; restore original value
clr c ; clear carry bit
subb a, r6 ; remaining value to send
lcall Lookup_Send ; send last digit
ret
Lookup_Send: ; Convert a decimal/hex digit to ASCII
push acc ; save acc on stack
anl a, #00001111b ; Mask off 4 bits
add a, #0f6h ; overflow if digit > 9
jnc NoAdjust ; no overflow digit <= 9
add a, #07h ; Adjust for hex digits (A-F)
NoAdjust:
add a, #3ah ; Adjust for ASCII
lcall send ; Send char to serial port
pop acc ; reload acc from stack
ret
;============================================================================
;Sends a null-terminated string to the serial port. DPTR=Begin address
; - modifies a & dptr
;============================================================================
SendString:
clr a ; no offset from DPTR
movc a, @a+dptr ; input first char in acc
jz SendString_End ; null-termination
inc dptr ; point to next char
lcall Send ; send current char
sjmp SendString
SendString_End:
ret
;============================================================================
;Send Carriage Return and Line Feed to the serial port
;============================================================================
SendCRLF:
mov a, #0dh ; send CR
lcall Send
mov a, #0ah ; send LF
lcall Send
ret
;============================================================================
;Menu choices & addresses
;============================================================================
OptionList:
db "BDV", 0h
OptionTable:
dw SetBase
dw Download
dw Verify
;============================================================================
;Message strings
;============================================================================
WelcomeMessage:
db "MCS51 Hex File Download program", 0dh, 0ah, "Johan Bijker - Jun 2000", 0h
MenuMessage:
db "(B)ase, (D)ownload, (V)erify: ", 0h
InvalidMessage:
db " is invalid! ", 0h
BaseAskMessage:
db "Enter base address (4 hex bytes): ", 0h
DownloadMessage:
db "Downloading... ", 0h
DownloadOK:
db "Download completed!", 0h
DownloadErr:
db "Error in line ", 0h
VerifyMessage:
db "Enter size (4 hex bytes): ", 0h
DumpMessage:
db "(H)ex or (A)SCII? ", 0h
end ; End of HEX downloader
Comments