0

I'm attempting to start a timer lasting a specific interval when the ultrasonic distance sensor measures a distance lower than 25 cm. Once that occurs, I want the speaker to make sound if the distance goes above 25 cm whilst the timer is running. I am attempting to use an interrupt to do this, but I'm having trouble.

This is what I have so far:

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sensor, CHANGE);
}

int makeSound() { // This function creates the sounds
  ...
}

int echo() { // This function gets the distance the sensor is measuring
  ...
}

void loop() {
  distanceCm = echo();
  if (distanceCm < 25) {
    Timer();
  }
}


int Timer() {
  half_hour_millis = millis();

  while (millis() < half_hour_millis + interval) {
    // Here goes the code that I haven't written and was hoping you could help me with
  }
}

// My interrupt function
void sensor() {
}
  • All the level changing on the interrupt pin is complete before the timer loop is started, so you can't interrupt the loop. Sounds like thinking of your problem as three states: idle, armed, and triggered would be good. Given the way you are polling distance measurement, I'm not sure that you need to use the interrupt if you get the transitions between those states right. – Dave X Apr 8 '17 at 17:41
  • Indeed I don't, but I'm trying to get to know interrupts. – andrew Apr 8 '17 at 18:43
1

Andrew,

I think I see what you're trying to accomplish. I would try something like the following, and I'll explain afterward:

boolean timerRunning = false;
unsigned long start_millis;
unsigned long end_millis;


boolean tripped() //was int Start()
{
  dist = echo1();
  if (dist < 25 && dist > 0) {
    return true;
  else
    return false;
}


void loop()
{
  if(tripped())  //check for < 25cm
  {
    //if tripped and timer not running, start
    //keeping track of time
    if(!timerRunning)
    {
      timerRunning = true;
      start_millis = millis();
      end_millis = start_millis + half_hour;
    }
    //if timer already running, print millis
    else
    {
      Serial.println(millis()); //or Serial.pringln(millis()-start_millis);
                    // for time since timer started                  
    }
  }
  else  //not < 25cm, not tripped
  {
    //if not tripped and timer running, time for sound
    if(timerRunning)
    {
      timerRunning = false; //might as well stop timer
      alert();
    }
    //if timer not started and not tripped nothing to do
  }

  //finally, lets check time, if past half hour, stop tracking
  //elapsed time
  if(timerRunning)
  {
    if(millis > end_millis)
    {
      timerRunning = false;
    }
  }
}//end void loop()

In general, you don't want to block the loop() from looping. Some of the Arduino functions do their processing outside that loop (the interrupt pin possibly too).

I know I'm not using the interrupt, but for a couple reasons. First, it looks like the pin can only change if you call your echo1() function, as you have to trigger the ultrasonic transmitter. Secondly, the state of the pin will not reflect the distance, only that it's receiving sound. As an aside, for what it looks like you were trying to do, you would have wanted to attach the interrupt and detach the interrupt only when the timer started or ended, as opposed to in the setup. Otherwise it could interrupt at any time, such as everytime the echo1() was called.

Hopefully my code comments help explain the flow. Basically I'm keeping track of the state of things, mostly with 'timerRunning'. Based on whether the timer is running and the ultrasonics are tripped (measuring less than 25cm), the appropriate actions are taken. The only way to stop the timer is the elapsing of half an hour, or the alert condition.

Double check my math, but i think there are 1,800,000 milliseconds in half an hour, so you will want to change your constant. Also, I don't know how long you plan on having your device run, but the millis() function will rollover back to 0 after about 50 days. Your end time will end up calculating out to less than the current time and the timer will not be able to run properly (will immediately stop) for that last half hour until rollover. Just something to keep in mind.

Hope this helps and good luck!

| improve this answer | |
  • Exactly what I needed! and thanks for the lesson heh. Oh, and I'm aware of the limit of millis(), and 50 days will be more than enough, so no problem :) – andrew Apr 8 '17 at 18:43
  • 1
    > I'm aware of the limit of millis(), and 50 days ... the 50 day "limit" is only a problem if programmed poorly. Otherwise, not an issue. – dannyf Apr 8 '17 at 22:04
  • To avoid the rollover problem, just code the comparison correctly instead of incorrectly. That is, delete end_millis = start_millis + half_hour; and replace if(millis > end_millis) [sic] with if(millis()-start_millis > half_hour) because that arithmetic works ok (assuming half_hour < 2³¹) – James Waldby - jwpat7 Apr 9 '17 at 5:00

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.