What you have implemented, perhaps unknowingly, is called
hysteresis. Your program spends most of its time in either of these
two states:
- 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.
- 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;
}
}
analogRead(A0)
... that will tell you when it exits the while loop