project 12 Arduino Starter Kit, Knock Lock problem

Dear all

I am trying to work on project 12 Knock Lock, and I think there must be a problem with the Piezo Buzzer I am using (or the code provided on the book!)

I include the function here below:

// this function checks to see if a  
// detected knock is within max and min range
boolean checkForKnock(int value){
  // if the value of the knock is greater than
  // the minimum, and larger than the maximum
  if(value > quietKnock && value < loudKnock){
    // turn the status LED on
    digitalWrite(yellowLed, HIGH);
    delay(500);
    digitalWrite(yellowLed, LOW);
    // print out the status
    Serial.print("Valid knock of value ");
    Serial.println(value);
    // return true
    return true;
  }
  // if the knock is not within range
  else {
    // print status
    Serial.print("Bad knock value ");
    Serial.println(value);  
    // return false
    return false;
  }
}

The problem I am facing is, when the Piezo detects the correct value (say 23) from a single knock, the program goes into turning on the yellow LED. That is fine. But I can observe on my Serial Monitor the knockVal showing 23 (or 24) endlessly in the loop without returning back to zero (and the yellow LED never gets turned off) ! Somehow when I removed :

digitalWrite(yellowLed, HIGH);
    delay(500);
    digitalWrite(yellowLed, LOW);

the knockVal did return to Zero after the single knock on the Piezo.

When I changed the delay value to 10 (see below) it works as well! (the knockVal returned to zero)

why didn’t delay(500) work??

it is very bizzare! can anyone explain to me what happened please?

Thanks!

Can you post the rest of the code. I suspect there’s an interaction we can’t see w/o it.

Here it is the full code! thanks!

// import the library 
#include <Servo.h>
// create an instance of the servo library
Servo myServo;

const int piezo = A0;      // pin the piezo is attached to
const int switchPin = 2;    // pin the switch is attached to
const int yellowLed = 3;    // pin the yellow LED is attached to
const int greenLed = 4;    // pin the green LED is attached to
const int redLed = 5;   // pin the red LED is attached to

// variable for the piezo value
int knockVal;
// variable for the switch value
int switchVal;

// variables for the high and low limits of the knock value
const int quietKnock = 10;
const int loudKnock = 100;

// variable to indicate if locked or not
boolean locked = false;
// how many valid knocks you've received
int numberOfKnocks = 0;

void setup(){
  // attach the servo to pin 9
  myServo.attach(9);

  // make the LED pins outputs
  pinMode(yellowLed, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);

  // set the switch pin as an input
  pinMode(switchPin, INPUT);

  // start serial communication for debugging
  Serial.begin(9600);

  // turn the green LED on
  digitalWrite(greenLed, HIGH);

  // move the servo to the unlocked position
  myServo.write(0);

  // print status to the serial monitor
  Serial.println("the box is unlocked!");
}

void loop(){

  // if the box is unlocked
  if(locked == false){

    // read the value of the switch pin
    switchVal = digitalRead(switchPin);

    // if the button is pressed, lock the box
    if(switchVal == HIGH){
      // set the locked variable to "true"
      locked = true;

      // change the status LEDs
      digitalWrite(greenLed,LOW);
      digitalWrite(redLed,HIGH);

      // move the servo to the locked position
      myServo.write(90);

      // print out status
      Serial.println("the box is locked!");

      // wait for the servo to move into position
      delay (1000);
    }
  }

  // if the box is locked
  if(locked == true){

    // check the value of the piezo
    knockVal = analogRead(piezo);

    // if there are not enough valid knocks
    if(numberOfKnocks < 3 && knockVal > 0){

      // check to see if the knock is in range
      if(checkForKnock(knockVal) == true){

        // increment the number of valid knocks
        numberOfKnocks++;
      }

      // print status of knocks
      Serial.print(3 - numberOfKnocks);
      Serial.println(" more knocks to go");
    }

    // if there are three knocks
    if(numberOfKnocks >= 3){
      // unlock the box
      locked = false;

      // move the servo to the unlocked position
      myServo.write(0);

      // wait for it to move
      delay(20);

      // change status LEDs
      digitalWrite(greenLed,HIGH);
      digitalWrite(redLed,LOW);
      Serial.println("the box is unlocked!");
    }
  }
}

