Skip to content

Instantly share code, notes, and snippets.

@mindcruzer
Last active August 26, 2019 04:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mindcruzer/d03bff36c1be28dd4dc8 to your computer and use it in GitHub Desktop.
Save mindcruzer/d03bff36c1be28dd4dc8 to your computer and use it in GitHub Desktop.
TI MSP430F5529 distance measurement with HC-SR04 ultrasonic range sensor.
#include <intrinsics.h>
#include <stdint.h>
#include <msp430.h>
#define TRIGGER_PIN BIT1 // P6.1
#define ECHO_PIN BIT3 // P1.3
#define LED_PIN BIT0 // P1.0
#define DISTANCE_THRESHOLD 60 // cm
#define MEASURE_INTERVAL 2048 // ~250 ms
void triggerMeasurement() {
// Start trigger
P6OUT |= TRIGGER_PIN;
// Wait a small amount of time with trigger high, > 10us required (~10 clock cycles at 1MHz MCLK)
__delay_cycles(10);
// End trigger
P6OUT &= ~TRIGGER_PIN;
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD;
// Configure trigger pin, low to start
P6DIR |= TRIGGER_PIN;
P6OUT &= ~TRIGGER_PIN;
// Configure LED, off to start
P1DIR |= LED_PIN;
P1OUT &= ~LED_PIN;
// Configure echo pin as capture input to TA0CCR2
P1DIR &= ~ECHO_PIN;
P1SEL |= ECHO_PIN;
// Set up TA0 to capture in CCR2 on both edges from P1.3 (echo pin)
TA0CCTL2 = CM_3 | CCIS_0 | SCS | CAP | CCIE;
// Set up TA0 to compare CCR0 (measure interval)
TA0CCR0 = MEASURE_INTERVAL;
TA0CCTL0 = CCIE;
// Set up TA0 with ACLK / 4 = 8192 Hz
TA0CTL = TASSEL__ACLK | ID__4 | MC__CONTINUOUS | TACLR;
uint16_t lastCount = 0;
uint32_t distance = 0;
for (;;)
{
triggerMeasurement();
// Wait for echo start
__low_power_mode_3();
lastCount = TA0CCR2;
// Wait for echo end
__low_power_mode_3();
distance = TA0CCR2 - lastCount;
distance *= 34000;
distance >>= 14; // division by 16384 (2 ^ 14)
if (distance <= DISTANCE_THRESHOLD)
{
// Turn on LED
P1OUT |= LED_PIN;
}
else
{
// Turn off LED
P1OUT &= ~LED_PIN;
}
// Wait for the next measure interval tick
__low_power_mode_3();
}
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR (void) {
// Measure interval tick
__low_power_mode_off_on_exit();
TA0CCR0 += MEASURE_INTERVAL;
}
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR (void) {
// Echo pin state toggled
__low_power_mode_off_on_exit();
TA0IV = 0;
}
@beso-eng
Copy link

i have a question please
why to set the MEASURE_INTERVAL to 2048
and could you explain the following equation i didn't get exactly how to find the distance from this equation
distance *= 34000;
distance >>= 14; // division by 16384 (2 ^ 14)

i know that distance = duration * 0.034/2;

@mindcruzer
Copy link
Author

mindcruzer commented Aug 26, 2019

@beso-eng It's been a long time since I wrote this, but I believe it works out like this:

The timer is clocked at 8192 Hz (increments 8192 times per second).

2048 ticks means 2048 / 8192 = 1/4 of a second, so 250 ms. This means that the first timer interrupt will fire every 250 ms, effectively taking the device out of low power mode, which it enters as the last instruction of the main loop. All this means is that the main loop runs every 250 ms, so a distance measurement is executed about 4 x per second.

distance = TA0CCR2 - lastCount

This is determining how many times the timer incremented between the trigger (emission of the sound pulse) and the echo (return of the sound pulse).

distance *= 34000

The speed of sound in dry air at room temperature is about 340 m/s. I wanted centimeters here so multiplying by 100 we get 34000 cm/s.

distance >>= 14

Those increments from earlier need to be converted to seconds. Dividing by 8192 (>> 13) gives us seconds, but the sound pulse hits the distant object and then returns, so that time needs to be divided by 2 (>> 14).

The calculation is effectively:
distance = timer ticks * 1 second / 8192 ticks * 1/2 * 34000 cm/s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment