Top Topics

74*245 Motor Driver

H-Bridge Driver

Simple PWM Gen.

Handy Method Measuring RPM

Measuring RPM via Photo reflector

Introduction to Robotic

DC, Stepper,and Servo Motor

Related Link

Microcontroller Tutorial

Computer Interface
Tutorial

.............more links

 

 

 

BACK

Program Source Code

The following is a complete listing of the most recent version of the program code used to control the robot. The program comments in the header describe the robots behavior with this code.


;------------------------------------------------------------------
;
; FIRE FIGHTING ROBOT PROGRAM
; by Jason Plumb, Brent Short, and John Walter
; EE3333 - Project Lab 3
; Spring 1998
;
; 3/24 Goes to every room and looks for the candle. If the candle
; is present, it will go toward it and look for the circle. When it
; reaches the circle it will turn the fan on and blow out the candle.
; It will not exit back out of the house once it blows out the candle...
; it will just sit there.
;
; 3/28 - This code has been reduced in size
; * FWD, BK, and STOP have been replaced with hard coded values
; * fwd_motors and bk_motors routines have been implemented
;
; 3/31 - This is the reduced code with modulation added in.
; Specifically, it uses PWM for the LED switch and the logic
; has been reversed
;
; 4/3 - Candle threshold is set for using flashlight reflector
; 4/4 - This has step count added back in and has been modified
; so that the robot will detect the candle circle if it is
; < 12" from the door
; * This code has been modified so that the robot aligns properly
; when entering the rooms. This is done in the go_in routine
; Note: This code needs serious reduction - it fills almost
; all available byte erasable eeprom
; 4/9 - won't hit wall if candle is close -makes sure it has
; gone a certain distance
;------------------------------------------------------------------
; Begin program equates here
;------------------------------------------------------------------
RAMSTART: equ $0800 ; Start of RAM for the HC12
PROGSTART equ $0D00 ; Start of program in jump EEPROM
PORTA: equ $0000 ; Address of port a on hc12
DDRA: equ $0002 ; Data direction register for port A
PORTB: equ $0001 ; Address of port b on hc12
DDRB: equ $0003 ; Data direction register for port B
PORTE: equ $0008 ; Address of port e on hc12
DDRE: equ $0009 ; Data direction register for port E
ATDSTAT: equ $0066

ADR0H: equ $70 ;A/D Converter Result Register 0
ADR1H: equ $72 ;A/D Converter Result Register 1
ADR2H: equ $74 ;A/D Converter Result Register 2
ADR3H: equ $76 ;A/D Converter Result Register 3
ADR4H: equ $78 ;A/D Converter Result Register 4
ADR5H: equ $7A ;A/D Converter Result Register 5
ADR6H: equ $7C ;A/D Converter Result Register 6
ADR7H: equ $7E ;A/D Converter Result Register 7

RAMSTRT: EQU $0800 ; start of internal ram
RAMSIZE: EQU $0400 ; Size of internal ram
STACK: EQU RAMSTRT+RAMSIZE ; top of stack

ATDCTL2: equ $0062
ATDCTL3: equ $0063
ATDCTL4: equ $0064
ATDCTL5: equ $0065
ATDSTATH: equ $66 ;ATD Status Register High
ATDSTATL: equ $67 ;ATD Status Register Low

COPCTL: equ $16 ;COP Control Register
COPRST: equ $17 ;Arm/Reset COP Timer register

PWEN: equ $0042 ; PWM enable register
PWPER0: equ $004C ; PWM period channel for channel 0
PWCLK: equ $0040 ; PWM clocks and concatenate (used to concat ch0 and ch1)
PWDTY0: equ $0050 ; PWM duty cycle for channel 1

;----------------------------------------------------------------------
; Begin data segment
;----------------------------------------------------------------------
org RAMSTART
temp db $00
tempfw dw $00
tempw dw $00
NUM_STEP90 db $87
speed dw $05FF
led_speed dw $0000
sensor_diff db $0
rtmtr db $58,$3D
ltmtr db $58,$3D
;FWD db $58
;BK db $54
;STOP db $a7

