Piezo Drum Lights Arduino code help!

Hello there everyone,

I have been working on my final uni project which involves triggering LEDs from Piezo elements connected to a drum set (so each time I hit a drum an LED strip gets activated and deactivated).

I have been doing this on an Arduino Uno and have been using this code on LED testers at the moment, however, the lights don’t seem to be responding well to the code.

I am a complete beginner in coding and was recommended this arduino Knock! (https://www.arduino.cc/en/Tutorial/Knock) code by Stephen from core electronics. It seems to be triggering the LEDs however once triggered once, the lights do not turn off for a couple of seconds and the serial print is printing hundreds of hits when I only tapped it once.

I basically just need a simple on/off reaction to the piezo’s being hit as it needs to respond dynamically to each drum hit. Any help or guidance would be wonderful to someone who has very little arduino knowledge!!! below is the code I have been working on so far.

Thanks in advance! (At the moment the Piezo is connected to a breadboard and a 1 megohm resistor).

int knockSensor = 0;               

byte val = 0;

int statePin = LOW;

int THRESHOLD = 200;



void setup() {

 pinMode(8, OUTPUT); 

 Serial.begin(9600);

}



void loop() {

  val = analogRead(knockSensor);     

  if (val >= THRESHOLD) {

    statePin = !statePin;

    digitalWrite(8, statePin);

    Serial.println("Knock!");



  }

  delay(100);  // we have to make a delay to avoid overloading the serial port

}

Hi Adisorn,

I’d be happy to help you out with your code. It sounds like your piezo might be much more sensitive than you are giving it credit for. Its probably continuing to sense vibrations above the threshold long after the drum has been struck!

Here are my suggested changes:

int knockSensor = 0;      // initializes knockSensor variable         
byte val = 0;                   // initializes val variable
int statePin = LOW;                // initializes statePin to LOW (off)

                 // This number sets the sensitivity. The higher the less sensitivity
int THRESHOLD = 500;      //I've changed it from 200 to 500 but I'm guessing
     
void setup() {
 pinMode(8, OUTPUT); 
 Serial.begin(9600);
}

void loop() {
  val = analogRead(knockSensor);     
  if (val >= THRESHOLD) {
    statePin = ! statePin;
    digitalWrite(8, statePin);
    Serial.println(val);   // I've changed this to print the reading from the knock sensor. 
                                   // you can use this to see what value the spike is when the sensor is hit
                                   // and then set your THRESHOLD to be just below
  }

  delay(100);  // we have to make a delay to avoid overloading the serial port
}

Let me know how that goes!

1 Like

You may also want to change the code within the if statement from this:

statePin = !statePin; // change from on to off 
digitalWrite(8, statePin); // set pin on or off
Serial.println("Knock!"); // Write to serial.

This will turn on with the first “knock” and off with the second. Changing to:

statePin = HIGH; Change state to on
digitalWrite(8, statePin); // set pin on
delay(100); //wait 100 miliseconds
Serial.println("Knock!"); // Write to serial.
statePin = LOW; Change state to Off
digitalWrite(8, statePin); // set pin Off

This should turn on then off after the knock is detected.

1 Like

Hi again Stephen!

Thanks for your prompt reply!

I have tried the code changes and it seems to now not be sensitive enough. Must be in the range of somewhere between 100 - 300 as that’s around where I was playing with it before. Your annotations have really cleared up a lot of confusions with each parameter though! so thankyou so much for that.

I have had most luck and consistency with the threshold at around 100-150.

I have not even connected it to the drums yet so am hoping that it’ll work.

If I wanted the LED to just turn on and off after each hit, do I need to amend anymore codes or do you think this will be ok? it seems to be responding ok now.

Also, I am going to buy LED strips today to test them out, do you have any recommendations/any guidance in what i’ll need to connect them to the set up I currently have? will I need capacitors or anything?

Thanks so much stephen!

Hi Adisorn,

I would follow Clinton’s advice to make the light turn on for a second on each hit then turn off. That’s probably the effect that you are going for. As for the LED’s what type of effect are you going for? Solid color or color changing strip?

For a full LED drum build I highly recommend following this tutorial: https://learn.adafruit.com/gemma-powered-neopixel-led-sound-reactive-drums/overview

They use a Gemma and a microphone, BUT you can use your arduino and piezo just the same I think. They give a great explanation on how to wire up the lights using Neopixels, and you cant just connect a piezo in place of the mic they use then it shouldn’t take many changes in the code to make it work.

Thanks Clinton! Will give this a try once I e got the threshold right!

  • Andrew

Hey guys,

I have done as advised and updated the code. However, now the LED tester seems to be flashing on and off continuously without stopping when I haven’t even touched the piezo.

Not sure if this is a problem with the LED or the code?

Warm regards,

Adisorn (Andrew)

Adisorn,

Please share your code so we can see what your updates are. It’s probably the code.

Hi Stephen,

This is the code as I have been trying it.

int knockSensor = 0;

byte val = 0;

int statePin = LOW;

int THRESHOLD = 100;

void setup() {

pinMode(8, OUTPUT);

Serial.begin(9600);

}

void loop() {

val = analogRead(knockSensor);

if (val >= THRESHOLD) {

statePin = HIGH; //Change state to on
digitalWrite(8, statePin); // set pin on
delay(100); //wait 100 miliseconds
Serial.println(“Knock!”); // Write to serial.
statePin = LOW; //Change state to Off
digitalWrite(8, statePin); // set pin Off

}

delay(100); // we have to make a delay to avoid overloading the serial port

}

100 threshold seems to be where its most responsive at the moment when im tapping it with my fingers. I need it to be quite responsive as I will be using a lot of loudness and softness in my playing of the drums!

Thankyou so much Stephen!

If your light is flashing on and off continuously with no tapping of the piezo, then you have the threshold set below the background noise that the sensor returns.

Try this:

int val = 0;    // changed this to an int. byte stores a number from 0-255. analogRead() returns an int from 0-1023
int THRESHOLD = 100; // change this based on your serial output readings!

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

  val = analogRead(knockSensor);
  Serial.println(val); // Write sensor readings to serial. Use this to set a good THRESHOLD

  if (val >= THRESHOLD) {
    digitalWrite(8, HIGH); // set pin on
    delay(500); //wait 500 miliseconds, this delay sets how long the light stays on each hit.
    digitalWrite(8, LOW); // set pin Off
  }


  // try removing this delay to see if you get better results
 delay(100); // we have to make a delay to avoid overloading the serial port
}

