problem on Analog read on Piezo sensors for triggering + timelapse

Hi all,

I’ve been working a lot on arduino lately and would like to thank all people helping on my previous questions.

I am trying to do a first “real” project that is trying to use everything I’ve learnt for the moment.
concept : 4 piezo sensors that triggers midi notes on a Midi Drum machine. I haven’t implemented the Midi part yet because of the impossibility to use the terminal to debugg the code.

  • a sort of menu with 3 switches so that each piezo (visually selected with 4 leds) can trigger 4 different sounds.
  • switch 1 and 2 are used to select the piezo i want to change the sound of.
  • switch 3 is to change the sound.

I have a for loop that gets the analogRead of each sensor and when one piezo is hit the sound is on (represented for by a Serial.print - the piezo X is playing Y sound).

Everything is working but the accuracy of the trigger by the piezo sensor (I tried to plug them directly without resistors and with resistors. the result is the same).

I think something is wrong in my code because :

  • I have coded a timelapse in bewteen which you can’t play the sound twice. (playTime > maxPlayTime) BUT I have more than one value coming out when I hit the piezo once.
  • I don’t understand but for the moment I have hooked up only one piezo but the result on the terminal gives me some triggering from more than one analog input.

I believe something is wrong in this code :

for (int pin=0; pin<piezoCount; pin++) {
  
  piezoVal [pin] = analogRead (piezo [pin]) ;
  
  if (piezoVal[pin]  > piezoThreshold[pin] && playTime[pin] > maxPlayTime [pin]) {
    
    Serial.print (piezo [pin]+1); Serial.print (" is on with noteOn "); Serial.println (drumKit [piezoPos]); 
    playTime[pin] = 0;
  }
  
  playTime[pin]++ ;
  
}

it gives me on the terminal for one hit on the piezo different input Pins where it should be only one… Like if the for loop increases the pin number but keeps the values of the previous read.

here’s the terminal result for one hit :

1 is on with noteOn 40
1 is on with noteOn 40
1 is on with noteOn 40
4 is on with noteOn 40
4 is on with noteOn 40
1 is on with noteOn 40
4 is on with noteOn 40
1 is on with noteOn 40
4 is on with noteOn 40
2 is on with noteOn 40

And here’s the full code… If you could let me know where I’m doing it wrong and also if you see any possible general ameliorations, it would be much appreciated.

// Notes from drumkits I have available. each line is : kickdrum, snare, hithat, ride.
int drumSet [4][4] = {
  {36, 40, 42, 53},
  {35, 38, 17, 51},
  {61, 60, 66, 67},
  {23, 24, 25, 20}};
  
// the drumkit i finally use by changing it with the drumSet values available. 
int drumKit [4] = {36, 40, 42, 53}; 
  
// 3 switches
int buttonSet [] = {11, 12, 13};
int buttonCount = 3; 

// 4 leds that will represent the type of sound i will change : kickdrum, snare, hithat, ride.
int ledPin [] = {4,5,6,7};
int ledCount = 4; 

int soundSelect = 0 ;

// switchstates change
int buttonState [] = {0, 0, 0};
int lastButtonState [] = {0,0,0};

// 4 piezos as sensors
int piezo [] = {0, 1, 2, 3};
int piezoCount = 4;
int piezoVal [] = {0, 0, 0, 0};
// Threshold for the piezo to put a sound ON. 
int piezoThreshold [] = { 600, 600, 600, 600};

// 2 notes can't be played before playtime > maxplaytime
int playTime [] = { 0, 0, 0, 0};
int maxPlayTime [] = {90, 90, 90, 90};

// when initialized the piezo that can be changed is piezo 1
int piezoPos = 0; 
int lastPiezopos;