; RAM variables used for holding sensor readings begin here
s0loff db $FF
s1loff db $FF
s2loff db $FF
s3loff db $FF
s4loff db $FF
s5loff db $FF
s6loff db $FF
s7loff db $FF

s0lon db $FF
s1lon db $FF
s2lon db $FF
s3lon db $FF
s4lon db $FF
s5lon db $FF
s6lon db $FF
s7lon db $FF

s1_close_thresh dw $0050
s2_close_thresh db $FF
s3_close_thresh db $FF
s5_close_thresh db $FF
s6_close_thresh db $FF
s2_far_thresh db $FF
s3_far_thresh db $FF
s5_far_thresh db $FF
s6_far_thresh db $FF
s2_center_thresh db $FF
s3_center_thresh db $FF
s5_center_thresh db $FF
s6_center_thresh db $FF

wall_status db $00
pwall_status db $00
abs_thresh db $00 ; The absolute threshold for any given sensor
exist_thresh db $18

sens_addr dw $0072 ; Parameter to follow_wall function
sens_far_thresh db $00
sens_close_thresh db $00
follow_wall db $00 ;0=right, not zero = left
low_step dw $00 ;step count for lowest candle value
low_value db $00 ;lowest candle value - init to $FF
old_y dw $00
old_x dw $00 ; Artificial stack vars
abovect db $00
extinguished db $00
stepct db $00
old_rt db $00
in_circle db $00
;----------------------------------------------------------------------
; Begin main program
;----------------------------------------------------------------------
org PROGSTART
;----------------------------------------------------------------------
; Initialization stuff here:
;----------------------------------------------------------------------
INIT_STUFF:
ldaa #$0
staa COPCTL ; Disable the COP watchdog timer
staa ATDCTL3
staa extinguished
staa stepct
staa in_circle
ldaa #$FF
staa DDRB ; Set direction for port B (all output)
staa PORTB ; Write initial PORT B value (unlock mot)
movb #%11101101, DDRA ; Set direction for A (outputs)
;ldaa ;PORTA
ldaa #%00001101 ; Ensure that calibration LED and IR LEDs on and Fan is off
staa PORTA ; Put byte back on port A

movb #$80, ATDCTL2 ; Set up ATD to function normally

;movb #$00, ATDCTL3 ; Select continue conversion in BGND Mode
; Ignore FREEZE in ATDCTL3
movb #$01, ATDCTL4 ; Select Final Sample time = 2 A/D clocks
; Prescaler = Div by 4 (PRS4:0 = 1)
;The next x lines set up RAM variables during init...
;that way, they aren't lost when we power down.
;(not used, hard coded)movb #$81, NUM_STEP90
;(speed is hard coded in the delay routine)
;movw #$1700, speed ; #$1D10, speed ; Speed variable
ldd #$003D
std rtmtr
std ltmtr
;movw #$003D, rtmtr
;movw #$003D, ltmtr

;movb #$40, s1_close_thresh ; Just hard coded for now
;movw #$01F6, steps_360 ; (was 1f8) (was 200)
;movb #$55, candle_thresh

; The next 4 lines set up and start PWM for modulating IR LEDs
movb #$40, PWCLK ; Concat channels 0 and 1
movb #$03, PWEN ; Enable PWM
movb #$1F, PWPER0 ; Set channel 0 period
movb #$10, PWDTY0 ; Set channel 0 duty cycle
;movb #$00, stepct

;jsr INIT_STUFF ; Do initialization stuff
;----------------------------------------------------------------------
;end init
;----------------------------------------------------------------------
jsr WaitForTone ; Actually, wait for button

jsr Read
ldaa ADR6H ; Get right wall calibration value
ldab ADR2H
addd #$0A0A ; Add for close threshold (due to modulatioN)
staa s6_close_thresh ; Calculate and store thresholds
stab s2_close_thresh
subd #$1414
staa s6_far_thresh
stab s2_far_thresh

