test code for piezo

seayaker

Active member
Why won't this code work with teensy 3.6? It just goes berserk when I open the serial monitor even with nothing connected. I copied the code from the spark fun Piezo Drum Kit Quickstart Guide and connected everything the same. What do I need to do to get 1 piezo working and trigger a note or something-anything?

#define DRUM1 0 // Our analog pin

byte val = 0; // Initializing the variable for the voltage value

void setup()
{
Serial.begin(9600); // Initializing the serial port at 9600 baud
}

void loop()
{
val = analogRead(DRUM1); // Read the voltage
Serial.println(val, DEC); // Print the voltage to the terminal
}
 
Unrestrained printing is most likely what you are seeing.

Also analogRead will return larger than 8 bit value on Teensy. Untested edits shown below.

Code:
uint16_t val = 0; // Initializing the variable for the voltage value
uint16_t last_val = 0; // Initializing the variable for the voltage value
void loop()
{
  val = analogRead(DRUM1); // Read the voltage
  if ( val != last_val ) {
    Serial.println(val, DEC); // Print the voltage to the terminal
    last_val = val;
    delay( 40 );
  }
}
 
Thanks for responding, I tried your sketch, it says

'DRUM1' was not declared in this scope.
I tried several sketches for piezo drum pads but still can't get any to trigger a note.
 
defragster wrote it to match your sketch, either graft his loop into yours, or add
#define DRUM1 0 // Our analog pin
In either case you probably also need to add
pinMode(DRUM!,INPUT);
to the setup function.
 
GremlinWrangler has it right - except for redefining 'val' - I expected the upper part with setup() and #define to persist.

As an Analog input the pinMode may be wrong to add.
 
Please bare with me, I'm new at this. Is this what you mean?

#define DRUM1 0 // Our analog pin

byte val = 0; // Initializing the variable for the voltage value

void setup()
{
Serial.begin(9600); // Initializing the serial port at 9600 baud
}