void setup () {
  
  Serial.begin (9600);
  delay (1000);
  Serial.println ("INITIALIZING");
  delay (300);
  
  // start set all buttons as inputs
  Serial.println ("SETTING BUTTONS");
  delay(300);
  for (int i= 0; i<buttonCount ; i++) {
    pinMode (buttonSet[i], INPUT) ; 
    Serial.print ("button  "); Serial.print (buttonSet[i]) ; Serial.println ("   is set ");
    delay (300);  }  
    Serial.println ("ALL BUTTONS ARE SET");
    delay(300);
   // end set all buttons as inputs
  
  // start set all leds as outputs
  Serial.println ("SETTING LEDS AS OUTPUTS");
  delay(300);
  for (int j= 0; j<ledCount ; j++) {
    pinMode (ledPin[j], OUTPUT);
    Serial.print ("ledPin  "); Serial.print (ledPin[j]) ; Serial.println ("   is set ");
    delay (300); }  
    Serial.println ("ALL LEDS ARE SET");
   // end set all leds as outputs
  delay(300); 
  Serial.print ("READY"); delay(100); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.println (". ");
}
  
  
void loop () { // Start loop 

// ----------------------------------------------------------
// check value of piezo 
// ----------------------------------------------------------

for (int pin=0; pin<piezoCount; pin++) {
  
  piezoVal [pin] = analogRead (piezo [pin]) ;
  
  if (piezoVal[pin]  > piezoThreshold[pin] && playTime[pin] > maxPlayTime [pin]) {
    
    Serial.print (piezo [pin]+1); Serial.print (" is on with noteOn "); Serial.println (drumKit [piezoPos]); 
    playTime[pin] = 0;
  }
  
  playTime[pin]++ ;
  
}


// ----------------------------------------------------------
// end check if piezo has a value
// ----------------------------------------------------------


// ----------------------------------------------------------
// check if a button is pressed and state change
// ----------------------------------------------------------
for (int i=0; i<buttonCount; i++) {
  
 buttonState[i] = digitalRead (buttonSet[i] ) ;
  
if (buttonState[i] != lastButtonState[i]) {
        
        if (buttonState[i] == HIGH) {
          // if the state has changed +  increment the counter
          if (i == 0) {
           
           piezoPos--; }
          // if the state has changed - decrement the counter
         else if ( i == 1 ) {
          
           piezoPos++ ;  }
           
         else if (i==2 ) {
           soundSelect++;
           if (soundSelect > 3) { soundSelect = 0;}
           drumKit [piezoPos] = drumSet [soundSelect] [piezoPos];
         }
           
          // verify I'm changing the right piezo sound 
          Serial.print ("You are on Piezo ");
          Serial.print (piezoPos+1); Serial.print (" // "); 
          Serial.print ("and sound "); Serial.println (drumKit [piezoPos]); 
          
          
          // Write on terminal what I have stored as the drumKit to be used. 
          Serial. print (drumKit [0]); Serial. print ("   "); Serial. print (drumKit [1]); Serial. print ("   "); 
          Serial. print (drumKit [2]); Serial. print ("   "); Serial. print (drumKit [3]); Serial. println ("   "); 
                } // end if buttonState === HIGH 
                
        // save the current state as the last state, 
        //for next time through the loop
        lastButtonState[i] = buttonState[i];        
      }  // end if buttonState != lastbuttonstate
} //end for int i=0

// turn ON the corresponding led and turn off the others
digitalWrite (ledPin[piezoPos], HIGH);
digitalWrite (ledPin[piezoPos-1], LOW);
digitalWrite (ledPin[piezoPos+1], LOW);
// ----------------------------------------------------------
// end check of button press
// ----------------------------------------------------------
 
 
 
} // end loop

One call of analogRead() takes about 100µs, so loop() is run about 2500 times per second. If the piezo is active for more than about 40 ms you get it registered twice. It seems like the first piezo was active for about one tenth of a second and you got 3 registrations.

If you haven't connected the other piezos, the appropriate pins are probably floating (not connected to anything), so they give you readings of a more or less random value. Connect these pins to GND and they should go away.

omg i spent the 3 last hours trying to figure it out and your answer made it work in a few seconds. Thanks so much !

Could you give more explanation on the the fact that if not used the other analog inputs can give random values like that ?

Thanks again !

One call of analogRead() takes about 100µs, so loop() is run about 2500 times per second. If the piezo is active for more than about 40 ms you get it registered twice. It seems like the first piezo was active for about one tenth of a second and you got 3 registrations.

Do you know how I can pass through that ? Because I really need just 1 noteOn and not 3 in a row ! Is there a line of code to get ride of the others ?

Thanks a lot,

Meshell

i’m really stuck here.
I’ve coded the midi part and I have more than 1 noteOn when I use the sensors.

i’ve been trying many ideas… i found one that seemed quite interesting and I wrote this code for the sensors loop but still not giving me just 1 noteOn

