Jump to content
Sign in to follow this  
itselbert

Ultrasonic range finder

Recommended Posts

Hi everyone, I literally just got the launchpad and I am hoping to use it to design an ultrasonic range finder. I've been doing some reading and I know that I need a MCU with Comp_A, so I've gotten myself some MSP430G2452 to start it all. Now the thing is I basically have no experience using microcontrollers and pretty light with coding in C, so when I read some of the documentation I am finding myself confused about alot of things.

 

What I'm hoping to find out is how to generate a 40 kHz square wave with the DCO rather than the crystal and how to use the comp_A peripheral to calculate the distance using the echo. So far I have worked out how to set the inpu/output pins and use the p1.3 button on the launchpad. I am going through david's blog at mspsci.blogspot and now I am kinda struggling at configuring the DCO. All I have achieved at this point is to slow down the blinking LED by modifying the BCSCTL1 and DCOCTL values, though I'm probably doing it wrong.

 

If you have read upto this point, let me say thanks and I hope you can help me out :D Cheers!

Share this post


Link to post
Share on other sites

Hey guys, thanks for the replies. Well looking at NJC's blog page I did get it to work somewhat using the code on the page. I actually need to test it later. I was just wondering about CCR0 and CCR1. For CCR0 what exaclty is data type used for it? because CCSv4 was complaining that the number was large and it was being truncated and also is its function to divide the DCO frequency? so CCR0 = 1000 means 1MHz/1000 ?

 

Alternatively using grace I did manage to set it to 40 kHz using one of the grace examples. Now my question is how would I proceed to use it with comp_A?

Share this post


Link to post
Share on other sites

Hey Bluehash/rick I managed to generate the 40 kHz signal. I am using the following code:

 

WDTCTL = WDTPW + WDTHOLD;

//P1DIR |= 0x01;

//P1DIR |= 0x40;

//P1OUT = 0x00;

 

P1DIR |= BIT6;

P1SEL |= BIT6;

 

BCSCTL1 = CALBC1_8MHZ; // Set range

DCOCTL = CALDCO_8MHZ; // Set DCO step + modulation */

 

CCR0 = 198; // for this, it gives me 40 kHz exactly

CCTL1 = OUTMOD_7;

CCR1 = 50;

TACTL = TASSEL_2 +MC_1;

 

_BIS_SR(LPM0_bits);

 

How do I connect this to Comp_A? I had a look at the 3 examples but they only explain the function they are performing but I don't know how it performs them. I haven't found any good explanation on how to use comp_a, so I was wondering if anyone knows of a good guide or would care to explain its use.

 

Cheers

Share this post


Link to post
Share on other sites

The comp_A as of yet doesn't make much sense to me. Instead I've been working on this:

 

#include  


#define RLY1  BIT6;

//  Global Variables  
char i=0;

void CAinit(void);
//  Function Definitions 

