Arduino and ultra sonic range measurement module or how to measure the pulse time with a hardware timer and an interrupt


SEN136B5B is a Ultra Sonic range measurement from SeedStudio. It can measure the distance by sending a 40k Hz ultra sound impulse via the transmitter  and calculating time needed for echo to reach receiver. Detecting range: 3cm-4m. More information about device.

In the description of module is mentioned that it is compatible with Arduino library, but I decided to write program without using PulseIn command.

As you can see from picture above reading information from ultra sonic module requires measurement of time. So once again I have used a hardware Atmega 16 bit timer/counter.

void setup()   {

  Serial.begin(9600);
  Serial.print(0x0C,BYTE); // clear screen

  TIMSK1=0x01; // enabled global and timer overflow interrupt;
  TCCR1A = 0x00; // normal operation page 148 (mode0);
  TCCR1B=0; //stop
}

I have used the serial OLED display GLO-16 to show distance, so there is serial port configuration. I hope to review this display later at the separate blog post.

The configuration of timer is standard.

void loop() {

  state=0;
  overflow_counter=0;

  pinMode(sense_pin, OUTPUT);
  digitalWrite(sense_pin,HIGH);
  delayMicroseconds(10); // 10 us impulse to start measurement

  pinMode(sense_pin, INPUT);
  digitalWrite(21,LOW);

  attachInterrupt(interrupt_pin, interrupt, RISING);
  x=0;

  //waiting for interrupt

  delay(50);

At the beginning of the loop a positive 10 µs duration impulse is generated at pin 21(there is the SIG pin of ultra sonic module connected)  to start measurement. Then the interrupt for rising edge is enabled. Not all Arduino pins can trigger external interrupt.

#define interrupt_pin 21 //SIG
#define interrupt_number 2

 


void interrupt()
{
  if (!x) { // rising edge happened

    TCCR1B=2; //start timer with /8 prescaler
    attachInterrupt(interrupt_number, interrupt, FALLING);

  }

  else {  //falling edge happened
    TCCR1B=0; //stop timer
    count=TCNT1;
    TCNT1=0x000;
    state=1;

  }

  x=~x;
}

After external interrupt is triggered by rising edge, timer is started and interrupt for falling edge is enabled.

With the /8 prescaler timer/counter is clocked at 2 MHz rate. A counter increases by 1 every 0.5 µs. That is 0.5 * 2^16 = 32,7 ms until overflow. It is enough if object is in 4 meter range, but it’s not if object if out of range and module generates 38 ms impulse, so the program lets timer to overflow one time.

If the falling edge is detected, timer is stopped and content of his register is saved.


void manage_overflow () {

  if (overflow_counter>1 ) {

    detachInterrupt(interrupt_number);
    TCCR1B=0; //stop
    state=2;
  }

}

ISR(TIMER1_OVF_vect) {

  overflow_counter++;
  manage_overflow();

}

If falling interrupt doesn’t occur since 32,7 ms since rising interrupt, one timer overflow is allowed. If ~ 60 ms is not enough timer is stopped and error is displayed.

Let’s back to end of loop:


switch(state) {

  case 1:
    {

    time=count*0.5; // µs

      if ( overflow_counter!=0) {
        show_out_off_range();
      }

      else  show_distance(time/58);

      break;
    }

  case 2:
    {
      show_error();
      break;
    }

  default :
    show_error();

  }

  delay(250);
};

state = 0 – no measurement are performed, module is not connected.

state =1 – it means that measurement was successful. Time is converted to distance, but if timer’s overflow occurred once then it’s likely that module generated 38 ms signal – no obstacle.

state = 2 – error, since time between rising and falling edges is more than ~60ms.

All program:

//Ultra Sonic range measurement module SEN136B5B
// with GLO-216 2x16 Multifont Serial OLED
//electronicsblog.net
unsigned char x=0;
double count =0;
double time=0;
int state=0;
int overflow_counter=0;

#define interrupt_pin 21 //SIG
#define interrupt_number 2

void show_error(void) {

  Serial.print(0x0C,BYTE); // clear screen

  Serial.print("Error!");
  Serial.print(0x01,BYTE); //home cursor
  Serial.print(0x0A,BYTE); //move down one row
  Serial.print("Check wiring!");
}

void show_out_off_range(void){

  Serial.print(0x0C,BYTE); // clear screen

  Serial.print("No obstacle!");
}

void show_distance(double distance)

{

  Serial.print(0x01,BYTE); //home cursor
  Serial.print(0x03,BYTE); // normal font
  Serial.print(0x02,BYTE);// increase font
  Serial.print(0x02,BYTE);// increase font
  Serial.print(0x02,BYTE);// increase font

  Serial.print(distance);

  if (distance<10) {
    Serial.print("   ");

    Serial.print(0x08,BYTE); // back space
    Serial.print(0x08,BYTE); // back space
    Serial.print(0x08,BYTE); // back space
  }

  if (distance<100) {
    Serial.print("  ");

    Serial.print(0x08,BYTE); // back space
    Serial.print(0x08,BYTE); // back space
  }

  Serial.print(0x03,BYTE);  // normal font
  Serial.print(0x0A,BYTE); //move down one row
  Serial.print(" cm");
  if (distance<100) {
    Serial.print("   ");
  }
  if (distance<10) {
    Serial.print(" ");
  }

}