// ----------------------------------------------------------
// check value of piezo 
// ----------------------------------------------------------

for (int pin=0; pin<piezoCount; pin++) {
  
  piezoVal [pin] = analogRead (piezo [pin]) ;
 
  if (piezoVal[pin]  > piezoThreshold[pin]) {
     if (playIsOk[pin] == true ) 
           {
        noteOn(0x90, drumKit [pin], 127);
        //digitalWrite (ledPinNote, HIGH);
        delay (10);
        noteOn(0x90, drumKit [pin], 0);
         //digitalWrite (ledPinNote, LOW);
      
        
      // Serial.print (piezo [pin]+1); Serial.print (" is on with noteOn "); Serial.println (drumKit [pin]); 
      // Serial.print (piezoVal[0]); Serial.print (" /  "); Serial.print (piezoVal[1]); Serial.print (" /  "); Serial.print (piezoVal[2]); Serial.print (" /  "); Serial.print (piezoVal[3]); Serial.print (" /  "); Serial.println (piezoVal[4]); 
       playIsOk[pin] = false;  
           }
     else if (playIsOk[pin] == false) {
          
            if (playTime[pin] > maxPlayTime[pin] )
                 { 
                   playIsOk[pin] = true;
                   playTime[pin] =0;
                 }
            }  
  }// end of piezoval > piezothresh
playTime[pin] = playTime[pin] +1;
} // end of for piezocount

and here’s the whole code - please help me !

// Notes from drumkits I have available. each line is : kickdrum, snare, hithat, ride.
int drumSet [4][5] = {
  // KICK , SNARE , CHH, 
  {36, 40, 42, 53, 46 },
  {35, 38, 17, 51, 18 },
  {61, 60, 66, 67, 65 },
  {23, 24, 25, 20, 26 }
};
  
// the drumkit i finally use by changing it with the drumSet values available. 
int drumKit [5] = {36, 40, 42, 53, 46}; 
  
// 3 switches
int buttonSet [] = {11, 12, 13};
int buttonCount = 3; 

// 4 leds that will represent the type of sound i will change : kickdrum, snare, hithat, ride.
int ledPin [] = {4,5,6,7,8};
int ledCount = 5; 
int ledPinNote = 10;

int soundSelect = 0 ;

// switchstates change
int buttonState [] = {0, 0, 0};
int lastButtonState [] = {0,0,0};

// 4 piezos as sensors
int piezo [] = {0, 1, 2, 3, 4};
int piezoCount = 5;
int piezoVal [] = {0, 0, 0, 0, 0};
int lastPiezoVal [] = {1023, 1023, 1023, 1023, 1023};
// Threshold for the piezo to put a sound ON. 
int piezoThreshold [] = { 200, 200, 300, 200, 200};

// 2 notes can't be played before playtime > maxplaytime
int playTime [] = { 0, 0, 0, 0, 0};
int maxPlayTime [] = {100, 100, 100, 100, 100};
boolean playIsOk[] = {true, true, true, true, true}; 

// when initialized the piezo that can be changed is piezo 1
int piezoPos = 0; 
int lastPiezopos;

// midi channel
#define  midichannel	0;    

