Listing 1: Assembly Program for COP8 Ultrasonic Rangefinder Module ;-------------------------------------------------------------------------- ; soncop3.asm: This code performs the following operations: ; 1) Sets up Timer 1, Comparator 1, and UART. ; 2) Waits for address from host (UART receives character). ; 3) If address matches module's address, module sends acknowledge. ; 3) Pre-loads Timer 1 with 40000 (microseconds). ; 4) Transmits an ultrasonic (40KHz) pulse 250 microseconds long. ; 5) Begins input-capture on T1A. ; 6) Waits at least 40ms (to allow stray echoes to die down). ; 7) Scales input-capture time to distance in inches. ; 8) Sends the distance data byte out of the UART. ; ; ; I/O Usage: ;-------------------------------------------------------------------------- ; COP8SGR740 ; +----------------+ ; INIT---1--|C2 C1|--40--TXNEG ; X---2--|C3 C0|--39--TXPOS ; X---3--|G4/SO G3/T1A|--38--CMPOUT ; X---4--|G5/SK G2/T1B|--37--X ; X---5--|G6/SI G1/WDO|--36--X ; XTAL1---6--|G7/CKO G0/INT|--35--X ; XTAL2---7--|CKI RESET#|--34--VCC ; VCC---8--|VCC GND|--33--GND ; X---9--|F0 D7|--32--X ; REF--10--|F1/CMP1IN- D6|--31--X ; ECHO--11--|F2/CMP1IN+ D5|--30--X ; CMPOUT--12--|F3/CMP1OUT D4|--29--X ; X--13--|F4/CMP2IN- D3|--28--X ; X--14--|F5/CMP2IN+ D2|--27--X ; X--15--|F6/CMP2OUT D1|--26--X ; X--16--|F7 D0|--25--X ; X--17--|L0 L7/T3B|--24--X ; TENA--18--|L1 L6/T3A|--23--X ; TDATA--19--|L2 L5/T2B|--22--X ; RDATA--20--|L3 L4/T2A|--21--X ; +----------------+ ; ; ;-------------------------------------------------------------------------- .title soncop3 .incld cop8sgr.inc ; BASE_ADDR = 0x20 ; base address of module .sect dsect, ram RAW: .dsb 2 ; [0-1] RAWLO = RAW RAWHI = RAW + 1 TOT: .dsb 2 ; [2-3] TOTLO = TOT TOTHI = TOT + 1 RMD: .dsb 2 ; [4-5] RMDLO = RMD RMDHI = RMD + 1 .endsect .sect memcnt, reg CNTR: .dsb 1 .endsect .sect code, rom, abs=0 start: ld PORTCC, #07 ; C2-C0 = output C3 = input ld PORTCD, #02 ; C1(TXNEG)=high C2(INIT),C0(TXPOS)=low stcmp: sbit CMP1OUT, PORTFC ; CMP1OUT = output rbit CMP1INP, PORTFC ; CMP1IN- = input rbit CMP1INN, PORTFC ; CMP1IN+ = input sbit CMP1EN, CMPSL ; enable comparator 1 operation sbit CMP1OE, CMPSL ; enable comparator 1 output ld PORTFD, #00 ; all inputs Hi-Z sttim: rbit T1A, PORTGC ; T1A = input rbit T1A, PORTGD ; T1A = Hi-Z sturt: sbit 1, PORTLC ; enable L1 as output for TXE sbit ETDX, ENUI ; enable uart TDX operation sbit TDX, PORTLC ; enable uart TDX output sbit CHL1, ENU ; enable 9-bit data mode ld PSR, #060 ; load prescaler with 6.5 ld BAUD, #09 ; load divisor with N-1 = 10-1 = 9 ; for CKI=10MHz, this yields 9600bps. waitaddr: ifbit RBFL, ENU ; if char was received jp checkaddr1 ; then check for address jp waitaddr ; else wait here checkaddr1: x A, RBUF ; get char from RBUF (clears RBFL) ifbit RBIT9, ENUR ; if 9th bit = 1 jp checkaddr2 ; then check for correct address jp waitaddr ; else wait for next char checkaddr2: ifne A, #BASE_ADDR ; if addr doesn't match jp waitaddr ; wait for another address checktbmt1: ifbit TBMT, ENU ; if transmit buffer is empty jp sendack ; then go ahead and send acknowledgment jp checktbmt1 ; else wait sendack: sbit 1, PORTLD ; TXE=1 nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay x A, TBUF ; and send acknowledgement nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay checktbmt2: ifbit TBMT, ENU ; if transmit buffer is empty jp waitxmtg1 ; then check XMTG flag jp checktbmt2 ; else wait waitxmtg1: ifbit XMTG, ENUR ; if still transmitting acknowledgment jp waitxmtg1 ; then wait here nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay rbit 1, PORTLD ; else TXE=0 nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay ldtim: ; load T1 with 40000 cycles (=40ms) ld TMR1LO, #040 ; load T1 lower byte with 40h ld TMR1HI, #09C ; load T1 upper byte with 9Ch stim: ld PSW, #00 ; disable interrupts ld CNTRL, #040 ; configure T1 for input capture mode, positive T1A ; Transmit for 250us. ; ld B, #0a ; B=10 tx_pulse: ld PORTCD, #05 ; TXPOS,INIT=high, TXNEG=low (3 cycles) nop nop nop nop nop nop nop nop nop ld PORTCD, #06 ; TXNEG,INIT=high, TXPOS=low (3 cycles) nop nop nop nop drsz B ; repeat until B=0 (3 cycles) jp tx_pulse ; (3 cycles) rbit #2, PORTCD ; INIT=low waitcap: ifbit T1PNDA, PSW ; if capture occurred jp stocap ; then go store capture value ifbit T1C0, CNTRL ; else if underflow occurred jp stoerr ; then go store error value jp waitcap ; else keep waiting stoerr: rbit T1C0, CNTRL ; reset T1C0 to disable counting rbit T1PNDA, PSW ; reset T1PNDA just in case ld A, #0EE ; load A with EE x A, TOTLO ; save value in TOTLO ld A, #0EE ; load A with EE x A, TOTHI ; save value in TOTHI jp testerr ; send it out stocap: ld A, T1RALO ; read T1RA low byte x A, RAWLO ; save value in RAWLO ld A, T1RAHI ; read T1RA high byte x A, RAWHI ; save value in RAWHI waitund: ifbit T1C0, CNTRL ; if 40ms is finished jp tmrdone ; then send out value jp waitund ; else wait for underflow tmrdone: rbit T1C0, CNTRL ; reset T1C0 to disable counting rbit T1PNDA, PSW ; reset T1PNDA for next time subtrct: ld A, #040 ; A = LSB of 40000 x A, TOTLO ; TOTLO = LSB of 40000 ld A, #09C ; A = MSB of 40000 x A, TOTHI ; TOTHI = MSB of 40000 sc ; set carry (clear borrow) ld X, #RAWLO ; set X ptr to address of RAWLO ld B, #TOTLO ; set B ptr to address of TOTLO subloop: ld A, [X+] ; load A with subtrahend (RAWLO) x A, [B] ; exchange subc A, [B] ; A = TOTLO - RAWLO x A, [B+] ; exchange ifbne #4 ; if B ptr != end of TOT jp subloop ; then repeat div: ld A, #094 ; A = LSB of 148 x A, RAWLO ; RAWLO = LSB of 148 ld A, #00 ; A = MSB of 148 x A, RAWHI ; RAWHI = MSB of 148 ld CNTR, #16 ; no leading zero means decimal ; division routine to scale time into inches ; distance (inches) = time (microseconds) / 148 (microseconds/inch) ; ; This routine is taken from the COP8 Feature Family User's Manual, ; page B-26. ; ld B, #5 ld [B-], #0 ld [B], #0 ld X, #4 lshft: rc ld B, #2 ld A, [B] adc A, [B] x A, [B+] ld A, [B] adc A, [B] x A, [B+] ld A, [B] adc A, [B] x A, [B+] ld A, [B] adc A, [B] x A, [B+] tsubt: sc ld B, #0 ld A, [X+] subc A, [B] ld B, #1 ld A, [X-] subc A, [B] ifnc jp test subt: ld B, #0 ld A, [X] subc A, [B] x A, [X+] ld B, #1 ld A, [X] subc A, [B] x A, [X-] ld B, #2 sbit 0, [B] test: drsz CNTR jmp lshft ; Time to write out value to UART. ; First check for measurement out-of-range (if one byte won't hold ; entire distance). ; testerr: ld A, TOTHI ; load MSB of TOT into A ifne A, #00 ; if MSB is not zero jp outrange ; then send out-of-range code out ld A, TOTLO ; else send LSB of TOT out jp checktbmt3 ; and jump to transmit outrange: ld A, #0FF ; A = out-of-range code checktbmt3: ifbit TBMT, ENU ; if transmit buffer is empty jp tdxnow ; then go ahead and send value out jp checktbmt3 ; else wait tdxnow: nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay sbit 1, PORTLD ; TXE=1 nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay x A, TBUF ; and send distance checktbmt4: ifbit TBMT, ENU ; if transmit buffer is empty jp waitxmtg2 ; then check for XMTG flag jp checktbmt4 ; else wait waitxmtg2: ifbit XMTG, ENUR ; if still transmitting distance jp waitxmtg2 ; then wait here nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay rbit 1, PORTLD ; else TXE=0 nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay nop ; 1usec delay jp waitaddr ; go back to idle .endsect .end start