Attempting to control the flow of a program with a while() function

Hello,

I'm currently trying to make a speedometer using a hall effect sensor(senses the presence of a magnetic field). In my sketch I have 2 functions set up, one that checks the value returned by the hall effect sensor and then sets a variable to HIGH or LOW, the other sets a variable (time) to the current millis() value, then returns that value. What I'm trying to do, and failing at is getting the millis() value when it is high, then letting the program continue to run until the state changes to HIGH again. Hopefully that makes sense, the basic sketch is below, I'm not trying to calculate the speed yet, I'm just trying to first get the time elapsed between HIGH -> LOW -> HIGH.

int startTime;
int stopTime;
int elapsedTime;
int val;
int state;
int time;
int threshold=520; //sets threshold to 520, this must be calibarated for each sensor


void setup(){
  Serial.begin(9600);
}

void check() {
    if(val < threshold) //checks to see if the value is less than the set threshold
      state=LOW;      //this then sets the state to either low or high
    else
      state=HIGH;
}

int getTimeValue() { //if state is HIGH(magnet present) then assign current millis value to time variable and return that value
    if(state == HIGH) {
      time = millis();
      return time;
    }
} 
  
  
void loop() {
  Serial.print("Raw Value: ");
  
  val = analogRead(0); //get raw reading from hall effect sensor, assign to val variable
  
  Serial.print(val); //print raw value, for calbrating the threshold variable
  
  Serial.println("  Elapsed Time: ");
  
  check();
  
  startTime = getTimeValue(); //if the state is HIGH (magnet is present) assign current millis value to startTime

  check(); //checking to see what the state is, HIGH or LOW
  
  //********  somewhere in here I need to control the program so it just loops, without doing anything if the state
  //********  is equal to LOW, then exit this loop when it changes to HIGH then continue running and execute the lines below
  //********  I tried using while(state == LOW); but that stops the program entirely and it never exits, any help is appreciated
  
  stopTime = getTimeValue(); //if it is HIGH again, assign new millis value to stopTime
  
  elapsedTime = (stopTime - startTime); // calculate the difference, should give elapsed time
  
  Serial.print(elapsedTime); //print elapsedTime to serial monitor
}

You need to do one thing in the while loop - refresh the value of state with the current value of the variable so that when it changes you will exit the loop.

As it is it will never exit because the value of state never changes.

A switch-type Hall sensor (a.k.a unipolar hall sensor) is more suitable for a speedometer. Instead of analog readings, it returns logical HIGHs or LOWs depending on the presence of a magnetic field. You could then use interrupts to detect the state changes (FALLING or RISING edges). It would make your sketch a lot simpler.

I have a good tutorial here on how to use the while loop:

http://hacking.majenko.co.uk/the-while-loop

Hey guys,

Thanks for the info. I had a suspicion that I needed a latching sensor. Anyways, I learned something along the way, and now I understand a little better how the while() loop works. I'm placing an order for latching hall effect sensors now :slight_smile:

I got the previous bit of code to work, it just is not accurate enough because the signal is really "bouncy" when going from LOW to HIGH, and there is actually a very short duration where the signal is HIGH for a few millis while the magnet is passing by the sensor, which is giving it a false reading of 0 or 1 for the elapsed time, but it does return the correct value for elapsed time when it first changes to HIGH. I'm sure there is a way around this problem, and while I'm waiting for the latching type sensor I would love to try and figure it out.

Any ideas or hints? my modified sketch is below:

int startTime;
int stopTime;
int elapsedTime;
int val;
int state;
int time;
int threshold=520; //sets threshold to 520, this must be calibarated for each sensor


void setup(){
  Serial.begin(9600);
}

void check() {
    val = analogRead(0);
    if(val < threshold) //checks to see if the value is less than the set threshold
      state=LOW;      //this then sets the state to either low or high
    else
      state=HIGH;
}

int getTimeValue() { //if state is HIGH(magnet present) then assign current millis value to time variable and return that value
    check();
    if(state == HIGH) {
      time = millis();
      delay(100);
    }
    return time;
} 
  
  
void loop() {
  
  check();
  
  startTime = getTimeValue(); //if the state is HIGH (magnet is present) assign current millis value to startTime
  

  check(); //checking to see what the state is, HIGH or LOW
  
  while(state == LOW) { //this is the new while() statement that constantly checks for the signal to go HIGH
    check();
  }
  
  check();
  
  stopTime = getTimeValue(); //if it is HIGH again, assign new millis value to stopTime
  
  Serial.println("Elapsed Time: ");
  
  elapsedTime = (stopTime - startTime); // calculate the difference, should give elapsed time
  
  Serial.print(elapsedTime);  
}

Thought I would post again since I have gotten somewhere with this. It now "accurately" reads the elapsed time since the last HIGH value was read, and with this I can now calculate speed, rpm, distance. It still randomly gives a weird negative number for elapsed time, not too often though. Next, I want to be able to store data and be-able to upload it to a database later... but that is a whole other can of worms.

Here's the sketch if you are interested:

float startTime;
float stopTime;
float elapsedTime;
float val;
float state;
float time;
float thresholdHigh=540; //sets threshold to 520, this must be calibarated for each sensor
float thresholdLow=520;


void setup(){
  Serial.begin(9600);
}

void check() {
    val = analogRead(0);
    if(val < thresholdLow) { //checks to see if the value is less than the set threshold
      state=LOW;      //this then sets the state to either low or high
    } else if(val > thresholdHigh) {
      state=HIGH;
    }
}

  
int getTimeValue() { //if state is HIGH(magnet present) then assign current millis value to time variable and return that value
    check();
    while(state == HIGH) { //used a while() loop here to try and stabilize the switch bewteen LOW & HIGH
      time = millis();     //this will only return the value of time when the magnet is no longer present,
      check();             //even with this it still gives a weir negative elapsed time reading every once and a while.
    }
    return time;
} 
  
void loop() {
  
  check();
  
  startTime = getTimeValue(); //if the state is HIGH (magnet is present) assign current millis value to startTime
  

  check(); //checking to see what the state is, HIGH or LOW
  
  while(state == LOW) { //this is the new while() statement that constantly checks for the signal to go HIGH
    check();
  }
  
  check();
  
  stopTime = getTimeValue(); //if it is HIGH again, assign new millis value to stopTime
  
  Serial.print(" Elapsed Time: ");
  
  elapsedTime = (stopTime - startTime); // calculate the difference, should give elapsed time
  
  Serial.println(elapsedTime); 
  Serial.print("Speed FPS: ");
  float speed = (15.70/(elapsedTime/1000))/12;
  if(speed < 0){
   speed = 0;
  } 
  Serial.print(speed);
}

Store your times (that you get from millis()) in unsigned long, not float.