arduino ultrasound sensor example

Hi All,

I just received my Arduino Dieimila last week, and I wanted to say thanks to the community for something that was so easy to set up with my Mac and get running.

As a first project, I worked through the Ultrasound example using the Parallax ultrasonic range finder. I modified the code to detect the returning pulse inside an external interrupt, rather than polling for it. I thought I'd post my code in case it proves useful for anyone else going in this direction. I haven't calibrated the sensor yet. The distances look approximately correct, with 0" starting a few inches from the sensor. That may be a timing issue on my part. Any comments or suggestions are welcome.

Thanks,

-Rob

/* Ultrasound Sensor
*------------------
*

  • Reads values (00014-01199) from an ultrasound sensor (3m sensor)
  • and writes the values to the serialport.
  • http://www.xlab.se | http://www.0j0.org
  • copyleft 2005 Mackie for XLAB | DojoDave for DojoCorp
  • 2007-09: Modified by RJL (robertlucier@yahoo.com)
  • to detect the ultrasound return pulse via INT1

*/

#define TIMER_US_PER_TICK 4 // 16MHz / 64 cycles per tick
#define TIMER_OVERFLOW_US TIMER_US_PER_TICK * 65536 // timer1 is 16bit
#define INCH_PER_SEC 13526 // speed of sound

// use pin 3 because it is connected to external interrupt 1 (INT1)
int ultraSoundSignal = 3; // Ultrasound signal pinint val = 0;

int ledPin = 13; // LED connected to digital pin 13
int count = 0;

// these are volatile because they are changed in interrupt handlers
// otherwise the compiler will assume they are unchanged and replace with constants.
volatile long ofStart = 0;
volatile long timerStart = 0;
volatile long ultrasoundValue = 0;
volatile int timer1_overflow = 0;

ISR(SIG_OVERFLOW1) {
// keep track of timer1 overflows.
// these should happen every TIMER_OVERFLOW_US microseconds (approx 4 per second at 16MHz clockspeed)
timer1_overflow += 1;
};

void ultrasound_response() {
/* Listening for echo pulse


  • response should come withing ~.5ms (6") and 10ms(20")
  • handles falling pin interrupt signal
    */
    if (ofStart != -1) {
    // check ofStart and return if a new ping has started.
    ultrasoundValue = diffTime();
    }
    }

void markTime() {
// !!! even though interrupts are disabled, this calculation is still error prone
// if the TCNT1 rolls over, but timer1_overflow isn't incremented.
cli(); // disable global interrupts
timerStart = TCNT1;
ofStart = timer1_overflow;
sei(); // enable global interrupts
}

long diffTime() {
// return diff in microsec between now and the last mark
long us;
us = (timer1_overflow - ofStart) * 65536;
us += (TCNT1 - timerStart);
us *= TIMER_US_PER_TICK;
return us;
}

long microsecs() {
// for debugging
long us;
us = timer1_overflow * 65536;
us += TCNT1;
us *= TIMER_US_PER_TICK;
return us;
}

void setup() {
beginSerial(9600); // Sets the baud rate to 9600
pinMode(ledPin, OUTPUT); // Sets the digital pin as output
attachInterrupt(1, ultrasound_response, FALLING);
TCNT1 = 0; // reset timer 1
TCCR1A = 0x00; // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,
// PWM10=0 => PWM Operation disabled
TCCR1B = 0x03; // clock/64 = increments every 3.2us - overflows in 209.7mS
TIMSK1 |= _BV(0); // timer1 overflow interrupt enable TOIE1=1. atmel_doc2545 p. 135
}

void triggerPulse() {
/* Send low-high-low pulse to activate the trigger pulse of the sensor


*/
int val;
ultrasoundValue = -1; // reset any previous value
ofStart = -1; // indicator to INT1 interrupt to ignore this LOW
pinMode(ultraSoundSignal, OUTPUT); // Switch signalpin to output
digitalWrite(ultraSoundSignal, LOW); // Send low pulse
delayMicroseconds(2); // Wait for 2 microseconds
digitalWrite(ultraSoundSignal, HIGH); // Send high pulse
delayMicroseconds(5); // Wait for 5 microseconds
digitalWrite(ultraSoundSignal, LOW); // Holdoff
Serial.print("!");

// this could also be handled in an interrupt
pinMode(ultraSoundSignal, INPUT); // Switch signalpin to output
// poll until ultrasound sensor goes low
val = digitalRead(ultraSoundSignal); // Append signal value to val
while(val == LOW) { // Loop until pin reads a high value
val = digitalRead(ultraSoundSignal);
}
markTime();
Serial.print("_");
}

void printValue() {
long in;
long ft;
// divide by 1000000 here in three steps of 100
in = ((ultrasoundValue/100) * (INCH_PER_SEC/100))/100;
in /= 2; // total elapsed time is there and back - divide by two for one way
ft = in / 12;
in = in % 12;
Serial.print("\n");
Serial.print('A'); // Example identifier for the sensor
Serial.print(ultrasoundValue);
Serial.print("\t");
Serial.print(ft);
Serial.print("'\t");
Serial.print(in);
Serial.print(""");
Serial.print("\n");
serialFlush();
}

void loop() {
printValue();
triggerPulse();
Serial.print(".");
delay(100);
}

hey

that is terrific... if you can, it's good to also make a page in the Playgorund, as the search function for the forum is terrible. At the bottom right corner of the Playground there is a link called "request contributor access". It issues you a password automatically.

Thanks for the tip. I created a page called PingInterruptCode, and linked it from the Interrupts Example page. That page also links to the cool DCF77 receiver clock, which provided some inspiration to me on timer code.