PhippsTech
PhippsTech

Reputation: 23

Breaking a While loop C++

I have a quick question and I think that a more experienced firmware developer will be able to help me out with. So the main goal I have with this code is:

  1. Run a loop (detect) that will "listen" for something to happen and then increment a variable (voltscount in this case) once that threshold is hit. Once voltscount is hit twice within a specified time, the 1st while loop inside of the sampling loop will listen more closely (via a FFT).

  2. I want to then break out of the while loop (stop listening with the FFT) when the threshold in the detect loop isn't hit in a certain time period (3 secs in this example).

Number 1 is achieve but I'm having trouble with number 2. The code seems to remain in the 1st while loop inside of sampling (the serial window keeps displaying the FFT values instead of 0,1 or 2 -voltscount value) well after 3 sec of that volts threshold remaining below 4.8.

I didn't include my void setup and all that jazz, let me know if that is needed in order to answer my question.

void loop(){
  detect();
  sampling();

}
void detect(){
   unsigned long startMillis= millis();  // Start of sample window

   unsigned int peakToPeak = 0;   // peak-to-peak level

   unsigned int signalMax = 0;
   unsigned int signalMin = 1024;

   // collect data for 50 mS
   while (millis() - startMillis < sampleWindow)
   {
      sample = analogRead(0);
      if (sample < 1024)  // toss out spurious readings
      {
         if (sample > signalMax)
         {
            signalMax = sample;  // save just the max levels
         }
         else if (sample < signalMin)
         {
            signalMin = sample;  // save just the min levels
         }
      }
   }
   peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
   volts = (peakToPeak * 5.0) / 1024;  // convert to volts
 Serial.println(voltscount);
}

void sampling(){
unsigned long currentMillis = millis();

if(volts >=4.8){
  voltscount++;

  previousMillis = millis();
}
while(voltscount >= 2){
    /////SAMPLING
    for(int i=0; i<samples; i++)
    {
        microseconds = micros();    /* Overflows after around 70 minutes! */
        vReal[i] = analogRead(0);
        vImag[i] = 0;
        while(micros() < (microseconds + sampling_period_us)){
        }
    }
  double x;
  double v;
  FFT.MajorPeak(vReal, samples, samplingFrequency, &x, &v);
  Serial.print(x, 0);
  Serial.print(", ");
  Serial.println(v, 0);
  delay(10); /* Repeat after delay */ 
/* 
// 3 tests for smoke detector chirps and code to light up the LEDs

    if (x > 4000 and x < 4900 and v > 80) {
        digitalWrite(blueLEDpin, HIGH);
        digitalWrite(uvLEDpin, HIGH);
        delay(blueLEDdelay);
        digitalWrite(blueLEDpin, LOW);
        delay(uvLEDdelay);
        digitalWrite(uvLEDpin, LOW);
    }

    if (x > 1700 and x < 1800 and v > 40) {
        digitalWrite(blueLEDpin, HIGH);
        digitalWrite(uvLEDpin, HIGH);
        delay(blueLEDdelay);
        digitalWrite(blueLEDpin, LOW);
        delay(uvLEDdelay);
        digitalWrite(uvLEDpin, LOW);
    }
*/
    if (v > 1400) {
        digitalWrite(blueLEDpin, HIGH);
        digitalWrite(uvLEDpin, HIGH);
        delay(blueLEDdelay);
        digitalWrite(blueLEDpin, LOW);
        delay(uvLEDdelay);
        digitalWrite(uvLEDpin, LOW);
    }
  if (currentMillis - previousMillis > 3000){
  voltscount = 0;
  break;
  }

 }

}


Upvotes: 0

Views: 291

Answers (2)

datafiddler
datafiddler

Reputation: 1835

In Arduino programming, most beginner's while loops are simply wrong. Especially, if you feel the need to break them somehow. The Arduino environment provides a loop() function prototype, which you should use properly.

Typically, any while() {...} can be replaced by an if() {...}, which is called again in the next loop() run. Sometimes, you need a few more state variables, but the important change is to follow the paradigm that loop() should not take noticeable time to run and should not describe sequential actions by listing them one after the other in loop(). The basic BlinkWithoutDelay sample applies everywhere, not only to blinking. The important part is not only calling millis(), but keeping the state of your sketch in appropriate variables (like those previousmillis)

Upvotes: 0

Destructor
Destructor

Reputation: 523

Assume the state where voltscount is 1. You enter sampling(). You first set the current mills to the current time. Assume it's 1000 (Hypothetical since I don't know what that function returns). Then since your volts is greater than 4.8 you increment voltscount to 2. And you set the previousMillis to something like 1500 because millis() is called for the second time. Then you enter the first while loop and at the end of it, you check if currentMillis - previousMillis > 3000. But this is never true since previouslMillis have a greater value than currentMillis. I guess what you could do is to read the currentmillis right before you check if the difference is greater than 3000.

if (millis() - previousMillis > 3000){
  voltscount = 0;
  break;
}

Upvotes: 1

Related Questions