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
}
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
}
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.
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?
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?
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.
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?
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!
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.
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).
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.
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.
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).
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
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;
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.
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