why does my WHILE not work?

This should be easy…but I just don’t know why my WHILE commands in the program don’t work. The US sensor is sensing all the time and when I point it close to something (using test numbers) , it should say “near lane”, and point it far, the LCD should display NO TRAFFIC. It displays nothing. I put a Serial print statement in the WHILE but it DOES NOT PRINT the statement.

Yet, if I replace WHILE with IF, it works. (I want WHILE so that the display doesn’t change “while” the sensor is still reporting within the range specified.) I’ve used WHILE in other sketches where it works okay, so is there a problem in my MAP function or my InRange function? (Like I said, works with IF).

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LcdBarGraphRobojax.h>
//byte lcdNumCols=20;//need for BarGraph library
//byte lcdLine=4;//need for BarGraph library
bool OFF = HIGH; //leds are common anode, current sink (LOW) turns them on.
bool ON = LOW;
//int pulseW;
int scaleFactor = 147; //scale Factor of MB 7067 is 58 uS/cm or 147 uS/inch
//float duration;
//float voltage;
//const int pwPin = 2;
// int anPin =A0;
//int count=0;
int inches;
int outMax=301;//max output of Maxbotix sensor is 301 inches
int sensorMax=696;//derived from actual value 3.4.  3.4/5*1024
const byte ledBlue =    8;  //motorcycle LED
//const byte ledCar =      9;  //car
const byte ledGreen =     10;  //SUV
//const byte ledPickup =  11;  //pickup
const byte ledRed =     12;  //bus
byte ledPins[] = {8, 9, 10, 11, 12};
int countSouth=0;
int countNorth=0;
byte threshold=5;//threshold before a detection changes.
LiquidCrystal_I2C lcd(0x27, 20, 4); 

/******************  Setup  ********************/
void setup()
{ for ( byte x = 0; x < 5; x++ )//make 5 LED pins all outputs
  { pinMode( ledPins[x], OUTPUT );
    digitalWrite(ledPins[x], OFF);}
    
  Serial.begin(115200);
  Wire.begin(); // start I2C
  lcd.begin(20, 4);
  lcd.backlight();
 //  pinMode(pwPin, INPUT);//not used at this time.
  pinMode(A0, INPUT);
}
/****************Function inRange****************/
byte inRange (int val,  int minimum, int maximum)
{  return ((minimum <= val) && (val <= maximum));}

/******************  Loop  ********************/
void loop()
{
  //pulseW = pulseIn(pwPin, HIGH); //get pulse duration
  //int inVal = pulseW;
  int inVal=analogRead(A0);
  inches= map(inVal, 0, sensorMax, 0, outMax);//sensorMax=value in 10 bits, OutMax: max of sensor,301 inches
  
 /****************Near Lane******************/
  // if (inRange(inches, 120, 216))//10 to 18 feet roughly center of near lane
  while (inRange(inches, 12, 21))//test value
  { digitalWrite (ledBlue, ON); //BLUE
    countSouth++;
    Serial.print("doing the while for Near Lane");
  }
    lcd.setCursor(0, 1);
    lcd.print("NEAR LANE    ");
    delay(200);
    digitalWrite (ledBlue, OFF);
   // lcd.setCursor (12,1);
    //lcd.print(countSouth);  
       
 /***************Far Lane******************/    
 // else if(inRange(inches, 240, 276))//20-23 feet roughly center of far lane
  while (inRange(inches, 24, 40))//test value
  { digitalWrite (ledGreen, ON); //GREEN
    countNorth++;
    Serial.print("doing the while for Far Lane");
  }
    lcd.setCursor(0, 2);
    lcd.print("FAR LANE     ");
    delay(200);
    digitalWrite (ledGreen, OFF);
    //lcd.setCursor (12,2);
    //lcd.print(countNorth);
    
/******************No Traffic*******************/  
    // if(inches>288)//real value ? 24 feet
    while (inches >48)//test value
    { digitalWrite (ledRed, ON); //RED
      lcd.setCursor(0, 3);
      lcd.print("NO TRAFFIC     ");
     // delay(500);
      digitalWrite (ledRed, OFF);
    
  }}
  while (inRange(inches, 12, 21))//test value
  { digitalWrite (ledBlue, ON); //BLUE
    countSouth++;
    Serial.print("doing the while for Near Lane");
  }

How do you expect to EVER get out of that while loop, when the condition variable, presumably "inches", is never changed in the loop?

Regards,
Ray L.

Easy…it changes when I move the sensor around. Point at the floor, that’s within the range where it should print “near lane”.

Point at the wall, that’s far lane, and point at nothing or turn on its face gives me the max reading of 301 inches.

It DOES change and I’ve seen it change, but as I add other commands to do other stuff (like count), I end up with something not working.