void loop()
{
val = analogRead(DRUM1); // Read the voltage
Serial.println(val, DEC); // Print the voltage to the terminal
}
uint16_t val = 0; // Initializing the variable for the voltage value
uint16_t last_val = 0; // Initializing the variable for the voltage value
void loop()
{
val = analogRead(DRUM1); // Read the voltage
if ( val != last_val ) {
Serial.println(val, DEC); // Print the voltage to the terminal
last_val = val;
delay( 40 );
}
 
Please bare with me, I'm new at this.

only one loop() function and one declaration

Code:
#define DRUM1 0    // Our analog pin

void setup()
{
  Serial.begin(9600);  // Initializing the serial port at 9600 baud
}

uint16_t val = 0; // Initializing the variable for the voltage value
uint16_t last_val = 0; // Initializing the variable for the voltage value
void loop()
{
  val = analogRead(DRUM1); // Read the voltage
  if ( val != last_val ) {
    Serial.println(val, DEC); // Print the voltage to the terminal
    last_val = val;
    delay( 40 );
  }
 
@seayaker - hopefully the more complete post from WMXZ gets you started better. If you click the "#" hashtag icon it adds HTML markers in the post to inset and format the code as shown in above posts to be more readable.

That delay(40); is just a guess to slow down the prints. There are better ways than delay() - Teensy comes with elapsedMicros and elapsedMillis that make tracking time very easy and keep from halting code execution as you get more going on. The Analog value may vary +/- 1 or more, and without that delay it could still end up printing every loop. That should be good enough though to see that it works for this demo purpose.

Because Teensy uses on-chip hardware USB it goes away during programming - and takes the computer a couple hundred milliseconds to re-attach. Which can leave some early print()'s lost. Sometimes things like this will be used to have setup() wait a short time - in this case up to 4 seconds for the connection to be made before continuing so all the output can be captured to the Serial Monitor:
Code:
void setup()
{
  Serial.begin(9600);  // Initializing the serial port at 9600 baud
  [B]while ( !Serial && millis() < 4000 ) ;[/B]
  Serial.println( "Hello World!" );
}
 
Last edited:
Before talking about code, I'd like to recommend using 2 resistors (470 and 10K) and 2 signal diodes (1N4148 or 1N914 or similar).

DSC_0860_web.jpg

The piezo sensor positive should connect to the 470 ohm resistor, and the 2 diodes should connect from the 470 resistor to GND and to 3.3V.

DSC_0862_zoom.JPG

This arrangement will limit the voltage, keeping your Teensy safe. These piezo sensors can create rather high voltage spikes, especially if struck with a lot of force by a hard object.

The other resistor connects to GND, in parallel with one of the diodes. This 10K resistor gives the piezo a load to drive. The result is much lower noise at the analog pin. In this test I used 10K, but you can adjust this resistor for more or less sensitivity.

Before you go any further, I highly recommend building this circuit with these 4 parts. It will protect your Teensy and give you a much better signal.
 
Nice detail Paul - Thx. I only looked at the code as reading a safe analog value of course. But I have something I might want to test a piezo for detecting a louder noise and saw a note go by about a single large resistor solution. Then I was wondering if I could still have the Piezo make a beep sound for me?
 
Now for the code part. To properly capture this signal requires work in the code. First, here's what the signal actually looks like at the analog pin, after the effect of those 2 resistors and 2 diodes.

file.png
(click for full size)

To proper capture this requires making many measurements during the first portion of the waveforms. Your first measurement that shows a signal won't be the peak. It'll very likely be somewhere along the rising slope. A timer is needed, to keep making measurements for the entire expected duration of the first peak. In this waveform it lasts about 3 milliseconds, but on others it could be slightly longer. During this time, every measurement must be checked and the highest value kept.

After the initial peak comes lasting aftershock and vibration. How long this lasts and how large it is depends on how the piezo is mounted. It it's sitting loose on a table, vibrations can last time quite some time. The code needs to ignore all readings for that amount of time. Then it can begin waiting for another reading, and start looking for the next peak.

With those ideas in mind, here's a quick program I wrote as an example. I tested it with the circuit shown above. It works well. Hopefully this helps?

Code:
const int thresholdMin = 12;  // minimum reading, avoid "noise"
const int aftershockMillis = 60; // time of aftershocks & vibration

int state=0; // 0=idle, 1=looking for peak, 2=ignore aftershocks
int peak;    // remember the highest reading
elapsedMillis msec; // timer to end states 1 and 2

void setup() {
  Serial.begin(115200);
  //pinMode(A0, INPUT_DISABLE);
  while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
  Serial.println("Piezo Peak Capture");
}

void loop() {
  int piezo = analogRead(A0);

  if (state == 0) {
    // IDLE state: if any reading is above a threshold, begin peak
    if (piezo > thresholdMin) {
      //Serial.println("begin state 1");
      state = 1;
      peak = piezo;
      msec = 0;
    }
  } else if (state == 1) {
    // Peak Tracking state: for 10 ms, capture largest reading
    if (piezo > peak) {
      peak = piezo;
    }
    if (msec >= 10) {
      Serial.print("peak = ");
      Serial.println(peak);
      //Serial.println("begin state 2");
      state = 2;
      msec = 0;
    }
  } else {
    // Ignore Aftershock state: wait for things to be quiet again
    if (piezo > thresholdMin) {
      msec = 0; // keep resetting timer if above threshold
    } else if (msec > 30) {
      //Serial.println("begin state 0");
      state = 0; // go back to idle after 30 ms below threshold
    }
  }
  
}
 
OK, now hopefully we're getting somewhere, I will get the components, is there a chance the teensy is damaged already? if so how could I test it? The blink and the buttons programs still work. I only have an ohm meter and when I squeeze and tap the piezo as hard as I can I get little more than 1 volt. I have my unit built which is just 20 pads, bass drum and hi hat pedals and a few buttons and pots for controlling midi functions. Is this doable with the 3.6? I have the usb type set at serial+midi correct? For now my goal is to get 1 piezo to trigger a midi note with velocity sense. Thanks for helping.
 
Last edited:
Yes, Paul posted a very nice application specific example sketch!

Not sure if there is a better way but each affected input exposed to direct Piezo input could be careful connected to GND and 3.3V in turn running Paul's Sketch and watch for full range values - or attach the wiper part of a POT and run it through some range testing.

Typical Ohmmeter does relatively slow repeat samples and perhaps averaging so it won't generally show the real time peaks generated.
 
is there a chance the teensy is damaged already?

Yes, there is a chance your Teensy may be damaged. But the total energy from those piezos is pretty small, so odds are probably in your favor. Hopefully you'll get lucky and have it working fine.

if so how could I test it?

You could use a pot or resistors to create known voltage, and then compare the result of analogRead().

I have my unit built which is just 20 pads, bass drum and hi hat pedals and a few buttons and pots for controlling midi functions. Is this doable with the 3.6?

Maybe. The hard part is you'll need to do 20 analogRead to capture all the inputs, which is 20X slower than just 1 input. If the peak is very narrow, you might end of reading slight before or after the actual peak.
 
I tried your code but no response with a piezo, the serial monitor says- piezo peak capture, peak = 507. this value changes when I hit the button on the board and it reboots but nothing happens when I tap the piezo. I have it connected +to analog 0 and - to analog ground with a 1m ohm between. I have yet to get any response from the piezo Any suggestions? I still just want to get 1 piezo to trigger a note or do something that tells me its working or not. I've tested the piezo itself and all connections Is this not the right board for what I'm trying to do?
 
Last edited:
I have it connected +to analog 0 and - to analog ground with a 1m ohm between.

That doesn't sound anything like the circuit I recommended.

In fact, I don't even know what "with a 1m ohm between" means. You really need to be more precise in words, or post photos showing the wiring clearly. I highly recommend using photos, even if you believe the words are clear. There are so many opportunities for misunderstanding. That's why I gave you pictures of the circuitry I tested yesterday.
 
I tried to upload a photo but it fails, anyway if you look at this link there are photos, I did exactly the same thing except with the teensy. https://www.sparkfun.com/tutorials/330. What I meant was the pull down resistor between the+and the-. I don't have the components to make your circuit yet, I assumed the diodes and resisters in your circuit were for protection and that if i taped lightly on the piezo I could at least get a response. If that were going to damage the board then it's damaged already because i tried this before you recommended the circuit. At this point I just want to make sure the board is ok and why I can't get the piezo to do anything. If it turns out I damaged it and I had to buy another so be it. If you say the only way to test it is with that circuit than I'll have to get the components.
 
The piezo if working will generate a voltage - but should be used in a controlled circuit as provided. Until then if you want to test the Teensy see notes posts #13 and #14 above - set up a POT or use known resistor values that should give consistent readings from 3.3V - or carefully GND the pin and then test again with 3.3V carefully attached on what ever analog pin is under test.

I'd do this with the revised post #7 sketch to test function so the values are not filtered. You could expand that code to read all the pins you want to in turn. With indication of the pins to be tested and your desire to do so - somebody might even provide working tested code - but showing your start and success on at least one pin with simple tests and that sketch would be good practice.

<edit> : Photo Limit is near 1MB for JPG or PNG
 
Last edited:
I don't have the components to make your circuit yet, I assumed the diodes and resisters in your circuit were for protection and that if i taped lightly on the piezo I could at least get a response. If that were going to damage the board then it's damaged already because i tried this before you recommended the circuit. At this point I just want to make sure the board is ok and why I can't get the piezo to do anything. If it turns out I damaged it and I had to buy another so be it. If you say the only way to test it is with that circuit than I'll have to get the components.

Just for my understanding... You just took a piezo and connected it to the Teensy without studying the piezo's and the Teensy's data sheets before to make sure that the voltage levels would match and that no harm would be done to either of these?

That would be a highly non-scientific approach! Please don't take it as personal critics, but I think it is important to mention here for all Teensy newbies:

Always solve a problem (be it circuit design or code) first in theory, studying data sheets, doing the needed analysis, calculus, and verifications, for example checking sub circuits with an oscilloscope to make sure that everything will run within safe boundaries before connecting things together and powering these. On the code side, know first what input your code will need, how to capture/interface it, which output you expect, and draw a flow diagram first. Then translate the flow diagram blocks into code one after another, and write test code to verify your code blocks individually before merging everything together into a large program.
 
Sparkfun's piezo tutorial is horrible.

As defragster suggested, use a pot (not the piezo) to test if your board is still working and able to read analog voltage.
 
To test your analog port you could also jumper DAC0 (A21) to A0 and run this little sketch
Code:
void setup() {
  Serial.begin(9600);
  analogWriteResolution(12);
  analogReadResolution(12);
}

void loop() {
  for (int i = 0; i < 4095; i += 32) {
    analogWrite(A21, i);    // DAC
    delayMicroseconds(10);   // DAC settle time
    Serial.print(i); Serial.print(" ");
    Serial.println(analogRead(A0));
    delay(500);  // regulate output speed
  }
}

other piezo test circuits i've seen use a zener diode (e.g. 3v3) to clamp voltage.
piezocircuit.png

T3.2 with just 1 Mohm and then with 5.1v zener
piezo.pngpiezoz.png

T3.6 is NOT 5v tolerant, so you would want a 3.3v zener diode for T3.6
 
Last edited:
Thanks, I appreciate your help, I tried the first test connecting A21 to A0 and running your code The serial monitor just keeps printing 2 rows of 4 digit numbers, It makes no difference when I disconnect the jumper. fried?
 
well, the two columns should be close in value
Code:
0 1
32 31
64 62
96 94
128 126
160 159
192 190
...
1376 1377
1408 1408
1440 1441
1472 1472
1504 1505
while it`s running if you remove the jumper from the DAC and plug it into GND, the 2nd column should go to 0 (or 1 ish)

with no jumper, you get random numbers in the 2nd column from the unconnected/floating A0. the first column is just the DAC value (i) counting from 0 to 4095 by 32

as noted photos of your setup would be helpful, try converting photos to .png or reducing size, (forum won't upload "big" photos). or take a photo with your smartphone and select a small size to save. is your T3.6 soldered to its header pins?
 
Last edited:
Back
Top