1

How can I measure the distance of an HR-S04 ultrasonic sensor with millis and micros?

5
  • 1
    I'd use the Input Capture ability of Timer1, but that's beyond the scope of this site - maybe you can find a library that does that for you.
    – Majenko
    Jul 3 at 11:18
  • @Majenko, did you see the self-answer?
    – Juraj
    Jul 3 at 15:13
  • @Juraj I did. Looks fine to me.
    – Majenko
    Jul 3 at 15:16
  • @Majenko, most ultrasonic code I saw activated trig for some microseconds and then used pulseIn to catch the echo. but the code in answer triggers for 10 milliseconds using states
    – Juraj
    Jul 3 at 15:30
  • The falling edge is what matters. It still uses pulseIn.
    – Majenko
    Jul 3 at 15:31
0

I have noticed that many people on the net have problems using millis with the sensor to take measurements etc. so I created this sketch to help anyone.

You are free to ask for any clarification about it!

/*
 *  HC-SR04 sensor measuring
 *
 *  Non-blocking HC-SR04 sensor measuring
 *
 *  The circuit:
 *  - Echo pin connected to pin 2
 *  - Trigger pin connected to pin 3
 *  - VCC pin connected to VCC (5v)
 *  - GND gger pin connected to GND
 *
 *  created 3 Jul 2021
 *  by alessandromrc
 */

#define trigPin 3
#define echoPin 2

unsigned long timerStart = 0;
unsigned long StartTime = micros();
bool timer = false;
const unsigned long HIGH_TRIGGER = 10;
const unsigned long LOW_TRIGGER = 2;

float timeDuration, distance;

enum SensorStatus {
  TRIG_LOW,
  TRIG_HIGH,
  ECHO_HIGH
};

SensorStatus sensorStatus = TRIG_LOW;

bool isTimerReady(const unsigned long Sec) {
  return (micros() - timerStart) < Sec;
}

void setup(void) {
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop(void) {
  switch (sensorStatus) {
  case TRIG_LOW: {
    digitalWrite(trigPin, LOW);
    timerStart = micros();
    if (isTimerReady(LOW_TRIGGER)) {
      sensorStatus = TRIG_HIGH;
    }
  }
  break;

  case TRIG_HIGH: {
    digitalWrite(trigPin, HIGH);
    timerStart = micros();
    if (isTimerReady(HIGH_TRIGGER)) {
      sensorStatus = ECHO_HIGH;
    }
  }
  break;

  case ECHO_HIGH: {
    if (!timer) {
      Serial.print("Microseconds Passed in initialization: ");
      Serial.println(micros() - StartTime);
      timer = !timer;
      Serial.println("Starting to Measure");
    }
    digitalWrite(trigPin, LOW);
    timeDuration = pulseIn(echoPin, HIGH);
    Serial.print("Measured: ");
    Serial.print(timeDuration * 0.034 / 2);
    Serial.println(" cm");
    sensorStatus = TRIG_LOW;
  }
  break;
  }
}

Github Repository

2
  • it is enough to trigger for 5 microseconds. why do you use a separate state to trigger for 10 milliseconds?
    – Juraj
    Jul 3 at 15:35
  • 1
    @Juraj I didn't knew about this, thanks for letting me know! Jul 3 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.