ULTRASONIC TEST PROGRAM

Ultrasonic Test Program for Ultrasonic Board MkIII (PIC16F628)

This code requires the code I2C Test Program for Mainboard (PIC16F876)

This code requires a digital scope and In Circuit Debugger (on Mainboard) to verify function. I used a PC scope and the Microchip MPLAB ICD2 In Circuit Debugger. I will program another piece of code later for the Mainboard to give a visual indication of functionality.

The code is too complex to explain in detail so instead here is a brief description of what it does.

Mainboard:

When the switch is pressed on the Mainboard a command is sent over the I2C to tell the Ultrasonic board to begin a scan.
One second later a command is sent over the I2C for the Ultrasonic board to send it's data (1 second is far too long 10 mS would do).
The data is put into the RXBuf (Receive Buffer) this can be checked with the ICD (In Circuit Debugger)

Ultrasonic Board:

When the Begin Scan command is received the PIC16F628 outputs 10 pulses at 40KHz on the left ultrasonic output.
It then listens to the return signal for an echo on the 628's internal comparator.
This echo is timed from the time the signal leaves the transmitter until it returns to the receiver. Note this is twice the distance measured.
If no echo is received by 2.92mS (Approx 0.5 metres) a value of 255 decimal is recorded.

This operation is then repeated for the right ultrasonic output.

When both channels are done the the data is sent over the I2C when a Send Data command is received from the mainboard. Data is sent left channel first the right channel.

Test results are after the code.

 

The Code:

 

	list p=pic16f628
#include "P16f628.inc"
#include "P16fxxx.mac"
#define us_OutR		PORTB,3
#define us_OutL		PORTB,0
#define LED		PORTB, 5
#define SCL		PORTB, 2
#define SDA		PORTB, 1
#define flag_USL 	flags0,0
#define flag_USR 	flags0,1
#define	flag_Start  	flags0,2
#define	flag_Clock	flags0,3
#define USEchoL		CMCON,C1OUT
#define USEchoR		CMCON,C2OUT
	cblock 0x20
	flags0, RXData, TXData, cnt
	I_wtemp, I_stattemp, I_temp			;interupt temp vars
	count, timeout, pgtime
	temp, cntL, cntR
	DelayF2, DelayF1, DelayF, SDelayF1, SDelayF	;delay routine vars
	endc
	ORG	0x0000
	nop				;required for debug 
	goto	Start
	org 	0x0004			;Interupt vector
	goto	Interupt
	
;+++++++++++++++++++++++++++++++++++++++++++++++++++
;+++++++++++++++++++++++++++++++++++++++++++++++++++
	
Start
	clrf	PORTA			;Init I/O
	clrf	PORTB
	bsf	STATUS, RP0
	bcf	STATUS, RP1
	movlw 	b'11100111' 		;PortA	Set all as inputs
	movwf 	TRISA 			;			
	movlw 	b'11010110' 		;PortB	Set RB<7:6:4:2:1> as inputs
	movwf 	TRISB 			;		and set RB<5:3:0> as outputs	
	bcf	OPTION_REG, T0CS;	;Timer0 source=machine clock
	bsf	OPTION_REG, PSA		;no prescaler on timer0
	bcf	STATUS, RP0
	movlw	.184			;255-73 (time 1")+2 cyc lost writing Timer0
					;speed of sound is 340.29m/S or 73.4uS/25mm
	movwf	TMR0
	bsf		INTCON, T0IE	;enable timer0 interupt
;	bsf		INTCON, GIE
	movlw	b'00000110'		;Setup Comp Register
	movwf	CMCON			;C2, C1 to output(C1=RA3, C2=RA4[open drain])
	bcf		flag_Clock
	bcf		flag_Start
	bcf		LED	
;+++++++++++++++++++++++++++++++++++++++++++++++++++
Main
	bcf	INTCON, GIE		;disable interrupts
	call	WaitDatHL		;wait for start condition
	btfss	SCL
	goto	Main			;if clock low goto Main
Start_condition_found
	call	WaitClkHL	;Wait for clock transition high to low
	call	GetByte		;get device address
	cfl_je	RXData, h'02', RecieveData	;if address =h'02' that's us goto recieve data	
	cfl_je	RXData, h'82', SendData		;if address =h'02' that's us goto send data	
	bcf		LED
	call	SetDataIn
	goto	Main
SendData			;address true so send data (2 Bytes)
	bsf	LED
;	movlw	b'10001000'	;byte to send
	movfw	cntL
	movwf	TXData		;put into transmit register
	call	PutByte		;send data
;	movlw	b'10101010'	;byte to send
	movfw	cntR
	movwf	TXData		;put into transmit register
	call	PutByte		;send data
Done
	call	SetDataIn	;set data port for input	release I2C port
	bcf	LED
	goto	Main
RecieveData			;address true so recieve data (1 byte)
	bsf	LED
	call	GetByte		;recieve data
	cfl_je	RXData, h'01', GetUltraSonic	;if command word 01h then check ultrasonic
	goto	Done
GetUltraSonic
	call	SetDataIn	;set data port for input	release I2C port
	bcf	LED
;	bsf	INTCON, GIE	;enable interrupts
		;ultrasonic here
;+++++++++++++++++++++++++++++++++++++++++++++++++++
Main1
	bcf	flag_USL	;set if bounce registered
	bcf	flag_USR
	bcf	INTCON, GIE	;disable interrupts
	movlw	.10
	movwf	pgtime
	clrf	count		;clear main counter inc. in IRQ
	
;+++++++++++++++++++++++++++++++++++++++++++++++++++	
PingLoopL
	bcf	us_OutL		;Must be kept as is due to
	nop			;critical timing 
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	bsf	us_OutL			;Square wave 
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	decfsz	pgtime, f
	goto	PingLoopL
;+++++++++++++++++++++++++++++++++++++++++++++++++++	
	bsf	INTCON, GIE	;enable interrupts
	movlw	.40
	movwf	timeout		;timeout aprox. 40" (3.3 Feet, 1m)/2
PMLoopUSL
	movlw	.19		;4 cycles to loop 4x19=76 
	movwf	temp	
PMLoopL
	btfss	USEchoL		;Look for echo 
	goto	EchoL		;found 
	decfsz	temp, f
	goto	PMLoopL
	decfsz	timeout, f
	goto	PMLoopUSL
	movlw	.255		;set to 255 for no echo found
	movwf	cntL
SecondUS			;Timed out so lets go again for second US
	bcf	INTCON, GIE	;disable interrupts
	movlw	.10
	movwf	pgtime
	clrf	count		;clear main counter inc. in IRQ
PingLoopR
	bcf	us_OutR		;Must be kept as is due to
	nop			;critical timing 
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	bsf	us_OutR			;Square wave 
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	decfsz	pgtime, f
	goto	PingLoopR
;+++++++++++++++++++++++++++++++++++++++++++++++++++
	bsf	INTCON, GIE	;enable interrupts
	movlw	.40
	movwf	timeout		;timeout aprox. 40" (3.3 Feet, 1m)/2
PMLoopR
	movlw	.19		;4 cycles to loop 4x19=76 
	movwf	temp		
PMLoopUSR
	btfss	USEchoR		;Look for echo 
	goto	EchoR		;found 
noechoR
	decfsz	temp, f
	goto	PMLoopUSR
	decfsz	timeout, f
	goto	PMLoopR
	movlw	.255		;set to 255 for no echo
	movwf	cntR
;Timed out so no echo found
;So just loop for now
	goto Main
;+++++++++++++++++++++++++++++++++++++++++++++++++++
EchoL			;Echo found so store count in cnt1
	movfw	count
	movwf	cntL
	bsf	flag_USL
	goto 	SecondUS
	
EchoR			;Echo found so store count in cnt2
	movfw	count
	movwf	cntR
	bsf	flag_USR
	
Mode
	;Do what has to be done if bounce detected
	;Then loop again
	
	goto Main
	


	goto	Main	
;+++++++++++++++++++++++++++++++++++++++++++++++++++
;++                  Subroutines  		  ++
;+++++++++++++++++++++++++++++++++++++++++++++++++++
WaitClkHL			;wait for clock transition high to low
	btfsc 	SCL		;test clock
	goto	setFlag		;if high goto setFlag
	btfss	flag_Clock	;if low test flag_Clock
	goto	WaitClkHL	;if flag clear back to wait
	bcf	flag_Clock	;if flag high then transition high to low occured
	return				
setFlag
	bsf	flag_Clock	;set flag_Clock
	goto	WaitClkHL	;back to wait
WaitDatHL			;wait for data transition high to low
	btfsc 	SDA		;test data line
	goto	setDFlag	;if high goto setFlag
	btfss	flag_Clock	;if low test flag_Clock
	goto	WaitDatHL	;if flag clear back to wait
	bcf	flag_Clock	;if flag high then transition high to low occured
	return				
setDFlag
	bsf	flag_Clock	;set flag_Clock
	goto	WaitDatHL	;back to wait
GetBit				;recieve bit into RXDAta
	call	WaitClkHL	;wait for clock high to low
	clrc
	btfsc	SDA		;test data line
	setc			;if data high set carry high else leave it clear
	rlf	RXData,F	;shift carry into RXData
	return
PutBit				;send bit to data line
	rlf	TXData,F	;shift TXData into carry flag	
	bcf	SDA		;clear data line
	btfsc	STATUS, C	;test carry flag
	bsf	SDA		;if carry set then set data line else leave clear
	call	WaitClkHL	;wait for clock high to low
	return
SetDataOut
	bsf	STATUS, RP0
	bcf	TRISB, 1	;set SDA to o/p
	bcf	STATUS, RP0
	return
SetDataIn
	bsf	STATUS, RP0
	bsf	TRISB, 1	;set SDA to i/p
	bcf	STATUS, RP0
	return
GetByte				;returns with byte in RXData
	call	SetDataIn
	clrf	RXData		;clear Recieve data byte
	movlw	.8		;8 bits to recieve
	movwf	cnt
Loop1
	call	GetBit		;recieve bit
	decfsz	cnt,F		;decrement counter and check for zero
	goto	Loop1		;if not zero then back to loop1
	call	SetDataOut	;if zero then we're done, set data for output
	bcf	SDA		;send acknowledge bit
	call	WaitClkHL	;wait clock high to low
	return
PutByte				;sends byte in TXData
	Call	SetDataOut
	movlw	.8		;8 bits to send
	movwf	cnt
Loop2
	call	PutBit		;send bit
	decfsz	cnt,F		;decrement counter and check for zero
	goto	Loop2		;if not zero back to loop2
	call	SetDataIn	;if zero then we're done set data for input
	call	WaitClkHL	;ignore acknowledge bit	
	return

;+++++++++++++++++++++++++++++++++++++++++++++++++++
;++		Interupt Routine 		  ++
;+++++++++++++++++++++++++++++++++++++++++++++++++++
Interupt
	movwf	I_wtemp		;Save 'w' and STATUS
	movfw	STATUS		;for restoring later
	movwf	I_stattemp
	
	movlw	.184		;255-73 (time 1")+2 cyc lost writing Timer0
				;speed of sound is 340.29m/S or 73.4uS/25mm
	movwf	TMR0
	bsf	INTCON, T0IF	;Restart timer0 interupt
	
	incf	count, f			;purpose of IRQ
	bcf		INTCON, T0IF	;clear timer0 interrupt flag 
;	bsf	LED
Iend
	movfw	I_stattemp	;Restore 'w' and STATUS
	movfw	STATUS		;before returning
	movfw	I_wtemp
	retfie

;**************************
;***    Config word     ***
;**************************
	__CONFIG h'3FFF' & _LVP_OFF & _BODEN_OFF & _XT_OSC & _PWRTE_ON & _WDT_OFF 
;+++++++++++++++++++++++++++++++
	end

 

The Results:

 

The ultrasonic output pulses from the PIC16F628 (RB0, RB3).

Note the frequency is 40.07KHz this is very close to 40KHz.

 

The ultrasonic output at the Transmitter.

 

The modulated echo from the Ultrasonic Amp. (D2A, D4A)

 

The demodulated echo (D2K, D4K)

 

The output from the comparator (RA3, RA4[open drain and needs a pull up resistor])

 

Proof of the pudding, an object was placed 300mm (12 inches) from the sensors the value read in to the Mainboard was 24 decimal the distance is measured in 25mm steps, however the value 24 has to be divided by 2 as it is twice the distance to the receiver i.e. from the transmitter back to the receiver.
The actual distance is (24/2)25 which is 300mm.