void interrupt()
{
  if (!x) { // rising edge happened

    TCCR1B=2; //start timer with /8 prescaler
    attachInterrupt(interrupt_number, interrupt, FALLING);

  }

  else {  //falling edge happened

    TCCR1B=0; //stop timer
    count=TCNT1;
    TCNT1=0x000;
    state=1;

  }

  x=~x;
}

void manage_overflow () {

  if (overflow_counter>1 ) {

    detachInterrupt(interrupt_number);
    TCCR1B=0; //stop
    state=2;
  }

}

ISR(TIMER1_OVF_vect) {

  overflow_counter++;
  manage_overflow();

}

void setup()   {

  Serial.begin(9600);
  Serial.print(0x0C,BYTE); // clear screen

  TIMSK1=0x01; // enabled global and timer overflow interrupt;
  TCCR1A = 0x00; // normal operation page 148 (mode0);
  TCCR1B=0; //stop
}

void loop() {

  state=0;
  overflow_counter=0;

  pinMode(interrupt_pin, OUTPUT);
  digitalWrite(interrupt_pin,HIGH);
  delayMicroseconds(10); // 10 us impulse to start measurement

  pinMode(interrupt_pin, INPUT);
  digitalWrite(21,LOW);

  attachInterrupt(interrupt_number, interrupt, RISING);
  x=0;

  //waiting for interrupt

  delay(50);

  switch(state) {

  case 1:
    {

      time=count*0.5; // µs

      if ( overflow_counter!=0) {
        show_out_off_range();
      }

      else  show_distance(time/58);

      break;
    }

  case 2:
    {
      show_error();
      break;
    }

  default :
    show_error();

  }

  delay(250);
};

Video demonstration is below:

  • seema

    nice

  • http://www.1-script.com/ Scriptster

    Darius, I’m curious if the measurement is any different if the obstacle is made of hard material (metal sheet for ex.) as opposed to the foam you used?

    • http://www.electronicsblog.net/ Darius

      One difference between materials would be  important in this measurement. It is ability to reflect ultrasound signal. If the amplitude of reflection is bigger then signal can be detected at longer distance.

      Reflection occurs then  sound travels trought border of different materials that have different acoustic impedance.  The bigger the difference of impedance the bigger reflection are.  At room temperature acoustic impedance of Air is .0004  (gm/cm2 sec) x 10^5, Aluminum – 17.0, Iron -45.4, Polyethylene – 1,7. So reflection is  less at Air -Polyethylene border.

      • http://elabz.com/ Elabz.com

        Thanks, Darius. This is a great concise explanation, makes total sense. So, the question is then: since you’re measuring distances that are not much greater than the thickness of the foam itself, do you see any potential issue with the device not being able to tell whether the reflection is coming from the front of the foam sheet or the back?

        I’m looking into a possibility of automatically focusing my CNC laser cutting rig http://elabz.com/laser-cutting-diy/ by moving the laser further away or closer, depending on the thickness of the foam I’m cutting. And it’s a small low-power setup based on DVD lasers, basically only cuts foam. The foam comes in different sizes anywhere between 2mm and 8mm, and at some point I may be able to cut even thicker sheets (blocks rather at this size). The trick is to position the focal point (which is at a precisely known distance from the laser) in the middle of the foam’s thickness. In other words, I’m looking at potentially measuring distance to the top of a sheet of foam that’s laying ontop of some greatly more rigid material (aluminum) with accuracy of +- 0.5mm

        So, based on your experience, should I even mess with ultrasound distance measuring  given the accuracy I’m looking for and, of course, I need the sensor to be able to take measurement from the air/foam border (top of the foam sheet) and not from foam/aluminum (bottom of the foam sheet). Will greatly appreciate any relevant experience with your device you can share.

        Cheers!

        P.S. Thanks again for the idea of using the SyntaxHighlighter for better looking code! I ended up making Arduino custom brush for it.

        • http://www.electronicsblog.net/ Darius

          First of all I’m know more about ultrasound measurement theoretically than practically. This ultrasonic module, witch i was using has resolution of measurement 1 cm (though no tested by myself)  http://garden.seeedstudio.com/index.php?title=Ultra_Sonic_range_measurement_module .

          I think this  module registers only first echo signal, so it should detect only reflection from top of foam sheet. Ultrasound speed in an air is 344 m/s. So sound takes ~ 3 ms to travel 1m, 300 µs – 1 cm, 30 µs – 1mm. So it’s not problem  to measure that period of time with simple microprocessor.

          As it seems module outputs the same duration pulse as ultrasound’s echo takes time to reach the receiver.  According to the formula http://www.electronicsblog.net/wp-content/uploads/Ultra-Sonic-seq.jpg is distance is 1 meter, pulse is 5,8 ms. From that ultrasound speed is 1*2/0.0058 = 344,9 m/s.

          So it’s imposable to measure foam width if ultrasound sensor distance from table is fixed. There is one problem. Ultrasound speed  depends on air’s humidity, temperature, composition , so there is need to calibrate system before measurements. For example speed at room temperature (25 C) is 344, 0 C – 334 C.

  • http://www.playlist.pk Pakistani music

    I think I got the machine language now and its working pretty good.