| CODE |
;Blair Lee ;John McDonald ;EE 476 Final Project ;RC Car - TRANSMITTER ;PORTA is used for speed control input. ;PORTB is used for pushbutton input. ;PORTC is used for steering control input. ;PORTD is used for serial output. .include "4414def.inc" .def savSREG =r16 ;save the status register .def TXbusy =r17 ;transmit busy flag .def TXflash =r18 ;text to be sent is in flash if <> 0 .def command =r19 ;command register .def temp =r20 ;general-purpose temporary register .def Volt =r21 ;ADC sample value .def Count =r22 ;a counter .def LEDReg =r23 ;register to store LED output (debug) .def debounce =r24 ;debounce ON or OFF .def DBcnt =r25 ;debounce counter .def status =r26 ;running and lights status .def release =r27 ;button release register .def temp2 =r28 ;another temporary register .equ baud96 =25 ;9600 baud constant for 4Mhz crystal .equ SpdMid =0x0c ;midpoint for fwd-back control .equ StrMid =0x0c ;midpoint for left-right control .equ FwdOffset=0xfd ;forward offset .equ RevOffset=0xfc ;reverse offset .equ LftOffset=0xfd ;left offset .equ RgtOffset=0xfd ;right offset .equ OFF =0x00 ;off .equ ON =0xff ;on .equ AADCDO =1;ADC data out .equ AADCCLK =2;ADC clock .equ AADCCS =3;ADC chip-select .equ AADCDI =4;ADC data in .equ CADCDO =1;ADC data out .equ CADCCLK =2;ADC clock .equ CADCCS =3;ADC chip-select .equ CADCDI =4;ADC data in .equ TOP =4 ;top hat switch .equ TRIG =5 ;trigger switch .equ SWmask =0x30 ;switch mask .equ Maxlights=0x04 ;nuumber of light modes .equ fwdcmd =0x00 ;forward prefix .equ bakcmd =0x10 ;backward prefix .equ lftcmd =0x20 ;left prefix .equ rgtcmd =0x30 ;right prefix .equ gocmd =0x40 ;lights prefix .equ stpcmd =0x50 ;other prefix .equ But1 =0x01; .equ But2 =0x02; .equ But3 =0x04; .equ But4 =0x08; .equ But5 =0x10; .equ But6 =0x20; .equ But7 =0x40; .equ But8 =0x80; ;======================================================== ; Toggle ADC Clock - PORTA ;ADC reads and outputs data on falling edge of the clock .MACRO A_CLOCKPULSE sbi PORTA, AADCCLK ;CLK high nop cbi PORTA, AADCCLK ;CLK low nop .ENDMACRO ;======================================================== ; Toggle ADC Clock - PORTC ;ADC reads and outputs data on falling edge of the clock .MACRO C_CLOCKPULSE sbi PORTC, CADCCLK ;CLK high nop cbi PORTC, CADCCLK ;CLK low nop .ENDMACRO ;======================================================== ;************************ .dseg ;define variable strings to be tranmitted from RAM cntstr: .byte 2 ;************************ .cseg .org $0000 rjmp Reset ;reset entry vector reti reti reti reti reti reti reti reti reti rjmp TXempty;UART buffer empty rjmp TXdone ;UART transmit done reti RESET: cli ldi temp, LOW(RAMEND);setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;initial conditions clr TXbusy ;start out not busy on TX ;setup UART -- enable TXempty & RXdone int, and RX, TX pins ldi temp, 0b00101000 out UCR, temp ;set baud rate to 9600 ldi temp, baud96 out UBRR, temp ;initialize ADCs on ports A and C ldi temp, 0b00011101 ;power ADC and set AADCCS out DDRA, temp ldi temp, 0b00001001 ;power ADC and set AADCCS out PORTA, temp ldi temp, 0b00011101 ;power ADC and set CADCCS out DDRC, temp ldi temp, 0b00001001 ;power ADC and set CADCCS out PORTC, temp ;set up leds on port B ldi temp, 0b00000011 ;input from switches on joystick out DDRB, temp out PORTB, temp ;debounce setup clr debounce ;debounce on or off clr DBcnt ;debounce counter clr status ;initialize car to off sei ;*********************Setup and Read Speed********************* Getspd: clr Volt ldi Count, 5 ;get top 5 bits A_CLOCKPULSE cbi PORTA, AADCCS ;initiate conversion A_CLOCKPULSE sbi PORTA, AADCDI ;startbit A_CLOCKPULSE sbi PORTA, AADCDI ;single ended A_CLOCKPULSE cbi PORTA, AADCDI ;channel 0 A_CLOCKPULSE ReadA: A_CLOCKPULSE clc ;clear carry sbic PINA, AADCDO sec ;set carry if high rol Volt dec Count brne ReadA ;more bits remaining ldi Count, 8 IgnoreA:A_CLOCKPULSE dec Count brne IgnoreA ;ignore lsb first data sbi PORTA, AADCCS ;conversion complete ;***********************Transmit Speed*********************** _bakCmd: cpi Volt, SpdMid brlt _fwdCmd cpi Volt, SpdMid breq _stpCmd lsr Volt subi Volt, RevOffset ori Volt, bakcmd mov command, Volt rjmp Sendspd _fwdCmd: ldi temp, SpdMid sub temp, Volt subi temp, FwdOffset ori temp, fwdcmd mov command, temp rjmp Sendspd _stpCmd: ldi command, 0x00 Sendspd: ; rcall LEDSt rcall SendMsg ;********************Setup and Read Steering******************** Getstr: clr Volt ldi Count, 5 ;get top 5 bits C_CLOCKPULSE cbi PORTC, CADCCS ;initiate conversion C_CLOCKPULSE sbi PORTC, CADCDI ;startbit C_CLOCKPULSE sbi PORTC, CADCDI ;single ended C_CLOCKPULSE cbi PORTC, CADCDI ;channel 0 C_CLOCKPULSE ReadC: C_CLOCKPULSE clc ;clear carry sbic PINC, CADCDO sec ;set carry if high rol Volt dec Count brne ReadC ;more bits remaining ldi Count, 8 IgnoreC:C_CLOCKPULSE dec Count brne IgnoreC ;ignore lsb first data sbi PORTC, CADCCS ;conversion complete ;***********************Transmit Steering*********************** _rgtCmd: cpi Volt, StrMid brlt _lftCmd cpi Volt, StrMid breq _ctrCmd lsr Volt subi Volt, RgtOffset ori Volt, rgtcmd mov command, Volt rjmp Sendstr _lftCmd: ldi temp, StrMid sub temp, Volt subi temp, LftOffset ori temp, lftcmd mov command, temp rjmp Sendstr _ctrCmd: ldi command, 0x00 ori command, rgtcmd Sendstr: ; rcall LEDSt rcall SendMsg ;***************************Get Status*************************** Getstat: cpi debounce, ON ;check if debounce is on breq _debounce in temp, PORTB cpi release, OFF ;check if buttons have been released breq _release ;buttons have been debounced and released sbic PINB, TRIG rjmp _trig _running: sbis PINB, TOP rjmp _status mov temp, status com temp andi temp, 0xf0 andi status, 0x0f or status, temp rjmp _status _trig: mov temp2, status andi temp2, 0x0f inc temp2 cpi temp, Maxlights brge _lightsoff rjmp _running _lightsoff: ori status, 0xf0 rjmp _running _debounce: inc DBcnt ;increment debounce counter breq _DBdone rjmp _release _DBdone: ldi debounce, OFF ;turn debounce off rjmp _release _release: ori temp, 0x30 brne _status ldi release, ON ;************************Transmit Status************************* _status: mov command, status ori command, 0xf0 breq _off _on: mov command, status ori command, 0x5f _off: mov command, status ori command, 0x4f rcall SendMsg rjmp GetSpd ;***************************Return******************************* ;****************** ;Pause procedure ;****************** ;_Wait: ; cli ;disable interrupts ; 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, 255 ; brne outerL ; sei ;here the outer loop is complete; approx. 1 ms has passed ; ret ;return from wait subroutine ;******************* ;message sending sub ;******************* SendMsg: ldi ZL, LOW(cntstr) ;ptr to RAM ldi ZH, HIGH(cntstr) inc ZL st Z, command ld r0,Z out UDR, r0 ;fire off the UART transmit clr TXflash ;the string is in RAM ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE ;enable the TXempty interrupt rcall TXwait ret ;****************** ;Debug procedure ;****************** LEDSt: mov LEDReg, command com LEDReg ;invert to send correct output to leds out PORTB, LEDReg ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;UART stuff follows. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; UART needs a character TXempty:in savSREG, SREG ;save processor status tst TXflash ;Is the string in flash memory? breq TXram ;If not, it is in RAM inc ZL ;get the next char from flash lpm ;and put it in r0 rjmp TXfls TXram: inc ZL ;get the next char from RAM ld r0,Z TXfls: tst r0 ;if char is zero then exit breq TXend out UDR, r0 ;otherwise transmit it rjmp TXexit ;exit until next char TXend: clr TXbusy ;no more chars cbi UCR, UDRIE ;clear the TXempty interrupt TXexit: out SREG, savSREG ;restore proc status reti ;back to pgm ; TX done -- buffer is empty -- unused here TXdone: in savSREG, SREG ;save processor status out SREG, savSREG ;restore proc status reti ;back to pgm ;***************************** ;subroutine TXwait: tst TXbusy ;now wait for the tranmission to finish brne TXwait ret |
| CODE |
;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 ;***************************** |