void main(void) {
WDTCTL = WDTPW + WDTHOLD;    // disable watchdog

P1OUT = 0;                  
//P1DIR = RLY1;    // P1.6 out to relay (LED)
P1DIR |= BIT6;
P1SEL |= BIT6;
P1DIR |= BIT0;

BCSCTL1 = CALBC1_8MHZ;    // Set DCO to calibrated 1 MHz.
DCOCTL = CALDCO_8MHZ;

TACCR0 = 198;    // A period of 62,500 cycles is 0 to 62,499.
TACCTL0 = CCIE;        // Enable interrupts for CCR0.
TACCTL1 = OUTMOD_7;
TACCR1 = 50;
TACTL = TASSEL_2 + MC_1 + TACLR;  // SMCLK, up mode, 
                                         // clear timer

_enable_interrupt();


_BIS_SR(LPM0_bits);


for(; {    // Do nothing while waiting for interrupts.  This would be an
}            // an ideal place to use low power modes!
} // main


//  Interrupt Service Routines  
#pragma vector = TIMER0_A0_VECTOR
__interrupt void CCR0_ISR(void) {

if (++i == 12) {
	P1OUT ^= BIT0;
	P1DIR ^= BIT6;
	i=0;	
}

Can anyone tell me if this is doing 12 cycle bursts of 40 kHz PWM? I created this bit so it wouldn't be transmitting the pwm signal constantly and I was hoping to work the comp_A component into this code. I don't have an oscilliscope at home so I can't test it over the weekend. If you could let me know if this is doing what I hope it is doing it'd be great.

 

Also I am a little confused regarding the CCRx and CCTLx registers, can I omit the "TA", for example, of the TACCRx that was used in the demo code? edit: nvm I found out they are the same from the header file.

 

Thanks guys

Share this post


Link to post
Share on other sites

Is there any chance someone can explain how I am meant to use the comp_a to detect the echo used to calculate the distance? I am having trouble figuring out how it works, so I can't even attempt to code it.

Share this post


Link to post
Share on other sites

I took a look at that, but I don't really understand it. I am using C, not assembly. When I read that, the pdf only says that the comp_a is used for detecting the echo.

 

From what I understand so far, the comp_a receives a signal from the rx transducer as 1 sample as well as the original signal. What I dont understand is how it works out that the rx signal is an echo. I am thinking its something to do with the time difference between the rising edge of the original signal and the echo. I think it uses the count stored in CCR0 to calculate the distance. But this is just guess work and I am not sure how I'd actually implement what i just typed.

Share this post


Link to post
Share on other sites
From what I understand so far, the comp_a receives a signal from the rx transducer as 1 sample as well as the original signal.

I doubt that. Here is a nice article that explains the workings of a range finder (it's for the Arduino, obviously :twisted:, but that doesn't make the theory less sound, and the code is easy to follow even if you haven't seen Arduino before).

Share this post


Link to post
Share on other sites

Here's something I had going awhile back. I didn't finish it do to some bug/got bored/meh. The circuits are the same as what gordon posted. My intent was to send the distance data to another uC through serial. Here's the code I had going and a pic. Hopefully I left things in a working state.

 

PS Don't look at the code if you wanted to figure it out yourself. I think I was pretty close to finished.

 

#include "msp430g2231.h"
//#include 

#define PIN_RECEIVER				BIT4
#define PIN_TRANSMITTER				BIT2
// SPI pins for reference, do not affect code: 
#define PIN_SCLK					BIT5
#define PIN_SDO						BIT6

#define ADC_MAX						1023
#define MCLK_FREQUENCY				16000000
#define TRANSMITTER_FREQ			24000
#define WDT_DIVIDER					64
#define SPEED_OF_SOUND_IN_PER_SEC 	13071.3f
#define MINIMUM_DISTANCE_IN			8
#define MAXIMUM_DISTANCE_IN			600
#define PINGS_AVERAGED 				1

#define sendPing()					TACTL |= MC_1
#define stopTransducer()			TACTL &= ~MC_1

const unsigned long WDT_FREQUENCY = MCLK_FREQUENCY / WDT_DIVIDER;
const float WDT_TICKS_PER_IN = (MCLK_FREQUENCY / WDT_DIVIDER) / SPEED_OF_SOUND_IN_PER_SEC;

char iTransducerCycle = 0;
char nTransducerCycles = 7;
volatile unsigned long wdtCounter = 0;
volatile unsigned long tPing;

void setup(){
const unsigned int SONAR_PERIOD = MCLK_FREQUENCY / TRANSMITTER_FREQ;

DCOCTL = CALDCO_16MHZ;
BCSCTL1 = CALBC1_16MHZ;

WDTCTL = WDTPW + WDTTMSEL + WDTIS1 + WDTIS0;
IE1 |= WDTIE;

// setup pwm for ultrasound gen
TACCTL1 |= OUTMOD_7;
TACCR0 = SONAR_PERIOD;
TACCR1 = SONAR_PERIOD / 2;
TACCTL0 |= CCIE;
TACTL |= TASSEL_2;
P1DIR |= PIN_TRANSMITTER;
P1SEL |= PIN_TRANSMITTER;

// setup adc to capture echo
ADC10CTL1 |= ADC10SSEL_3 + INCH_4;
ADC10CTL0 |= ADC10ON + ENC + ADC10SHT_0;

// setup USI
USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE; // Port, SPI master
//  	USICTL1 |= USIIE;                     // Counter interrupt, flag remains set
 	USICKCTL = USIDIV_7 + USISSEL_2;      // SMCLK/128 for 125000 baud @ SMCLK 16MHz
	USICTL0 &= ~USISWRST;                 // USI released for operation
	USICNT |= USI16B;					  // shift out 16-bits

_BIS_SR(GIE);
}

//void delayMillis(unsigned long milliseconds){
//	// todo: add rollover handling
//	unsigned long wakeTime = wdtCounter + (milliseconds * WDT_FREQUENCY / 1000);
//	while(wdtCounter < wakeTime);
//}

unsigned long locatePeak(unsigned long startTime, unsigned long endTime){
unsigned long peakTime = 0;
unsigned long conversionTime;
unsigned int peakValue = 0;
unsigned int analogValue;

while(wdtCounter < startTime);

while(wdtCounter < endTime){
	ADC10CTL0 |= ADC10SC;
	conversionTime = wdtCounter;
	while(ADC10CTL1 & ADC10BUSY);
	analogValue = ADC10MEM;
	if(analogValue > peakValue){
		peakValue = analogValue;
		peakTime = conversionTime;
	}
}
return peakTime;
}

float wdtTicksToInches(unsigned int ticks){
return ((ticks / WDT_TICKS_PER_IN) / 2);// + 0.5;
}

float inchesToWdtTicks(float inches){
return(inches * WDT_TICKS_PER_IN * 2);
}

float getDistance(unsigned long minimumWdtTicks, unsigned long maximumWdtTicks){
unsigned long tStrongestEcho;

sendPing();
while(TACTL & MC_1);					// wait for ping transmit completion
tStrongestEcho = locatePeak(minimumWdtTicks + tPing, maximumWdtTicks + tPing);

return wdtTicksToInches(tStrongestEcho - tPing);
}

void TX_Data(unsigned int data){
while(USICNT & 0x1F);					// wait for previous TX completion
USISR = data;
USICNT += 16;
}

void main(){
char iPing;
float averageDistance;
unsigned int distance;
unsigned int minimumWdtTicks;
unsigned int maximumWdtTicks;

setup();

minimumWdtTicks = inchesToWdtTicks(MINIMUM_DISTANCE_IN);
maximumWdtTicks = inchesToWdtTicks(MAXIMUM_DISTANCE_IN);

while(1){
	if(PINGS_AVERAGED > 1){
		averageDistance = 0;
		for(iPing = 0; iPing < PINGS_AVERAGED; iPing++)
			averageDistance += (getDistance(minimumWdtTicks, maximumWdtTicks) / PINGS_AVERAGED);

		distance = averageDistance + 0.5;
	}
	else
		distance = getDistance(minimumWdtTicks, maximumWdtTicks) + 0.5;

	TX_Data(distance);
}

}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0 (void){
if(iTransducerCycle < nTransducerCycles)
	iTransducerCycle++;
else{
	tPing = wdtCounter;
	stopTransducer();
	iTransducerCycle = 0;
}
}

#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void){
wdtCounter++;
}

 

2011-10-11_17-33-58_573.jpg

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...