Piezo MIDI Drums

Hi everybody,

This piezo midi drums are my school project. For now I have just one "drum". My Arduino sends a signal to Serial to MIDI Coverter then via LoopBe1 to Native Instruments:Traktor.
I have one serious problem. When I hit the piezo I get multiply values, sometimes it's even 20 values :astonished: . Program should search for maximum value
I hope you can help me.
here is my code:

int ledPin = 12;
int piezo = A0;
int threshold = 100;
int sensorReading = 0;
int i=0,MAX=0;

void setup() {

pinMode(ledPin, OUTPUT);
pinMode(piezo, INPUT);
Serial.begin(57600);

}

void loop() {

sensorReading = analogRead(piezo);

if (sensorReading > threshold) {

while(sensorReading > threshold){

if(sensorReading > MAX)

MAX=sensorReading;
else {
i++;

/analogWrite(ledPin,MAX);
MidiTX(176, 0, 127);
/

Serial.println(MAX);
Serial.println(i);
Serial.println("\t");
Serial.println("TUC");
break;
}
}

}

MAX = 0;
digitalWrite(ledPin, LOW);
delay(20);

/*void MidiTX(unsigned char StatusByte, unsigned char Note, unsigned char Val)
{
Serial.write(StatusByte);
Serial.write(Note);
Serial.write(Val);
}
*/

Do you have some protection at the input of the Arduino ?

Do you connect the piezo in such a way that a positive pulse is generated ? Or could it also be a negative pulse ?

You use a threshold, and if the input signal is above that, it is considered a valid pulse. Waiting for the maximum value seems not right to me.
But for each drum, you could add a variable called 'active'. That variable is 'true' while the pulse is still busy, and 'false' is the pulse is below the threshold again. That way just one midi TX is sent for each pulse, no matter how long the pulse is.

Another way to do this, is to use timing with the millis() function. You can use it to make a new pulse is only valid after about 100ms.

The best way is perhaps both. Use the variable 'active' together with the timing.

yop, I have parallel 1MOhm and serial diode to evade negative pulses

And what about pulses greater that 5V?

I measured it and max was something about 3.3V

Did you use a scope to measure it. Meters can't see such narrow spikes.

nop. only multimeter

thanks Krodal, I tried that timing, and it seems to work.

int ledPin = 12;
int piezo = A0;
int threshold = 200;
int sensorReading = 0;
int val,oldtime,time;

void setup() {

pinMode(ledPin, OUTPUT);
pinMode(piezo, INPUT);
Serial.begin(57600);

}

void loop() {

////////////////////SNARE/////////////////////////////////////////////
oldcas = millis()+10;

sensorReading = analogRead(piezo);
if( sensorReading > threshold ) {

while(analogRead(piezo) > threshold) {
time = millis();
if(time==oldtime) val = map(analogRead(piezo), 0,1023, 0, 127);

}

MidiTX(144, 0, val);
MidiTX(128, 0, val);
}
}

void MidiTX(unsigned char StatusByte, unsigned char Note, unsigned char Val)
{
Serial.write(StatusByte);
Serial.write(Note);
Serial.write(Val);
}

It's not beautiful programming, but if you are happy then I'm happy.

For example the millis() function returns an unsigned long

You use integers to compare the time.

now it works almost fine. there is one problem with latency. I hit the piezo, but sound is delayed by 500 milliseconds approx. do you think that problem is with converter or virtual midi interface or software that plays samples?

code:

int ledPin = 12;
int piezo = A0;
int threshold = 200;
int sensorReading = 0;
int val,oldcas,cas;

void setup() {

pinMode(ledPin, OUTPUT);
pinMode(piezo, INPUT);
Serial.begin(57600);

}

void loop() {

// SNARE

sensorReading = analogRead(piezo);

if( sensorReading > threshold ) {
oldcas = millis()+5;
while(analogRead(piezo) > threshold)
{
if(millis()==oldcas)
{
val = analogRead(piezo) / 8;
}
}
/Serial.println(val);/
MidiTX(144, 0, val);
MidiTX(128, 0, val);
}
}

void MidiTX(unsigned char StatusByte, unsigned char Note, unsigned char Val)
{
Serial.write(StatusByte);
Serial.write(Note);
Serial.write(Val);
}

You can try a fixed value for 'val', and send the MidiTX as soon as sensorReading > threshold.