You are on page 1of 7

;Blair Lee

;John McDonald
;EE 476 Final Project
;RC Car - RECEIVER
.include "4414def.inc"
.def spdPulse=r16 ;speed pulse counter for PWM (0..16)
.def spdPW =r17 ;speed pulse width (0=stop, 15=full on)
.def strPulse=r18 ;steering pulse counter
.def strPW =r19 ;steering pulse width (14=left, 30=right)
.def savSREG =r20 ;save the status register
.def RXchar =r21 ;a received character
.def state =r22 ;state machine variable
.def Spdreg =r23 ;speed register (Forward, Reverse)
.def temp =r24 ;temporary register
.def temp2 =r25 ;another temporary register
.def running =r26 ;flag to denote running or not running status
.def timtemp =r27 ;timer temporary register
.def lights =r28 ;lights status register
.def temp3 =r29
.equ baud96 =25 ;9600 baud constant for 4Mhz crystal
.equ read =0
.equ fwd =1
.equ back =2
.equ left =3
.equ right =4
.equ go =5
.equ stop =6
.equ mask =0x0f
;command line prefixes, shifted right 5 bits
.equ fwdcmd =0x00 ;forward prefix
.equ bakcmd =0x01 ;backward prefix
.equ lftcmd =0x02 ;left prefix
.equ rgtcmd =0x03 ;right prefix
.equ gocmd =0x04 ;go prefix
.equ stpcmd =0x05 ;stop prefix
.equ Center =0x16
.equ MaxWidth =0x3f
.equ SpdOffset =0xfd
.equ OFF =0x00
.equ ON =0xff
.equ Forward =0x0f
.equ Reverse =0xf0
;mask values for "other" commands
.equ run_mask = 0x01 ;starts/stops car
;**************************************
.dseg
;define variable strings to be transmitted from RAM
cntstr: .byte 3 ;a two digit count + a zero terminate
;**************************************
.cseg
.org $0000
rjmp RESET ;reset entry vector
reti
reti
reti
reti
reti
rjmp Timer1 ;Timer1 overflow - speed control
rjmp Timer0 ;Timer0 overflow - steering control
reti
rjmp RXdone ;UART receive done
reti
reti
reti
; PORTA is for speed control
; PORTC is for steering control
; PORTB controls the lights
; PORTD is the serial receiver

;Timer0 speed and steering control interrupt


Timer0:
cli ;disable interrupts
inc strPulse ;increment the steering Pulse counter
brmi StrOff ;turn steering pulse off
cp strPulse, strPW ;compare strPulse to strPulseWidth
brge StrOff ;turn steering pulse off
tst strPulse ;check if counter is negative
brmi StrOff ;turn steering pulse off
ldi timtemp, ON
out PORTC, timtemp ;turn steering pulse on
sei ;enable interrupts
reti
StrOff:
ldi timtemp, OFF
out PORTC, timtemp ;turn steering pulse off
sei ;enable interrupts
reti

Timer1:
cli ;disable interrupts
inc spdPulse ;increment the speed Pulse counter
cp spdPulse, spdPW ;compare spdPulse counter to spdPW
brge ShutOff ;branch to motor shutoff
out PORTA, SpdReg ;turn motor on
sei ;enable interrupts
reti ;return from timer0 interrupt
ShutOff:
ldi timtemp, OFF
out PORTA, timtemp ;turn motor off
cpi spdPulse, MAXwidth ;compare spdPulse to MAXwidth
breq TimerReset ;branch to reset the timer
sei ;enable interrupts
reti ;return from timer0 interrupt
TimerReset:
ldi spdPulse, 0x00 ;reset spdPulse
out PORTA, SpdReg ;turn motor on
sei ;enable interrupts
reti ;return from timer0 interrupt