jsr wait_toggle ; Should turn it back on
jsr WaitForTone ; tone or button
movb #%00110011, PORTB ; Write initial value to port B
basic: ;
ldy #$00FF
jsr fwdabit
movb #$FF, follow_wall ;left wall
jsr Follow

jsr RoomL ; First room (island)

jsr right_90
movb #$00, follow_wall ;right wall

jsr Follow

jsr RoomR ; Second room
jsr right_90
jsr Follow
jsr RoomR ; Third room
jsr right_90
jsr Follow
jsr RoomR ; Fourth (last) room
jsr left_90

ldaa #$FF
staa count_steps

ldaa #$FF
staa follow_wall ; Follow left wall out of house
staa done
jsr Follow
jsr Room
jsr right_90
ldy #$00DA
jsr fwdabit
jsr Follow
quit: movb #%11111111, PORTB
stop: bra stop

;----------------------------------------------------------------------
; This will wait for the tone to be present for a given period of time
; before continuing. If the button is pressed, it will also exit
;----------------------------------------------------------------------
WaitForTone:
;stx old_x
ldx #$3000
Tone2: ldaa PORTA
bita #%00000010 ; Check for button
bne ToneExit
bita #%00010000
beq TonePres ; The tone is present
bra WaitForTone
TonePres: dex
beq ToneExit
bra Tone2
ToneExit:; ldx old_x ; Artificial stack
;----------------------------------------------------------------------
; This will toggle the status of the calibration LED
;----------------------------------------------------------------------
ToggleCLED:
ldaa PORTA
eora #%00000100
staa PORTA
;ldy old_y ; Artificial stack
rts
;----------------------------------------------------------------------
;wait $100 delay cycles - used for calib. LED - then go on to toggle
;----------------------------------------------------------------------
wait_toggle:
;sty old_y ; Artificial stack
ldy #$0100
wtlp1: jsr DELAY ; Wait before turning LED back on
dey
bne wtlp1
bra ToggleCLED
;----------------------------------------------------------------------
Read: movb #%01010100 , ATDCTL5 ; Initializes ATD, MULT=1 (do conversions on AN0-AN7)
; Run conversions on subsequent channels
WTCONV: BRCLR ATDSTATH,#$80,WTCONV ; Wait for Sequence Complete Flag
rts
;-----------------------------------------------------
; This will follow the right or left wall until the floor
; sensor is detected
;-----------------------------------------------------
Follow:
ldaa stepct ; Used to go fwd every 3rd step
cmpa #$03 ; If A is not equal to 3
bne Follow_1 ; Then jump to follow1
movb #$00, stepct ; Otherwise, reset stepct
bra Follow2 ; And jumpt to follow2 (go 1 step fwd)
Follow_1:
inca ; Increment A
staa stepct

