MSP430 | Distance Measurement Using HC-SR04 Ultrasonic sensor
MSP430 | Distance Measurement Using HC-SR04 Ultrasonic sensor

An ultrasonic sensor is an electronic device that measures the distance of a target object by emitting ultrasonic sound waves. The emitted sound waves frequency is too high for humans to hear. They then wait for the sound to be reflected back, and converts the reflected sound into an electrical signal. which can be used to calculate distance based on the time required.

HC-SR04 Ultrasonic sensor

Ultrasonic ranging module HC – SR04 provides 2cm – 400cm non-contact measurement function, the ranging accuracy can reach to 3mm. The modules includes ultrasonic transmitters, receiver and control circuit. The basic principle of work:

  • The trigger pin has to be high for at least 10us.
  • The Module automatically sends eight 40 kHz signals and echo pin will be high. Initiates a time counter.
  • IF the signal back, echo pin will be low, stop the timer, the time duration of high pulse is same duration as the time difference between transmitted ultrasonic bursts and the received echo signal.
Timing diagram

The following equation calculates the distance to an object placed in front of an ultrasonic sensor:

Basic equation

After including speed of sound and further simplification the final equation for distance in terms centimeter and inch is given below.

Final equation

The explanation for the equation derivation can be found in http://www.emcu.eu/understand-the-way-to-use-hc-srf04-on-stm32-nucleo-board-and-mbed/

In this post the MSP430 microcontroller is used to calculate the distance in centimeter with timer capture method. HC-SR04 sensor is connected to MSP430FR6989 development board.

  • VCC – VCC
  • Trigger pin – P3.3
  • ECHO pin – P1.7
  • GND – GND
uint8_t compareDone = 0,reset;
uint16_t negEdge,posEdge,distance,diff;
const uint16_t onecycle = 30;//         1/32768

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    //LCD initialization
    lcdInit();

    //Configuring Trigger pin as output
    P3DIR |= BIT3;
    P3OUT &= ~BIT3;

    //Configuring echo pin as input
    P1DIR &= ~BIT7;
    P1SEL0 |= BIT7;
    P1SEL1 |= BIT7;

    PM5CTL0 &= ~LOCKLPM5;

      // Timer0_A3 Setup
      TA0CCTL2 = CM_3 | CCIS_0 | SCS | CAP | CCIE;
                                                // Capture rising edge,
                                                // Use CCI2B=ACLK, //32768 Hz
                                                // Synchronous capture,
                                                // Enable capture mode,
                                                // Enable capture interrupt

      //Trigger pin high for more than 20us
      P3OUT |= BIT3;
      __delay_cycles(20);
      P3OUT &= ~BIT3;

      //Start the timer
      TA0CTL = TASSEL__ACLK | MC__CONTINUOUS;  // Use SMCLK as clock source,
                                                // Start timer in continuous mode
      __bis_SR_register(GIE);

      while(1)
      {
          //Perform calculation to find distance in cm.
          if(compareDone == 0x02)
          {
              __disable_interrupt();
              TA0CTL = TACLR;
              diff = negEdge - posEdge;
              distance = (onecycle * diff) / 58;
              if(distance < 30)
              {
                  // Display digits
                  LCDM15 = lcd_num[distance / 10];
                  LCDM8 = lcd_num[distance % 10];
              }
//              else
//              {
//                  LCDM15 = lcd_num[0];
//                  LCDM8 = lcd_num[0];
//              }

              //After calculation restart the operation
              compareDone = 0x00;
              __enable_interrupt();
              P3OUT |= BIT3;
              __delay_cycles(20);
              P3OUT &= ~BIT3;
              TA0CTL = TASSEL__ACLK | MC__CONTINUOUS;
              reset = 0;
          }
            __delay_cycles(800000);
            reset++;

            //If calculation fails restart the operation again
          if(reset == 10)
          {
              __disable_interrupt();
              TA0CTL = TACLR;
              compareDone = 0x00;
              __enable_interrupt();
              P3OUT |= BIT3;
              __delay_cycles(20);
              P3OUT &= ~BIT3;
              TA0CTL = TASSEL__ACLK | MC__CONTINUOUS;
              reset = 0x00;
          }
      }
    return 0;
}

// Timer0_A3 CC1-2, TA Interrupt Handler
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer0_A1_ISR(void)
{
  switch (__even_in_range(TA0IV, TA0IV_TAIFG)) {
    case TA0IV_TA0CCR1:
      break;
    case TA0IV_TA0CCR2:
        if(compareDone == 0x00)
        {
            //Capture the timer value when echo pin becomes high (ranging start)
            posEdge = TA0CCR2;
            compareDone = 0x01;
        }
        else if(compareDone == 0x01)
        {
            //Capture the timer value when echo pin becomes low (ranging stops)
            negEdge = TA0CCR2;
            compareDone = 0x02;
        }

      break;
    case TA0IV_TA0IFG:
      break;
    default:
      break;
  }
}

The timer capture method is used to get the time difference between echo high and echo low. Timer A is configured for ACLK and to start capture at both edge of input signal. ACLK frequency is 32768 Hz so 1/32768 = 30.5us for 1 tick count. The formula for distance measurement required time in terms of microseconds so onecycle is take as 30. Time taken by echo signal from becoming high to low (echo pulse width) is given by (onecycle * diff). The distance measurement is displayed on LCD.

The source code of the project is available in Github.