Counting number of Vibrations (Piezo/analog in) within timeframe

Hey :slight_smile:

i have been trying around with several scripts for two days but i am not able to solve this problem on my own and i am totally lost and confused at the moment:
I have a piezo wired to Analog 5 (with pulldown resistor etc) and i want the arduino to count the number of vibrations (above a fixed threshold) within a given timeframe:
For example: The first vibration / shock starts the timer of e.g. 20 seconds. Every vibration/shock within that timeframe is added to the
number of counts. (Afterwards i want to make the program do something depending from the number of shocks but i will try to figure out
how this works by myself)

could you please help me?

thank you so much

tm

I have a piezo wired to Analog 5 (with pulldown resistor etc) and i want the arduino to count the number of vibrations (above a fixed threshold) within a given timeframe:

Piece of cake. All you need is a while loop that executes for the specified amount of time. In that loop, read the pin, and see if the value is now above, but wasn't before, a threshold. If so, increment the counter.

Of course, one of the difficulties you will encounter is that the analogRead() function is relatively slow, so if the thing causing the vibration is doing so at a high frequency, you will miss some values.

So, what does your code to read the pin look like?

Hey PaulS,

thank you very much. Currently my code looks like this: (i have started all over and try to begin from the scratch)

int sensorPiezo = A5;    // piezo input
int sensorValue = 0;  // unused 

void setup() {
 Serial.begin(9600);	
}

void loop() {

  sensorValue = analogRead(sensorPiezo);    // read the value from the sensor:
  Serial.println(analogRead(sensorPiezo));    // tell the value from the sensor:
   delay(100);          

}
delay(100);

That's going to limit the frequency by three orders of magnitude more than the analogue read time.
Get rid of it.

  sensorValue = analogRead(sensorPiezo);    // read the value from the sensor:
  Serial.println(analogRead(sensorPiezo));    // tell the value from the sensor:

You are reading the sensor twice. This bit of code will take much longer to execute than it needs to.

  sensorValue = analogRead(sensorPiezo);    // read the value from the sensor:
  Serial.println(sensorValue);    // tell the value from the sensor:

would be a lot better.

   delay(100);

Here I was under the impression that you wanted this to be fast... Silly me.

What you need to do is keep track of the current value and the previous value. If the current value is above the threshold, and the previous value was not, then you have detected a rising edge, and need to count the event.

Lets break this into multiple steps. The next thing for you to do is to add a variable to hold the previous value. Then, add some code to determine if the current and/or previous values are above the threshold. Of course, this means that you need to define a threshold.

Once you have that code working, and posted, we can work on the "how many times in 20 seconds" part.

ok...this should be something like this but somehow it is wrong..sorry ...

int sensorPiezo = A5;    // piezo input
int sensorValue = 0;  
int sensorValueBefore = 0; 

void setup() {
 Serial.begin(9600);	
}

void loop() {

  
sensorValue = analogRead(sensorPiezo);    // read the value from the sensor:
Serial.println(sensorValue);    // tell the value from the sensor:

    if (sensorValue != sensorValueBefore) 
    {
      Serial.println("something has changed ");
    }    

sensorValueBefore=sensorValue;


} // end

Somehow, that statement doesn't convey much meaning.

Are you saying it continually prints "something has changed"?
Well, yes, that will happen.
Maybe, rather than testing for equality, see if the absolute value of the difference of the current and previous values is greater than some threshold (Hint: it is quicker to code than it is to write out in English)

What i wanted to say is that i am not sure about my code and that it does not do what i wanted it to do. I get
the value from the analogRead and a million times »something has changed« ; ) ...

I like names like currValue and prevValue. I like spaces between names and operators (sensorValueBefore = sensorValue;).

But, like AWOL says, you need to tell us what is wrong.

if (abs (sensorValue - sensorValueBefore) > SOME_THRESHOLD)

that's great. One step ahead : )

int sensorPiezo = A5;    // piezo input
int currValue = 0;  
int prevValue = 0; 
int threshold = 6;  

void setup() 
{
 Serial.begin(9600);	
}

void loop() {
  
currValue = analogRead(sensorPiezo);    // read the value from the sensor:
// Serial.println(currValue);    // tell the value from the sensor:

if (abs (currValue - prevValue) > threshold) 
    {
      Serial.println("something has changed ");
    }      
      
prevValue = currValue;

} // end

the monitor tells me »something has changed« when i touch the piezo. As far as i understand abs does some kind of comparison between currValue and prevValue and the whole line checks if it is above the threshold? Is this correct?

Currently what i get is »something has changed« being displayed in the monitor 4 or 5 times (this is what i tried to avoid with my delay). How can i proceeed with counting within my given timeframe?

thank you so much

tm

Not quite, "abs" takes the result of the subtraction in the parentheses and makes it positive if it is negative.
So, "abs(x - y)" will always be either zero or positive.

One problem with using the abs() function is that you will detect rising edge changes, falling edge changes, and significant rising or falling edge changes, even when both current and previous values are above the threshold.

We need to understand just what it is you are trying to measure. What is causing the vibrations that you are measuring?

it is not exactly i vibration i guess: The piezo element is connected to a case and i want to count the hits or knocks or something like that
on the case ...

thank you,

tm

Some useful reading and experimentation would be playing around with the blink without delay example, to see how to keep track of a period of time, whilst still doing useful work.

Some useful reading and experimentation would be playing around with the blink without delay example, to see how to keep track of a period of time, whilst still doing useful work.

Agreed. I still think, though, that it is necessary only to detect when the current reading is above the threshold, and the previous reading was not.

Using the abs() method, if the threshold was 20, and the previous reading was 10, and the current reading is 35, the difference is above the threshold, so that reading would be counted. If the next reading is 60, the difference, since the previous reading was 35, will be 25, which is above the threshold, so this reading will be counted, too. It's not clear, to me, that it should be.

I guess that OP needs to write some code, and perform some testing to determine whether it is possible to reliably count knocks, using abs() and whether it is it is possible to reliably count knocks, not using abs().

Would love to see this code completed.