jsr Read
ldaa ADR0H ;floor sensor
cmpa #$80
bhi no_line
jmp left_motor
no_line:
ldaa ADR3H ; Get value of front sensor (1 = 3 temp)
cmpa #$50 ; was 70 ; Compare to close threshold
blo Follow1a ; If we didnt' "hit" a front wall, branch
jsr right_90
bra Follow
Follow1a:
ldaa follow_wall ; 0 for right wall, 1 for left
beq wall_right ; If zero, follow right wall
ldab ADR2H ; Otherwise, get left sensor value
cmpb s2_far_thresh ; Compare to the far threshold
bhi not_too_far ; If we're higher than far thresh, we're ok so far
bra foll_1bC
not_too_far: ; Not too far from left wall
cmpb s2_close_thresh ; Compare to the left close threshold
blo Follow2 ; If lower than close thresh, just go fwd
bra wall_rtC
wall_right: ; If here, we're following right wall
ldab ADR6H ; Get front right sensor value
cmpb s6_far_thresh ; Compare it with far thresh
bhi Follow1b ; If higher, we're ok
wall_rtC: jsr left_motor ; Otherwise, turn in one step
bra Follow
Follow1b:
cmpb s6_close_thresh ; Compare sensor value to close threshold
blo Follow2 ; If higher, we're aligned and can go fwd
foll_1bC:
jsr right_motor ; Otherwise, we need to turn away
bra Follow
Follow2:
jsr fwd_motors ; Set up motor directions for both fwd
jsr GO ; Go forward 1 step
bra Follow ; Keep following
;----------------------------------------------------------------------
; This will set the directions of the motors to pivot left
;----------------------------------------------------------------------
piv_left_motors:
movb #$58, rtmtr
movb #$54, ltmtr
rts
;----------------------------------------------------------------------
; This will set the directions of the motors to pivot right
;----------------------------------------------------------------------
piv_right_motors:
movb #$54, rtmtr
movb #$58, ltmtr
rts
;----------------------------------------------------------------------
; This will set the directions of both motors to fwd
;----------------------------------------------------------------------
fwd_motors:
ldaa #$58
staa rtmtr
staa ltmtr
rts
;----------------------------------------------------------------------
; This will set the directions of both motors to bk
;----------------------------------------------------------------------
bk_motors:
ldaa #$54
staa rtmtr
staa ltmtr
rts
;----------------------------------------------------------------------
; This will move just the right motor forward. Used in turning
;----------------------------------------------------------------------
right_motor:
movb #$58, rtmtr
movb #$a7, ltmtr
bra lmgo
;----------------------------------------------------------------------
; This will move just the left motor forward. Used in turning
;----------------------------------------------------------------------
left_motor:
movb #$58, ltmtr
movb #$a7, rtmtr
lmgo: jmp GO
;rts
;----------------------------------------------------------------------
; This will turn the car 90 degrees left or right
;----------------------------------------------------------------------
left_90: jsr piv_left_motors
;movb #$58, rtmtr
;movb #$54, ltmtr
bra all_set
right_90: jsr piv_right_motors
;movb #$54, rtmtr
;movb #$58, ltmtr
all_set: ldy #$0081 ; Load Y with # of steps in 90 deg (NUM_STEP90)
loop_90: jsr GO
dey
bne loop_90
rts
;----------------------------------------------------------------------
; Goes forward or backward a bit depending on the value passed in Y
;----------------------------------------------------------------------
;bakabit: jsr bk_motors
; bra bakabl
fwdabit: jsr fwd_motors
bakabl: jsr GO
dey
bne bakabl
rts
;----------------------------------------------------------------------
;Room Routine - This is what the robot does when it enters the room
;----------------------------------------------------------------------
RoomL: jsr right_motor
bra into
RoomR: jsr left_motor
bra into
Room: jsr fwd_motors
into: movb #$00, PWEN ; Disable PWM (turn off IR LEDs)

rm1: ;jsr go_in ; Go into the room
;------------------------------------------------------------------
; go_in will move the robot into the room from the doorway
; It will exit out when it goes 12 inches or detects the candle
; circle on the floor
;------------------------------------------------------------------
go_in:
ldaa rtmtr
staa old_rt ; Preserve the original rt mot direction
go_o_line:
ldaa old_rt
cmpa #$58
bne go_o_lineL
jsr right_motor
bra go_o_line1
go_o_lineL:
jsr left_motor
go_o_line1:
jsr GO
jsr fwd_motors
jsr GO
jsr Read ; Read sensors
ldaa ADR0H ; Get floor sensor
cmpa #$80 ; Compare with the floor threshold
blo go_o_line ; Keep going fwd until line disappears
ldaa extinguished ; Not used (yet)
beq look
jmp leave

look: ldy #$00DA ; Should be 12 inches
; jsr fwd_motors ; Set motor direction to fwd
go_in_al: jsr GO ; Go fwd 1 step
jsr Read ; Read sensors
ldaa ADR0H ; Get floor sensor
cmpa #$80 ; Compare with line
blo go_bail ; If line found, we need to bail
dey
bne go_in_al
bra turn
go_bail:
ldaa #$FF
staa in_circle
jsr GO
dey
cpy #$0050
bhi go_bail

