# How does while(analogRead(A0)) function in this code?

A sine wave is being fed to `A0` and I would like to calculate the frequency. If a certain threshold is crossed, start the timer.....count 5 such crossings.....then stop the timer. The code is attached. Even though I understand `while()` with logical operators such as `while(State<5)` (shown in code), I do not understand the use of `while(analogRead(A0))`. I would like to know how it functions in relation the code? The program runs fine as it is. Tested this in Tinkercad, and got erroneous readings when `while(analogRead(A0))` was commented. Thank you so much for reading my question ^_^.

``````void loop()
{

while(State<5)
{
if(val>200)
{
Serial.println("Threshold Crossed");
if(State==0)
{
Start_Time=millis();
}
State++;
while(analogRead(A0)); //I DON'T UNDERSTAND THIS
}
}

End_Time=millis();

Period=(Start_Time-End_Time)/5;
Frequency=1000/(Start_Time-End_Time)
Serial.println(Frequency);

State=0;
}
``````
• print the value of `analogRead(A0)` ... that will tell you when it exits the while loop Aug 6, 2021 at 6:27
• Can you fix the indentation of the code? Aug 6, 2021 at 20:48
• Re "A sine wave is being fed to A0": What is its amplitude and DC offset? What is the output impedance of the signal generator (what kind of signal generator is it)? How is it coupled? AC coupled? Aug 6, 2021 at 21:08

As you correctly note, `while` typically takes a bool as argument. However, mainly for historical reasons, C/C++ don't really differentiate between int and bool, and therefore conditions can be of integer type. Any condition, be it in a `while` or an `if`, can be of int type. The condition evaluates to true if it is not zero. So the condition `while(analogRead(A0));` loops (doing nothing) until `analogRead` returns 0.

• I think I get this now, this line just works as some sort of delay. Without while(analogRead(A0)), just after the first threshold is crossed (say val is now 202), state becomes +1 and the program loops to "val=analogRead(A0)" again. The val is now 210, so state will get incremented again.........and until state>5, val probably reaches upto 250. This will certainly give the wrong time period. On the other hand while(analogRead(A0)) keeps looping until false (0), gives enough time for val to cross threshold and then become less than threshold, so that the crossing can be detected again. Thanks! Aug 6, 2021 at 7:20
• @Nawaz Not a delay, rather a “keep checking the value until it’s what I’m looking for”. It has nothing to do with time, but value. Aug 6, 2021 at 13:03
• Yes, but analogRead() may never return identical 0 (an offset of 20 mV would prevent it). Or only occasionally due to random noise. This is the equivalent to comparing floats with fixed values. Perhaps address that in your answer? Aug 6, 2021 at 20:58

What you have implemented, perhaps unknowingly, is called hysteresis. Your program spends most of its time in either of these two states:

1. It is continually running the outer `while` loop, and the value read is ≤ 200. It gets out of this state as soon as it reads a value larger than 200.
2. It is continually running the inner `while` loop, and the value read is > 0. It gets out of this state only when `analogRead()` returns zero.

Hysteresis is a good way to reject noise when you want to detect a signal crossing a threshold. I would, however, recommend you use it in a more controlled manner. Specifically, the second threshold should probably be greater than zero, otherwise it won't be crossed unless the signal goes all the way down to ground level. At a minimum, you can replace the inner `while` loop with something like:

``````while (analogRead(A0) >= 100)
/* wait until the signal gets low enough */;
``````

For the record, this logic can be implemented in a non-blocking fashion, which would let the program do other things, like responding to button presses, while waiting for the transitions. For this, you need a variable to record the current state of the signal (say, `LOW` or `HIGH`) and record the state changes when the corresponding thresholds are crossed.

The sketch below implements this non-blocking technique in `loop()`, whereas `setup()` does block while waiting for the first `LOW``HIGH` transition:

``````const int LOW_THRESHOLD  = 100;
const int HIGH_THRESHOLD = 200;

uint8_t state;      // either LOW or HIGH
uint8_t count = 0;  // count the LOW -> HIGH transitions
uint32_t start_time;

void setup() {
// Wait for the first LOW -> HIGH transition.
while (analogRead(A0) >= LOW_THRESHOLD)
/* Wait for the LOW state. */;
while (analogRead(A0) < HIGH_THRESHOLD)
/* Wait for the HIGH state. */;
state = HIGH;

// Record transition time.
start_time = millis();
}

void loop() {
// Record transitions.
uint8_t val = analogRead(A0);
if (state == HIGH && val < LOW_THRESHOLD) {
state = LOW;
} else if (state == LOW && val >= HIGH_THRESHOLD) {
state = HIGH;
++count;
}

if (count >= 5) {
// Report measured frequency.
uint32_t end_time = millis();
int frequency = 1000 * count / (end_time - start_time);
Serial.println(frequency);

// Prepare for the next round.
start_time = end_time;
count = 0;
}
}
``````
• Re "Specifically, the second threshold should probably be greater than zero, otherwise it won't be crossed unless the signal goes all the way down to ground level.". Indeed. And perhaps add a more general statement about comparing for equality (with fixed values) for such ADC output (noise, rate of change of the input signal, etc.)? Aug 6, 2021 at 21:11
• @PeterMortensen: This is generally quite relevant. However, the reasons why one should normally not compare an ADC value for equality do not quite apply to the special case of comparing to zero. Aug 6, 2021 at 22:27