LED is HIGH if analogValue reached 500 5 times in 10 seconds. How?

I am trying to turn ON the LED if the value from potentiometer reached greater than 500 5 times in 10 seconds. Its been a week and i am stuck on this project. What i am trying to do is too difficult for beginner?

Demonstration: https://wokwi.com/arduino/projects/317517042178589250

So far this is my code.

const int ledPin = 2;
const int analogPin = A0;
int PeakCount = 0;
int lastPeakValue;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int peakValue = analogRead(analogPin);

  if (lastPeakValue < 500 && peakValue >= 500) {
    PeakCount++;
    Serial.print("Bark !  (");
    Serial.print(PeakCount);
    Serial.println(")");
  }
  lastPeakValue = peakValue;

  delay(100);
}

Not much work for a weeks worth of coding. Here is one general idea of how do to the do thing.



unsigned long CountMeasureTimeTotal = 10000;
unsigned long MeasureTime = millis();
int PeakValueTrigger = 500;

void setup()
{
  
}

void loop()
{
  int peakValue = analogRead( analogPin);

  if ( (peakValue > PeakValueTrigger) && CountStarted == false )
  {
    PeakCount++;
    CountStarted = true;
    CountMeasureTime = millis();
  }

  if ( (peakValue >= PeakValueTrigger) && CountStarted )
  {
    if ( ((millis() - MeasureTime) < CountMeasureTimeTotal) && CountStarted )
    {
      PeakCount++;
      //collect the measurements whiles the time has not expired
    }
  }
    if ( ((millis() - MeasureTime) >= CountMeasureTimeTotal) && CountStarted )
    {
      // stop the count when measurement time expires
      CountStarted = false;
    } 
}

Oops

1 Like

I think you'll have to store the last four times the analog value went over 500.

You can use an array of unsigned longs

unsigned long eventTime[4];

and when you get an new event, see if the previous four were all within ten seconds.

unsigned long thisTime = millis();

and loop over the four stored times to see if they are within 10000 milliseconds of thisTime.

If so, do your dance of success or whatever.

If not, throw away the oldest recorded time (lowest value of millis()) and store in the place that frees up on the array with the new thisTime.

Typically "throwing away the oldest" in a case like this is done with a circular or ring buffer.

Or you could just look through the array for the oldest time (smallest value) and use that index where you found the oldest to stash the new time.

So some googling terms for you

arrays in C/C++
Arduino millis()
ring buffer

Also, stay tuned, as I am hoping I have overlooked the obviouser solution that would be way simpler.

No, not too difficult for beginner, but not a trivial problem either.

a7

There was another similar topic, in which @J-M-L mentioned a barking dog :dog: All replies together already showed how it should be done. I made a very basic start with this sketch and made a Wokwi project for it. That project is copied by @faqeerdankgerm but the header was removed.

@Idahowalker's code in #N, with as much time as I have right now: (beach beckons…)

It needed the one thing the OP had going for it - a kind of denouncing for the trigger on the pot reading.

And a few other dets. Still doesn't reset, and won't see some things that you might think would pass the test.

I replaced the pot with a switch; easier to manipulate in the sim.

HTH

a7

const int LEDPin = 2;
const int AnalogPin = A0;

const int PeakValue = 500;
const byte MaxPeakCount = 5;
const unsigned long Interval = 10000;

unsigned long Timestamps[MaxPeakCount];
int TimestampIndex = 0;

void setup()
{
  digitalWrite(LEDPin, LOW);
  pinMode(LEDPin, OUTPUT);
}

void loop()
{
  static int lastValue = 0;
  int value = analogRead( AnalogPin);

  if (lastValue < PeakValue && value >= PeakValue)
  {
    unsigned long timestamp = millis();
    lastValue = value;

    // Keep a circular buffer of the last "MaxPeekCount" timestamps.
    Timestamps[TimestampIndex++] = timestamp;
    if (TimestampIndex >= MaxPeakCount)
      TimestampIndex = 0;

    // If the oldest timestamp was less than 'Interval' ago
    unsigned long oldestTimestamp = Timestamps[TimestampIndex];
    if (oldestTimestamp != 0 && millis() - oldestTimestamp < Interval)
      digitalWrite(LEDPin, HIGH);
    else
      digitalWrite(LEDPin, LOW);
  }

  delay( 100);
}

:clap:

next stop wokwi.

OK, the only substatnive change necessary to @johnwasser' code (in my test) was to move the update to the mechanism that deglitches the analog read, viz:

lastValue = value;

to after the if block it is currently in.

I took the logic from the OP's code. :wink:

The delay can be reduced from 100 ms to improve response. Yes the dleay can be eliminated.

a7

That is a practically useless measurement. It is too dependent on the number of samples you take in 10 seconds. If I took 100 samples in 10 seconds and they were all over the threshold, it would not trigger. If I took 100,000 samples of a noisy signal in 10 seconds, it might accumulate 500 in the first second, if there was a short burst of 500 readings over the threshold. It is meaningless.

I am playing further with code from #7. I think the thing that checks for 5 times in 10 seconds has to go outside the if block it is in now, or the code, this:

      // If the oldest timestamp was less than 'Interval' ago
    unsigned long oldestTimestamp = Timestamps[TimestampIndex];
    if (oldestTimestamp != 0 && millis() - oldestTimestamp < Interval)
      digitalWrite(LEDPin, HIGH);
    else
      digitalWrite(LEDPin, LOW);

that turns off the light does not get executed if no analog value change counts. It should self-extinguish itself ten seconds after the event that made it go on absent any triggers from the abalog input.

a7

I agree.

I agree.

Here is a new take:

const int LEDPin = 2;
const int AnalogPin = A0;

const int PeakValue = 500;
const byte MaxPeakCount = 5;
const unsigned long Interval = 10000;

unsigned long Timestamps[MaxPeakCount];
int TimestampIndex = 0;

void setup()
{
  digitalWrite(LEDPin, LOW);
  pinMode(LEDPin, OUTPUT);
}

void loop()
{
  static int lastValue = 0;
  int value = analogRead(AnalogPin);

  if (lastValue < PeakValue && value >= PeakValue)
  {
    unsigned long timestamp = millis();

    // Keep a circular buffer of the last "MaxPeekCount" timestamps.
    Timestamps[TimestampIndex++] = timestamp;
    if (TimestampIndex >= MaxPeakCount)
      TimestampIndex = 0;
  }

  lastValue = value;

  // If the oldest timestamp was less than 'Interval' ago
  unsigned long oldestTimestamp = Timestamps[TimestampIndex];
  if (oldestTimestamp != 0 && millis() - oldestTimestamp < Interval)
    digitalWrite(LEDPin, HIGH);
  else
    digitalWrite(LEDPin, LOW);

  // Add a delay to roughly limit the sample rate to under 100 per Interval.
  delay(Interval / 100);
}

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