As I was writing this and going back to see what I did, I made a few changes and now I seem to have something working here. See screenprint. Nearlane was the floor, Farlane was the wall.

Now I can work on counting each.

ScreenHunter 1034.jpg

What @RayLivingston said.

I made a few changes

Which we can’t see.

RayLivingston:

  while (inRange(inches, 12, 21))//test value

{ digitalWrite (ledBlue, ON); //BLUE
    countSouth++;
    Serial.print("doing the while for Near Lane");
  }




How do you expect to EVER get out of that while loop, when the condition variable, presumably "inches", is never changed in the loop?

Regards,
Ray L.

I agree 100%, but the OP says that the Serial.print() never prints, so 'inches' is not in range to be true.

Here’s something else I noticed.

This function should be returning a bool, not a byte. OK, byte will work but a bool is more readable.

/****************Function inRange****************/
byte inRange (int val,  int minimum, int maximum)
{  return ((minimum <= val) && (val <= maximum));}

Zero = true, anything else is false.

But unless you print the value of inches before you test it, you don’t know if the while is ever executed.

Here’s my latest iteration of this program. I must be at about 400 compiles and downloads by now…

My Maxbotix sensor is pulsing at about 10x/second, and returning a value, a pulse-width I can monitor on my scope. Close: short width (157uS/inch), open air (or totally blocked) gives me max pulse width of 44 mS. I was using the pulse width output (more precise) but I don’t need precision, I just need to know if a vehicle is in range, that is in near lane or far lane, so I’m using the analog output of the device (A0).

I know that putting a { or } in the wrong place totally screws up the logic without showing any error and I think that’s my problem. Mr. Spock would not be happy with me.

I’ve also attached a screen print of the output as I move it through space: floor, far wall, and open, the three conditions. Since last entry I moved the last condition to a function at bottom of program, so I only have to deal with two conditions and count each time. Since the sensor is pulsing 10x/second I have to grab a value, ignore further pulses UNTIL the sensor sees a different value (vehicle moved out of way, or one appears in other lane), then it counts that event.

The Serial.print statements are for testing only, as is the delays. The LEDs work as expected. The screenprint shows all kinds of counts when what I really want is it reflect how I moved the sensor: floor, wall, open space: 2 counts (since I don’t count when there is no blocking object).

#include <Wire.h>
  #include <LiquidCrystal_I2C.h>
  #include <LcdBarGraphRobojax.h>
  //byte lcdNumCols=20;//need for BarGraph library
  //byte lcdLine=4;//need for BarGraph library
  bool OFF = HIGH; //leds are common anode, current sink (LOW) turns them on.
  bool ON = LOW;
  //int pulseW;
  int scaleFactor = 147; //scale Factor of MB 7067 is 58 uS/cm or 147 uS/inch
  int currReading = 0;
  int currReading1 = 0;
  int prevReading1 = 0;
  int currReading2 = 0;
  int prevReading2 = 0;
  int countSouth = 0;
  int countNorth = 0;
  byte threshold = 3; //threshold before a detection changes.
  //int inches;
  int outMax = 301; //max output of Maxbotix sensor is 301 inches
  int sensorMax = 696; //derived from actual value 3.4.  3.4/5*1024
  const byte ledBlue =    8;  //motorcycle LED
  //const byte ledCar =      9;  //car
  const byte ledGreen =     10;  //SUV
  //const byte ledPickup =  11;  //pickup
  const byte ledRed =     12;  //bus
  byte ledPins[] = {8, 9, 10, 11, 12};
  
  LiquidCrystal_I2C lcd(0x27, 20, 4);
  
  /******************  Setup  ********************/
  void setup()
  { for ( byte x = 0; x < 5; x++ )//make 5 LED pins all outputs
    { pinMode( ledPins[x], OUTPUT );
      digitalWrite(ledPins[x], OFF);
    }
  
    Serial.begin(115200);
    Wire.begin(); // start I2C
    lcd.begin(20, 4);
    lcd.backlight();
    //  pinMode(pwPin, INPUT);//not used at this time.
    pinMode(A0, INPUT);
  }
  /****************Function inRange****************/
  bool inRange (int val,  int minimum, int maximum)
  {
    return ((minimum <= val) && (val <= maximum));
  }
  
  /******************  Loop  ********************/
  void loop()
  {
    int inVal = analogRead(A0);
    currReading = map(inVal, 0, sensorMax, 0, outMax); //sensorMax=value in 10 bits, OutMax: max of sensor,301 currReading
  
    /****************Near Lane*****************/
    // if (inRange(currReading, 120, 216))//10 to 18 feet roughly center of near lane
    currReading1 = currReading;
    if (currReading > 48)//if reading is >48, then sensor is not blocked: no bounce-back
    {
      NoTraffic();
    }
  
    { while (inRange(currReading1, 12, 21))//test values
      { if (prevReading1 != currReading1)
        { Serial.print("Near Lane  ");
          Serial.print(currReading1);
          digitalWrite (ledBlue, ON);
        }
        break;
      }
      countSouth++;
      Serial.print("   count  ");
      Serial.println(countSouth);
      prevReading1 = currReading1;
      delay(500);
      digitalWrite (ledBlue, OFF);
  
      /***************Far Lane******************/
      // else if(inRange(currReading, 240, 276))//20-23 feet roughly center of far lane
      currReading2 = currReading;
      while (inRange(currReading2, 24, 40))//test values
      { Serial.print("Far Lane  ");
        Serial.println (currReading2);
        digitalWrite(ledGreen, ON);
        break;
      }
      countNorth++;
      Serial.print("   count  ");
      Serial.println(countNorth);
      prevReading2 = currReading2;
      delay(500);
      digitalWrite (ledGreen, OFF);
    }
  }
  /******************Function No Traffic******************/
  // if(currReading>288)//real value ? 24 feet
  void NoTraffic()
  //if (currReading > 48) //test value
  { digitalWrite (ledRed, ON); //RED
    Serial.print("No traffic  ");
    Serial.println (currReading);
    delay(500);
    digitalWrite (ledRed, OFF);
  }