I removed statePin because it’s no longer relevant.
I changed val from a byte to an int because you weren’t getting all your readings from analogRead()
Removed knockSensor because it’s not used.

See how that works!

1 Like

Hi Stephen,

thanks again for such a quick reply! Thankyou so much for all your help, you have been an instrumental part of this project so I really really appreciate it!

I have tried those code amendments and it still seems to be flashing but this time after one hit it continues to flash forever while the serial print is reading a range of numbers descending from 400-300 all the way to 0.

However, I went back to the code I uploaded to you just above and re-amended the threshold and the delay and it seems to be a lot more responsive than it was yesterday!!

I have also bought LED strips however it needs 12vDC power. Any advice on how to connect it to my project? It comes with a 2-wire output, one red and one grey-ish (its a solid colour one). Will i need MOSFETS and more resistors? (planning to connect 3 but 2 is the minimum I’d like to go for).

thanks so much again!

  • Adisorn

Hi again Stephen, sorry to double up on a post but I just had a bit of an update.

The initial code that I posted is now acting up again. The LED will be responsive to my taps for a couple of seconds then it will begin to flash like a strobe once again, registering many many knocks. When I amend the threshold to a higher setting it doesn’t detect the knocks at all.

Will try more fixes that you suggested.

Cheers!

Hi Adisorn,

You will need to adjust the THRESHOLD value to be appropriate given the readings. in the code I shared. How long does it take for the readings to drop from the piezo? Maybe you need to put a resistor inline.

Hello there Stephen,

Thanks again for the reply. No matter how high or low I set the Threshold, the readings keep climbing or lowering itself with the threshold value. E.g. if I set the threshold to 100 the readings will keep ascending/descending from 150 onwards to 200, if I set the threshold to 200 the readings climb to 250 and does the same on a loop.

The LED never stops flashing as if detecting thousands of knocks. I have attached a video (hopefully the video works).

(Attachment Video.MOV is missing)

(Attachment ATT00001.htm is missing)

The video didn’t work, so here are some photos of the set up/the serial print. I will try with the Neopixel drum build code and replace the microphone with piezos. Thankyou so much Stephen

1 Like

Adisorn,

Could you please share the code that you are currently using?
It looks like you might not have made the changes that I suggested.

Stephen,

I’m not currently home at the moment but I’m pretty sure this was the latest code I was working with last night.

Apologies if I have not done what you recommended, I will go home and double check and use the code you recommended if this is not it! Cheers!

int knockSensor = 0;

byte val = 0;

int statePin = LOW;

int THRESHOLD = 100;

void setup() {

pinMode(8, OUTPUT);

Serial.begin(9600);

}

void loop() {

val = analogRead(knockSensor);

if (val >= THRESHOLD) {

statePin = HIGH; //Change state to on

digitalWrite(8, statePin); // set pin on

delay(100); //wait 100 miliseconds

Serial.println(“Knock!”); // Write to serial.

statePin = LOW; //Change state to Off

digitalWrite(8, statePin); // set pin Off

}

delay(100); // we have to make a delay to avoid overloading the serial port

}

  • Andrew
1 Like

Hi Stephen,

I have been using your recommended code above:

int val = 0; // changed this to an int. byte stores a number from 0-255. analogRead() returns an int from 0-1023
int THRESHOLD = 1000; // change this based on your serial output readings!
int knockSensor = A0;

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

val = analogRead(knockSensor);
Serial.println(val); // Write sensor readings to serial. Use this to set a good THRESHOLD

if (val >= THRESHOLD) {
digitalWrite(8, HIGH); // set pin on
delay(500); //wait 500 miliseconds, this delay sets how long the light stays on each hit.
digitalWrite(8, LOW); // set pin Off
}

// try removing this delay to see if you get better results
delay(100); // we have to make a delay to avoid overloading the serial port
}

I have changed the Threshold all the way to 1000 following the readings and still no luck. The LED tester keeps flashing without being touched. Even when I remove the piezo from the circuit it still does this.

Any guidance would be wonderful.

Cheers!

Change this to:

while (val >= THRESHOLD) {
  digitalWrite(8, HIGH); // set pin on
}
delay(500); //wait 500 miliseconds, this delay sets how long the light stays on each hit.
digitalWrite(8, LOW); // set pin Off

This way it will turn on the drums once per hit.