;ldy #$006C
;jsr fwdabit
;rts

turn: movb #$FF, low_value ; Init strongest candle reading (lowest #)
jsr piv_left_motors ; Set up motor directions for a left pivot
ldy #$01F6 ; Y gets number of steps in a 360 deg turn
T360: jsr Read ; Read sensor values
ldaa ADR7H ; Get candle sensor value
cmpa low_value ; compare with the low_value
bhi not_stronger ; If higher, skip
staa low_value ; Otherwise, store as new low value
sty low_step ; Store Y into the low_step count var
not_stronger:
jsr GO ; Do one step CCW
dey ; Decrement step counter
bne T360 ; If we haven't done a 360, keep going
; If here, we've done a whole 360
ldaa low_value ; Otherwise, get the lowest value
cmpa #$55 ; Compare to candle threshold
bhi leave ; If higher, then candle not in room
jsr piv_right_motors ; Set up motor directions for a right pivot
ldy low_step
ldab #$0C
aby ; Add $0C to Y to "fix" turn
turn_back:
jsr GO
dey
bne turn_back
jsr fwd_motors
ldx #$0000
FoundIt:
ldaa in_circle
bne fan_on
inx
jsr GO ; Step forward one step
jsr Read ; Read sensors
ldaa ADR0H ; Check floor sensor
cmpa #$80 ; Compare with threshold
bhi FoundIt ; If higher, need to keep going fwd
fan_on: ldaa PORTA ; If we're here, we hit candle circle
anda #%11110111 ; Make fan turn on (reverse logic)
staa PORTA
jsr wait_toggle ; Keep fan on for ~ 1/2 sec
ldaa PORTA
oraa #%00001000
staa PORTA ; Turn fan back off
staa extinguished ; a != 0
jsr bk_motors
inx
back: jsr GO
dex
bne back
jsr piv_left_motors
ldy low_step
straight:
jsr GO
dey
bne straight

;jmp quit
leave:
movb #$03, PWEN ; Turn IR LEDs on before backing to wall
;jmp Back_to_wall
;rts
;----------------------------------------------------------------------
;backs until it sees a wall
;----------------------------------------------------------------------
Back_to_wall:
jsr bk_motors ; Set up motor directions for backward
no_wall: jsr GO
jsr Read
ldaa ADR4H
cmpa #$70
blo no_wall
rts
;----------------------------------------------------------------------
; This routine moves both motors one step
; The current state of the motor does not matter
;----------------------------------------------------------------------
GO: clc ; clear carry bit
ldab PORTB ; read the current motor byte
andb #%11110000 ; Mask off right stepper bits
jsr rtmtr ; carry out shift
bcc NEXT1 ; If we didn't carry, skip to NEXT1
orab #%00010000 ; If we carried, set LSB of this nibble
NEXT1: bitb #%00001000 ; check if we overflowed right
beq NEXT3 ; if not, branch
eorb #%10001000 ; if so, fix it
NEXT3: stab temp ; store right motor nibble in temp
clc ; clear carry
ldab PORTB ; read the current motor byte
andb #%00001111 ; Mask off left stepper bits
jsr ltmtr ; carry out shift
bcc NEXT4 ; if didn't carry, skip to NEXT4
orab #%00001000 ; if carried, fix it
NEXT4: bitb #%00010000 ; check if overflowed left
beq NEXT2 ; if not, branch
eorb #%00010001 ; if so, fix it
NEXT2: orab temp ; combine the two motor nibbles
stab PORTB ; send out to motor driver
jsr DELAY
rts

;----------------------------------------------------------------------
; This delay routine is used for delaying between steps
;----------------------------------------------------------------------
DELAY: xgdx ;(exchange X and D to save X) stx old_x
ldx #$1200 ; Load X with speed var (used for delaying)
dloop: dex ; Decrement X
cpx #$0000 ; If X != 0
bne dloop ; Loop again
xgdx ;(exchange X and D to save X) ldx old_x ; Fake stack
eof: rts

BACK