// this function checks to see if a  
// detected knock is within max and min range
boolean checkForKnock(int value){
  // if the value of the knock is greater than
  // the minimum, and larger than the maximum
  if(value > quietKnock && value < loudKnock){
    // turn the status LED on
    digitalWrite(yellowLed, HIGH);
    delay(50);
    digitalWrite(yellowLed, LOW);
    // print out the status
    Serial.print("Valid knock of value ");
    Serial.println(value);
    // return true
    return true;
  }
  // if the knock is not within range
  else {
    // print status
    Serial.print("Bad knock value ");
    Serial.println(value);  
    // return false
    return false;
  }
}

I don’t see anything wrong with the code and I’d have been surprised if I did. What flavor of Arduino are you running this on ? Check that the board selected under the Tools menu in the Arduino IDE is your flavor of Arduino. Also when you changed the delay to 10, did the yellow LED flash ever so briefly or did it stay on for some noticable time ? If the the latter would you do an experiment ? Could you measure the time the LED stays on (just count 1001, 1002, etc) for delays of 10, 20, 50 ? What I’m thinking is that the clock on your Arduino is somehow slower than the 16 MHz expected and the timing functions aren’t “aware” of it. So a delay of 500 msecs is really something quite a bit longer and if you waited that long you’d eventually see the knock work as expected. How much longer or how much slower ? The experiment (if my thinking is correct) will tell us.

Hi thanks for the reply.

I am using the official Arduino Uno.

When the delay is 10, the LED flashes only very briefly. I have used delay 500 before to flash LED in other projects and it worked just fine. I did some further test (delay 10, 20, 25, 30), up to delay (25), it worked just fine, but after that it stopped working! I wonder if there is something “strange” with my Piezo?

Thanks!

I don’t see how the piezo could make these symptoms, short of it having somehow zapped the Uno in some odd fashion I can’t understand. Try this code, it doesn’t use the delay() function to control the LED on time.

    // this function checks to see if a 
    // detected knock is within max and min range
    boolean checkForKnock(int value){
      // if the value of the knock is greater than
      // the minimum, and larger than the maximum
      unsigned long onTime;
      if(value > quietKnock && value < loudKnock){
        // turn the status LED on
        digitalWrite(yellowLed, HIGH);
        onTime = millis();
        while(millis() - onTime < 500){
          //do nothing but wait for 500 msecs
          __asm__("nop\n\t"); 
        }
        digitalWrite(yellowLed, LOW);
        // print out the status
        Serial.print("Valid knock of value ");
        Serial.println(value);
        // return true
        return true;
      }
      // if the knock is not within range
      else {
        // print status
        Serial.print("Bad knock value ");
        Serial.println(value); 
        // return false
        return false;
      }
    }

As to why your Arduino hangs with a delay > 25 … that’s odd and I can’t help but think some register or memory internal to the Arduino’s 328 is zapped. But then I can’t understand why the delay(1000), used when locking the box, doesn’t hang the Uno as well. And Uno is selected as the board in the IDE ? :?: :shock: :think:

it looks like I have a dodgy piezo! I just swapped the pizeo with a new one and it is now working with delay (500)! I wonder what happened to the bad piezo?

Your blink code without using delay() works like a charm! thanks a lot. What does this line do:?

asm(“nop\n\t”);

Well that’s both good and odd. I guess you can mark this thread as soIved now. I looked at the schematic and have decided that plugging the piezo into your Arduino w/nothing more than a 1 M resistor in parallel is not a good idea. I sufficiently “knocked” piezo can generated voltages over + and - 100 V !!! That could damage the input pin and cause weird resets (see links below). But I don’t think you were seeing resets and why it affected only “long” delays … I just don’t get it.

http://forum.arduino.cc/index.php/topic,4350.0.html

http://todbot.com/blog/2006/10/29/spook … l-arduino/

http://leucos.lstilde.org/wp/2009/06/pi … ditioning/

The asm tells the Arduino compiler that the instruction is in Assembly (not C, C++) and to do a “no op(eration)”, basically to do nothing.

http://playground.arduino.cc/Main/AVR