[SOLVED] Reading analog input from piezo

I have encountered the same problem as the guy here

I wanted to comment on it, but it's read only, so I am reposting in hopes somepony might find my findings useful.

I have tried running the same sketch as in the link above, but I couldn't get it to work. I pulled out my scope and a multimeter. I have measured the output voltage of the piezo to be >2 volts when I knock the table on my scope, which was confirmed by the CREST function of my multimeter. However, the Arduino didn't seem to care.

Turns out the code is sampling the ADC at a VERY low rate and thus it just skips the knock most of the time.

If you are encountering my problem, simply comment out the line that says // delay(100); // delay to avoid overloading the serial port buffer

Now the sensor reading is happening much quicker. Of course, the correct solution would be to reduce the resolution of the adc to get quicker sampling, and then handle the sampling itself in low level macros, but this works too, so whatever. Just set the threshold to about 10 and it'll work well unless you are in super electrically noisy environment.

Edit: failed to mention that the resulting code will spit out "Knock" more than once after the knock. Ideally, we should do a peak detection to find a local maximum and move on from there...

I wasn’t happy with the knock sensor example, so I rolled my own.
It reads at least one full knock sinewave, and stores the positive peak.
Very sensitive.

// knock sensor/alarm
// Piezo, with 1Megohm load resistor across, connected to A0 and ground
// optional 5volt buzzer on pin 13

int threshold = 100; // alarm threshold from 1 (very sensitive) to 1022 <<<<<<<<
int alarmDuration = 100; // alarm duration in milliseconds <<<<<<<<

const byte piezoPin = A0;
int rawValue; // raw A/D readings
int piezoValue; // peak value
const byte onboardLED = 13; // onboard LED and/or buzzer

void setup() {
  analogReference(INTERNAL); // remove this line if too sensitive
  Serial.begin(115200); // serial monitor for raw piezo output
  pinMode (onboardLED, OUTPUT);

void loop() {
  // reset
  piezoValue = 0;
  // read
  for (int x = 0; x < 250; x++) { // multiple A/D readings
    rawValue = analogRead(piezoPin);
    if (rawValue > piezoValue) {
      piezoValue = rawValue; // store peaks
  // print
  if (piezoValue > 0) {
    Serial.print(F("Piezo value is "));
  // action
  if (piezoValue > threshold) {
    Serial.print(F("Knock was over the threshold of "));
    digitalWrite (onboardLED, HIGH);
    digitalWrite (onboardLED, LOW);

Thanks a lot! I was originally also considering changing the reference for better sensitivity. I do believe that the "delay(100)" line was supposed to be a part of the original condition...

void loop() {
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);
  //  Serial.println(sensorReading);
  // if the sensor reading is greater than the threshold:

  if (sensorReading >= threshold) {

    // toggle the status of the ledPin:
    ledState = !ledState;
    // update the LED pin itself:
    digitalWrite(ledPin, ledState);
    // send the string "Knock!" back to the computer, followed by newline
//  delay(100);  // delay to avoid overloading the serial port buffer

I'll go test your code now!

EDIT: Tested, works nicely! I like how you are storing the strings in flash, nice attention to detail.