void setup () {
  
  Serial.begin (31250);
  delay (3000);
  Serial.println ("INITIALIZING");
  delay (100);
  
  // start set all buttons as inputs
  Serial.println ("SETTING BUTTONS");
  delay(100);
  for (int i= 0; i<buttonCount ; i++) {
    pinMode (buttonSet[i], INPUT) ; 
    Serial.print ("button  "); Serial.print (buttonSet[i]) ; Serial.println ("   is set ");
    delay (100);  }  
    Serial.println ("ALL BUTTONS ARE SET");
    delay(100);
   // end set all buttons as inputs
  
  // start set all leds as outputs
  Serial.println ("SETTING LEDS AS OUTPUTS");
  delay(100);
  for (int j= 0; j<ledCount ; j++) {
    pinMode (ledPin[j], OUTPUT);
    Serial.print ("ledPin  "); Serial.print (ledPin[j]) ; Serial.println ("   is set ");
    delay (100); }  
    pinMode (ledPinNote, OUTPUT);
   digitalWrite (ledPinNote, HIGH);
   delay (100);
   digitalWrite (ledPinNote, LOW);
   
    Serial.println ("LedPinNote is Set");
    Serial.println ("ALL LEDS ARE SET");
   // end set all leds as outputs
  delay(100); 
  Serial.print ("READY"); delay(100); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.print (". "); Serial.println (". ");
}
  
  
void loop () { // Start loop 

// ----------------------------------------------------------
// check value of piezo 
// ----------------------------------------------------------

for (int pin=0; pin<piezoCount; pin++) {
  
  piezoVal [pin] = analogRead (piezo [pin]) ;
 
  if (piezoVal[pin]  > piezoThreshold[pin]) {
     if (playIsOk[pin] == true ) 
           {
        noteOn(0x90, drumKit [pin], 127);
        //digitalWrite (ledPinNote, HIGH);
        delay (10);
        noteOn(0x90, drumKit [pin], 0);
         //digitalWrite (ledPinNote, LOW);
      
        
      // Serial.print (piezo [pin]+1); Serial.print (" is on with noteOn "); Serial.println (drumKit [pin]); 
      // Serial.print (piezoVal[0]); Serial.print (" /  "); Serial.print (piezoVal[1]); Serial.print (" /  "); Serial.print (piezoVal[2]); Serial.print (" /  "); Serial.print (piezoVal[3]); Serial.print (" /  "); Serial.println (piezoVal[4]); 
       playIsOk[pin] = false;  
           }
     else if (playIsOk[pin] == false) {
          
            if (playTime[pin] > maxPlayTime[pin] )
                 { 
                   playIsOk[pin] = true;
                   playTime[pin] =0;
                 }
            }  
  }// end of piezoval > piezothresh
playTime[pin] = playTime[pin] +1;
} // end of for piezocount

  
 
  


// ----------------------------------------------------------
// end check if piezo has a value
// ----------------------------------------------------------


// ----------------------------------------------------------
// check if a button is pressed and state change
// ----------------------------------------------------------
for (int i=0; i<buttonCount; i++) {
  
 buttonState[i] = digitalRead (buttonSet[i] ) ;
  
if (buttonState[i] != lastButtonState[i]) {
        
        if (buttonState[i] == HIGH) {
          // if the state has changed +  increment the counter
          if (i == 0) {
           
           piezoPos--; }
          // if the state has changed - decrement the counter
         else if ( i == 1 ) {
          
           piezoPos++ ;  }
           
         else if (i==2 ) {
           soundSelect++;
           if (soundSelect > 3) { soundSelect = 0;}
           drumKit [piezoPos] = drumSet [soundSelect] [piezoPos];
         }
           
          // verify I'm changing the right piezo sound 
          //Serial.print ("You are on Piezo ");
          //Serial.print (piezoPos+1); Serial.print (" // "); 
          //Serial.print ("and sound "); Serial.println (drumKit [piezoPos]); 
          
          
          // Write on terminal what I have stored as the drumKit to be used. 
          //Serial. print (drumKit [0]); Serial. print ("   "); Serial. print (drumKit [1]); Serial. print ("   "); 
          //Serial. print (drumKit [2]); Serial. print ("   "); Serial. print (drumKit [3]); Serial. print ("   "); 
          //Serial. print (drumKit [4]); Serial. println ("   "); 
                } // end if buttonState === HIGH 
                
        // save the current state as the last state, 
        //for next time through the loop
        lastButtonState[i] = buttonState[i];        
      }  // end if buttonState != lastbuttonstate
} //end for int i=0

// turn ON the corresponding led and turn off the others
digitalWrite (ledPin[piezoPos], HIGH);
digitalWrite (ledPin[piezoPos-1], LOW);
digitalWrite (ledPin[piezoPos+1], LOW);
// ----------------------------------------------------------
// end check of button press
// ----------------------------------------------------------
 
 
 
} // end loop 

// ----------------------------------------------------------
// Transmit MIDI message
// ----------------------------------------------------------
//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

I really need just 1 noteOn and not 3 in a row ! Is there a line of code to get ride of the others ?

Not a line of code but you can do it with several Once you have detected a hit set a flag and clear it after a time which you will have to determine, but about 50ms would be a starting point. Whilst the flag is set ignore other positive reads from the device.

Maybe you have to define what a noteOn is. One possibility is to register just rising edges. So if the value is bigger than 600, register you "noteOn", then ignore all values until they go below 500. As soon as you got the first reading below that, start looking again for values greater than 600. Does that make sense in your case?