How to count number of same values?

I am very new to Arduino so hopefully I can explain this well!

My project is small prototype swing which will trigger an irrigation system for garden when in use.
I am using a DC motor as an INPUT for this.

The motor is attached to the swing, and when in motion I receive values between 3 and 40. Since the motor produces a negative voltage when turned the opposite direction I usually receive a short series of 0's. When the swing is stationary I only receive 0's.

While I've been testing the code I've been using an LED as the OUTPUT instead of the water-pump. In my code I've put if the value is greater than 3, then the LED should be turned on.

As I want the LED to turn off when the swing is not in use I wanted to count the number of 0 values I receive until it reaches 200 0's in a row which will turn the LED off. (I'm using 200 as I usually receive 19-21 values per second so I could hypothesise the swing would not be in use after that amount of time)

I was wondering what would be the best method to this? I have tried using a counter but I don't think I've done it correctly. The LED does switch on after receiving a value greater than 3, but wont switch off after receiving 200 0 values in a row?

I'll attach the code below. Thanks in advance :slight_smile:

int val=0;
int ledPin =3;
int motorPin=1; 
void setup() {
    pinMode(A1, INPUT);
    pinMode(ledPin,OUTPUT);
    Serial.begin(9600);
}
 
void loop() {
val = analogRead(A1);   
Serial.println(val);

if (val > 3) {
digitalWrite(ledPin, HIGH);
}

else { val=0;
}

if (analogRead(motorPin) <3) {
  val+=1; 
}

if (val == 200) {
  digitalWrite(ledPin, LOW);
}
}

Unfortunately you can destroy the analog input if the motor voltage exceeds 5V (for a 5V Arduino, 3.3V for a 3.3V Arduino) or is below 0V (negative). You need to protect the input with a simple circuit, something like this one:

R1 and R2 make sure that the input voltage is positive when the motor shaft is not rotating. The analog reading will be above or below the midpoint, depending on the direction of shaft rotation.

It is still possible to have too high or negative input voltages, but R3 protects the input from excessive current flow.

it's not obvious to me what is being measured on pins 1 and A1

You can't use 'val' for the analog input value AND use it to count the number of times 'val' is zero. Use a separate variable for the count.

Your method sounds a little odd to me. If you just want to establish that the swing has been inactive for some interval, the normal way would be to (optionally) low pass filter (average) the values to reduce noise, then update a time stamp every time the threshold for an active swing is detected. Separately, any comparison between now and the time stamp, will indicate how long it has been inactive.

To me, this is more derivative of your actual problem, more intuitive and straightforward than taking counts of values.

uint32_t zero_count = 0;

void check_motor_input()
{
  if( input == 0 )
    if(zero_count < 200) ++zero_count;
  else
    zero_count = 0;
}

Basically keep a global counter, if you get a zero coming in increment that counter, if you read something else reset it to 0. Then you can just test if that counter is >= 200 for whatever condition you need.

1 Like

First, as said, to prevent damage to the Arduino, it is necessary to get the input voltage issue worked. Eliminate the negative voltages and keep voltages below 5V.

As also said, You can't use one variable, val for both the analog reading and a count of those readings which are <=3.

When make a count of the readings it would be best to compare the current reading to the last one you got.

As I want the LED to turn off when the swing is not in use I wanted to count the number of 0 values I receive until it reaches 200 0's in a row which will turn the LED off. (I'm using 200 as I usually receive 19-21 values per second so I could hypothesise the swing would not be in use after that amount of time)

If you perform the analog readings with a fixed time period, you can achieve the 200 counts and 20 seconds if you read every 100ms.

int val = 0;
int previousVal = 0;
const byte threshold = 3;
int ledPin = 13;
int motorPin = A1;
unsigned int count;
boolean countingLows = false;

void setup() {
  //pinMode(A1, INPUT);//pinMode not required for analogRead()
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {  
  static unsigned long lastReading = 0;
  if (millis() - lastReading >= 100) //10readings/second
  {
    val = analogRead(A1);
    lastReading = millis();

    if (val >= threshold)
      digitalWrite(ledPin, HIGH);

    if (val <= threshold and previousVal >= threshold) //state change
    {
      countingLows = true;
      Serial.println("Starting to count sequential Lows");
    }
    
    if (countingLows and val <= threshold)
    {
      count++;
      if(count%50 ==0) Serial.println(count);
    }

    else //went back above threshold during timing period
    {
      count = 0;
    }

    previousVal = val;
  

    if (count >= 200)
    {
      digitalWrite(ledPin, LOW);
      count = 0;
      countingLows = false;
      Serial.println("sequentialLows = 200");
    }
  }
}
1 Like

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