Stuck in a loop

So, i have connected to my arduino uno, a carbon monoxide sensor, an lcd screen, an active buzer, an rgb led and a push button with a pull-down. in my code, when the sensor detects more than 10 ppm, as long as there is more than 10 ppm, it enters a loop which makes the buzer sound. However, when it enters this loop, it doesn't exit even if the value is less than the condition ... Here is my code:

float RS_gas;
float ratio;
float sensorValue;
float sensor_volt;
float R0 = 37384;
int repeat = 0;
int heattime = 0;

//pin on the Arduino
int red = 9;
int green = 10;
int blue = 11;
int heatOFF = 8;
int bp = 12;
//------------------

#include <LiquidCrystal.h>

const int rs = 2, en = 13, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("Carbon Monoxide");
  lcd.setCursor(0, 2);
  lcd.print("Detector");
  delay(2500);
  lcd.clear();
  lcd.setCursor(1, 1);
  Serial.begin(9600);
  pinMode(heatOFF, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(bp, INPUT);
  tone(3, 550, 100);
  delay(200);
  tone(3, 550, 100);
}

void loop()
{
  while (heattime <= 6000 && digitalRead(12) == LOW)
  {
    lcd.clear();
    lcd.print("Heating...");
    digitalWrite(heatOFF, LOW);
    digitalWrite(red, HIGH);
    digitalWrite(green, LOW);
    digitalWrite(blue, LOW);
    heattime += 1;
    delay(10);
  }
  if (digitalRead(bp) == HIGH)
  {
    lcd.clear();
    lcd.print("Bypass heating");
    delay(1000);
    lcd.clear();
  }

  heattime = 0;
  digitalWrite(heatOFF, HIGH);
  digitalWrite(red, LOW);
  digitalWrite(green, HIGH);
  digitalWrite(blue, LOW);
  lcd.clear();
  lcd.print("Reading...");
  delay(1500);
  tone(3, 400, 100);

  while (repeat <= 180)
  {
    lcd.clear();
    sensorValue = analogRead(A0);
    sensor_volt = sensorValue / 1024 * 5.0;
    RS_gas = (5.0 - sensor_volt) / sensor_volt;
    ratio = RS_gas / R0; //Replace R0 with the value found using the sketch above
    float x = 1538.46 * ratio;
    float ppm = pow(x, -1.709);
    lcd.print("PPM: ");
    lcd.print(ppm);
    while (ppm >= 10 && ppm < 25)
    {
      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0;
      float x = 1538.46 * ratio;
      float ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      digitalWrite(red, HIGH);
      analogWrite(green, 100);
      tone(3, 600, 100);
      delay(300);
      digitalWrite(red, LOW);
      digitalWrite(green, LOW);
      delay(300);
    }
    while (ppm >= 25 && ppm < 50)
    {
      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0;
      float x = 1538.46 * ratio;
      float ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      digitalWrite(red, HIGH);
      analogWrite(green, 30);
      tone(3, 600, 100);
      delay(200);
      digitalWrite(red, LOW);
      digitalWrite(green, LOW);
      delay(200);
    }
    while (ppm >= 50 && ppm < 90)
    {
      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0;
      float x = 1538.46 * ratio;
      float ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      digitalWrite(red, HIGH);
      analogWrite(green, 30);
      tone(3, 600, 100);
      delay(100);
      digitalWrite(red, LOW);
      digitalWrite(green, LOW);
      delay(100);
    }
    while (ppm >= 90 && ppm < 1000)
    {
      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0;
      float x = 1538.46 * ratio;
      float ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      digitalWrite(red, HIGH);
      digitalWrite(green, LOW);
      tone(3, 800, 100);
      delay(100);
      digitalWrite(red, LOW);
      digitalWrite(green, LOW);
      delay(100);
    }
    while (ppm >= 1000)
    {
      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0;
      float x = 1538.46 * ratio;
      float ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      digitalWrite(red, HIGH);
      digitalWrite(green, LOW);
      tone(3, 600, 100);
      delay(100);
      tone(3, 800, 100);
      analogWrite(green, 85);
      delay(100);
    }

    digitalWrite(red, LOW);
    digitalWrite(green, HIGH);
    repeat += 1;
    delay(500);

  }
  lcd.clear();
  repeat = 0;
}

and here is the schematics :

float ppm = pow(x, -1.709);you have that inside the while loop.
Lose the word "float"

Every time you do that, you're creating a new variable, but one where the scope of the variable is limited to within the loop's enclosing braces.

A much better approach would be to get rid of all those while() loops and just let loop() do what it is designed to do. Read your sensor, determine which state you are in and set your leds accordingly rather than repeat the same code inside multiple while() loops. Something like this:

unsigned long heatStartTime;
const unsigned long heatDuration = 6000UL;  // msec