RESET:
cli
ldi temp, LOW(RAMEND) ;setup stack pointer
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
;initial conditions
ldi RXchar, go ;start out running
;setup UART -- enable TXempty & RXdone int, and RX, TX pins
ldi temp, 0b10010000
out UCR, temp
;set baud rate to 9600
ldi temp, baud96
out UBRR, temp
;enable Timer0 interrupts
ldi temp, 0b10000010 ;turn on timer0 interrupt only
out TIMSK, temp
ldi temp, 0x01 ;prescale timer to raw clock
out TCCR0, temp
ldi temp, 0x00
out TCCR1A, temp
ldi temp, 0b00000001
out TCCR1B, temp
;enable watchdog timer
ldi temp, 0x0e
out WDTCR, temp
;setup ports A and C to all output
ldi temp, ON
out DDRA, temp
out DDRC, temp
ldi temp, OFF
out PORTA, temp
out PORTC, temp
ldi temp, 0xff
out DDRB, temp
;initialize Speed
ldi spdPW, OFF
ldi spdPulse, OFF
;initialize Direction
ldi strPW, Center
ldi strPulse, OFF
ldi running, OFF
ldi state, read
sei
MainLoop:
cpi state, read
breq _read
cpi state, stop
breq _stop2
cpi state, go
breq _go2
cpi state, fwd
breq _fwd
cpi state, back
breq _back3
cpi state, left
breq _left3
cpi state, right
breq _right3
rjmp MainLoop
_read: mov temp, RXchar ;grab a byte from stream for analysis
mov temp2, temp ;don't want to clobber original temp
lsr temp2 ;now shift right 4 bits (bear with us...)
lsr temp2
lsr temp2
lsr temp2
cpi temp2, gocmd
breq _readgo
cpi temp2, stpcmd
breq _readstp
cpi running, ON ;check if input is to be used
breq _readchng
ldi state, stop
rjmp MainLoop ;if not running, ignore input
_readchng:
cpi temp2, fwdcmd
breq _readfd
cpi temp2, bakcmd
breq _readbk
cpi temp2, lftcmd
breq _readlt
cpi temp2, rgtcmd
breq _readrt
rjmp MainLoop
_readfd:
ldi state, fwd
rjmp MainLoop
_readbk:
ldi state, back
rjmp MainLoop
_readlt:
ldi state, left
rjmp MainLoop
_readrt:
ldi state, right
rjmp MainLoop
_readgo:
ldi state, go
rjmp MainLoop
_readstp:
ldi state, stop
rjmp MainLoop
_left3:
rjmp _left2
_right3:
rjmp _right2
_stop2:
rjmp _stop
_go2:
rjmp _go
_back3:
rjmp _back
_fwd:
; mov temp2, spdPW
; com temp2
; out PORTB, temp2
ldi temp2, mask ;set up mask for magnitude
and temp, temp2 ;extract magnitude
breq _fwdstop ;stop the motor
lsl temp ;scale the pulse width
lsl temp
cpi SpdReg, Reverse ;check if currently in reverse
breq _fwdwait
rjmp _fwd2
_fwdwait:
rcall wait ;wait for 1ms
_fwd2:
mov spdPW, temp ;load PulseWidth with the appropriate value
ldi SpdReg, Forward ;set current speed to forward
subi spdPW, SpdOffset;add speed offset
ldi state, read
rjmp MainLoop
_fwdstop:
ldi spdPW, OFF ;set pulse width to zero
ldi SpdReg, OFF ;set current speed to OFF
ldi state, read
rjmp MainLoop
_left2:
rjmp _left
_right2:
rjmp _right
_back:
; mov temp2, spdPW
; com temp2
; out PORTB, temp2
ldi temp2, mask
and temp, temp2 ;extract magnitude
lsl temp ;scale the pulse width
lsl temp
cpi SpdReg, Forward ;check if currently in forward
breq _backwait
rjmp _back2
_backwait:
rcall wait ;wait for 1ms
_back2:
ldi SpdReg, Reverse ;set current speed to reverse
mov spdPW, temp ;load PulseWidth with the appropriate value
subi spdPW, SpdOffset;add speed offset
ldi state, read
rjmp MainLoop
_left:
mov temp2, temp
com temp2
out PORTB, temp2
ldi temp2, mask
and temp, temp2
lsr temp ;shift right to get top 3 bits
ldi temp2, Center ;load Center steering position
sub temp2, temp ;subtract left steering offset
mov strPW, temp2 ;store steering PWM value
ldi state, read
rjmp MainLoop
_right:
mov temp2, temp
com temp2
out PORTB, temp2
ldi temp2, mask
and temp, temp2
lsr temp ;shift right to get top 3 bits
ldi temp2, Center ;load Center steering position
add temp2, temp ;add right steering offset
mov strPW, temp2 ;store steering PWM value
ldi state, read
rjmp MainLoop
_go:
ldi running, ON ;turn car on
mov lights, temp ;load new light settings
andi lights, 0x0f
ldi state, read
rjmp MainLoop
_stop:
ldi spdPW, OFF ;stop the car
ldi SpdReg, OFF ;set current speed to OFF
ldi strPW, Center ;center the steering
ldi lights, OFF ;turn lights off
ldi state, read
rjmp MainLoop

;wait before changing direction


wait:
cli ;disable interrupts
ldi temp2, OFF
out PORTA, temp2 ;turn motor off
clr temp2 ;clear upper 8 bits of counter
outerL:
clr temp3 ;clear lower 8 bits of counter
innerL:
inc temp3
cpi temp3, 0
brne innerL
inc temp2
cpi temp2, 16
brne outerL
sei ;here the outer loop is complete; approx.
1 ms has passed
ret ;return from wait subroutine
;*****************************
;interrupt routines
; UART read a character
RXdone: cli
wdr ;watchdog timer reset
in savSREG, SREG ;save processor status
in RXchar, UDR ;get the character
out SREG, savSREG ;restore proc status
sei
reti ;back to pgm
;*****************************

You might also like