ScreenHunter 1037.jpg

I think I got it. Replaced the WHILE with IF instead. I had iF before in other sketches but I didn’t have the state tests in place (plus other issues).

The program seems to work as I intended it to.
Here it is. Comments on how to improve are welcome. I come from Assembler and Basic…C++ is still not easy.

/****************Function inRange****************/
bool inRange (int val,  int minimum, int maximum)
{
  return ((minimum <= val) && (val <= maximum));
}

/******************  Loop  ********************/
void loop()
{ int inVal = analogRead(A0);
  currReading = map(inVal, 0, sensorMax, 0, outMax);
  if (currReading > 48)//if reading is >48, then sensor is not blocked: no traffic
  { NoTraffic();
  }
  /****************Near Lane*****************/
  { currReading1 = currReading;
    if (inRange(currReading1, 12, 21))//test values
    { if (prevReading1 != currReading1)
      { digitalWrite (ledBlue, ON);
        countNearLane++;
        Serial.print("Count Near Lane  ");
        Serial.println(countNearLane);
      }
      prevReading1 = currReading1;
      delay(500);
      digitalWrite (ledBlue, OFF);
    }
    else

      /***************Far Lane******************/
      currReading2 = currReading;
      (inRange(currReading2, 24, 40));//test values
    { if (prevReading2 != currReading2)
      { digitalWrite(ledGreen, ON);
        countFarLane++;
        Serial.print("Count Far Lane  ");
        Serial.println(countFarLane);
      }
      prevReading2 = currReading2;
      delay(500);
      digitalWrite (ledGreen, OFF);
    }
  }
}
/******************Function No Traffic******************/
void NoTraffic()
//if (currReading > 48) //test value
{ digitalWrite (ledRed, ON); //RED
  Serial.print("No traffic  ");
  Serial.println (currReading);
  delay(500);
  digitalWrite (ledRed, OFF);
}

This is all wrong.

      (inRange(currReading2, 24, 40));//test values
    { if (prevReading2 != currReading2)
      { digitalWrite(ledGreen, ON);

The first line does nothing. The second one should not begin with a { bracket. I stopped looking after that...

If you have really programmed in Basic and Assembler, you should have no problem understanding the C documentation. I suggest you spend some time there.

queenidog:
I know that putting a { or } in the wrong place totally screws up the logic without showing any error and I think that's my problem. Mr. Spock would not be happy with me.

Generally, you can put in a lot of extra {} pairs, just as long as they are matching pairs.

TIP: Use CTRL-T. If you have a program that just won't compile and the error message doesn't help, do a CTRL-T then scan your sketch to look for two closing braces at the same indent level.

 void (myFunction){
    //Do stuff
  }
}
}

This example shows that there is a mismatch of braces.

Why is it “all wrong”. Pretty sweeping statement considering you pointed out only one line.

I kept getting errors “else without if” so I took the IF out and it worked. In Basic, we would delineate IF statements with IF-THEN-ELSE and I think a RETURN at the end. No syntax, just words.

I check brackets continuously. It’s good that the IDE highlights the pair so it is EASY to find them. The issue is when I have an IF statement what goes in between the brackets. It’s a logic problem.

The program WORKS except, I used delay functions so I could see the changes on the monitor. I had intention to remove them and now since I have…the program does not work. Now, although it detects changes in distance, it counts every pulse back and forth…at 10x/second.

I think I know what to do. Put in some flags to stop it from anymore sensing.

Steve Mann, thank you for a useful reply.

No syntax, just words.

Words in a particular order == syntax.