unsigned long readingStartTime;
const unsigned long readingDuration = 90000UL;

//pin on the Arduino
const int tonePin = 3;
const int red = 9;
const int green = 10;
const int blue = 11;
const int heatOFF = 8;
const int bp = 12;
//------------------

#include <LiquidCrystal.h>

const int rs = 2, en = 13, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("Carbon Monoxide");
  lcd.setCursor(0, 2);
  lcd.print("Detector");
  delay(2500);
  lcd.clear();
  lcd.setCursor(1, 1);
  Serial.begin(9600);
  pinMode(heatOFF, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(bp, INPUT);
  tone(tonePin, 550, 100);
  delay(200);
  tone(tonePin, 550, 100);
}

enum { HEAT_START, HEATING, READING_START, READING, DONE };
int state;

void loop()
{
  float RS_gas;
  float ratio;
  int sensorValue;
  float sensor_volt;
  const float R0 = 37384.0;
  float x;
  float ppm;

  switch ( state ) {

    case HEAT_START:  // begin the heating portion, one-time only
      lcd.clear();
      lcd.print("Heating...");
      digitalWrite(heatOFF, LOW);
      digitalWrite(red, HIGH);
      digitalWrite(green, LOW);
      digitalWrite(blue, LOW);
      state = HEATING;
      heatStartTime = millis();
      break;

    case HEATING: // check if we have heated long enough or bypass requested
      if (millis() - heatStartTime >= heatDuration)
      {
        state = READING_START;
      }
      if (digitalRead(bp) == HIGH)
      {
        lcd.clear();
        lcd.print("Bypass heating");
        delay(1000);
        state = READING_START;
      }
      break;

    case READING_START:   // begin reading portion
      digitalWrite(heatOFF, HIGH);
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
      digitalWrite(blue, LOW);
      lcd.clear();
      lcd.print("Reading...");
      delay(1500);
      tone(tonePin, 400, 100);
      state = READING;
      readingStartTime = millis();
      break;

    case READING: // update readings or done if enough time has elapsed
      if ( millis() - readingStartTime >= readingDuration )
      {
        state = DONE;
      }

      lcd.clear();
      sensorValue = analogRead(A0);
      sensor_volt = sensorValue / 1024.0 * 5.0;
      RS_gas = (5.0 - sensor_volt) / sensor_volt;
      ratio = RS_gas / R0; //Replace R0 with the value found using the sketch above
      x = 1538.46 * ratio;
      ppm = pow(x, -1.709);
      lcd.print("PPM: ");
      lcd.print(ppm);
      if (ppm >= 10 && ppm < 25)
      {
        digitalWrite(red, HIGH);
        analogWrite(green, 100);
        tone(tonePin, 600, 100);
        delay(300);
        digitalWrite(red, LOW);
        digitalWrite(green, LOW);
        delay(300);
      }
      else if (ppm >= 25 && ppm < 50)
      {
        digitalWrite(red, HIGH);
        analogWrite(green, 30);
        tone(tonePin, 600, 100);
        delay(200);
        digitalWrite(red, LOW);
        digitalWrite(green, LOW);
        delay(200);
      }
      else if (ppm >= 50 && ppm < 90)
      {
        digitalWrite(red, HIGH);
        analogWrite(green, 30);
        tone(tonePin, 600, 100);
        delay(100);
        digitalWrite(red, LOW);
        digitalWrite(green, LOW);
        delay(100);
      }
      else if (ppm >= 90 && ppm < 1000)
      {
        digitalWrite(red, HIGH);
        digitalWrite(green, LOW);
        tone(tonePin, 800, 100);
        delay(100);
        digitalWrite(red, LOW);
        digitalWrite(green, LOW);
        delay(100);
      }
      else if (ppm >= 1000)
      {
        digitalWrite(red, HIGH);
        digitalWrite(green, LOW);
        tone(tonePin, 600, 100);
        delay(100);
        tone(tonePin, 800, 100);
        analogWrite(green, 85);
        delay(100);
      }
      else
      {
        digitalWrite(red, LOW);
        digitalWrite(green, HIGH);
      }
      delay(500);
      break;

    case DONE:
      // do any cleanup and start again
      state = HEAT_START;
      break;
  }
}

blh64:
A much better approach would be to get rid of all those while() loops and just let loop() do what it is designed to do.

I agree. While is a bad way to execute a state machine, mostly because it is blocking code. If the state changes, the code might miss it. How you organize your code in loop() is a personal preference. I like to keep my loop() as clean as possible.

In this example, I would just test the various conditions in the loop(), then if any are met, go to a function to handle them.

Pseudo code:

loop(){
  if(condition1) handleCondition1()
  if(condition2) handleCondition2()
  if(condition3) handleCondition3()
etc

ok, thanks !

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.