Arduino Clapper - Clap Clap = On - Clap Clap = Off

I was checking this other thread out, but couldn't make it work with the Sound Sensor I got on eBay a long time ago.

Here's the old thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1251151678

Here's the sensor:

http://www.ebay.com/itm/Sound-Sensor-Module-Arduino-Sensor-Shield-MCU-PIC-/120758238742?pt=LH_DefaultDomain_0&hash=item1c1dc07e16

Edit: here's the final product video, for more videos, check the other posts below.

So I decided to create my own code nearly from scratch, this works perfectly with that Sound Sensor, and has some error checking and noise detection.

Since the plan is to use this on our bedroom, I added a touch-sensor (just put a wire connected to any metal thingy into a digital input) to also turn the lights on/off.

The relay for the 220V lights I will be using is this one:
http://www.ebay.com/itm/Mini-5V-DC-SONGLE-Power-Relay-SRD-5VDC-SL-C-PCB-Type-/320571789994

Its very easy to setup the relay. At the bottom you will see 5 connections, the left 3, the middle goes to your 110/220V power. Left and right to the Arduino Ground and output pin. Them the other 2 are the On and Off outputs for the 110/220 destination, in this case, our lights. 8)

So, I just tested the whole thing with an ATtiny85 using its internal 8Mhz clock and it works perfectly. Here's the complete code as I'm using on the ATtiny85.

I use the info from the Beat707 BigtTime code, found over the following link: https://github.com/Beat707/Beat707-BigTime

I didn't use an Arduino as I need something very small to fit on the power-box that has the current light on/off switch, I will replace the whole thing with this setup: ATtiny85, Mini Relay and 5V USB 110/220V adapter from an old Wii controller charger that was no longer used. (the controllers batteries failed, but the charger still works, 5V @ 500ma)

Everything is working perfectly and its already in place. I will post some pictures and videos soon. :wink:

In the end, here's the code I'm using. It only turns the lights off when you clap-clap, to avoid getting them to turn on in the middle of the night if you cough. :wink:

Here are the videos:

After using it on the "real" world, I had to do some changes on the code. Now I save to the EEPROM the Background-Noise levels, so when the power fails, which happens a lot here, it doesn't mess up the system if it startups again and there's some noises going on... Also, fixed some other issues.

// Arduino Clapper - by WilliamK @ Wusik.com & Beat707.com - September 06 2011 - V 1.2.0 //
// On V1.2.0, when powering up, it will flash the output them detect for 10 seconds any ambient noise and save into the EEPROM and flash the output once its finished //

#include <EEPROM.h>

#define inPin A1                // Pin input for the audio sensor
#define outPin 0               // Output pin to active external device (use relay for 110/220V)
#define touchPin PINB4         // Must be in PINB# format (digital pin 8 ~ 13 = PINB0 ~ PINB5)
#define clapTime 200           // How long to wait between claps
#define clapIdle 1000          // How long to wait after 2 claps before turning on external device
#define debounceTime 150       // Debounce time, to remove double inputs due to echoing
#define waitBeforeRetry 2000   // How long to wait before trying again after a failed set of claps or loud background noise/sounds
#define delayAfterSwitch 500   // How long to wait after a switch has happened
#define defaultSensitivity 50  // 50 should be ok for most uses
#define outputToSerial 0       // Outputs Stage information to the Serial Device
#define force_new_background 0 // If set to 1 it will force a new Noise Background check

// ------------------------------------------------------------------------------------------------------------------------ //
int def2, num1, num2, num3, def = 0;
uint8_t isOn = false;
uint8_t prevIsOn = false;
unsigned long lastMillis = millis();
uint8_t stage = 0;
#if outputToSerial
  uint8_t prevStage = 9;
#endif
int sensitivity = defaultSensitivity;
int lastValue = 0;
uint8_t prevButton = 0;
uint8_t curButton = 0;
uint8_t wasButtonLow = 1;

// ------------------------------------------------------------------------------------------------------------------------ //
void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);
  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}

// ------------------------------------------------------------------------------------------------------------------------ //
unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address);
  byte highByte = EEPROM.read(p_address + 1);
  return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}

// ------------------------------------------------------------------------------------------------------------------------ //
void setup()  
{
  pinMode(outPin, OUTPUT);
  pinMode(inPin, INPUT);
   
  if (EEPROM.read(0) != 24 || force_new_background) // Check for the Background Noise //
  { 
    delay(2000);

    digitalWrite(outPin, HIGH);
    delay(150);
    digitalWrite(outPin, LOW);
    
    for (char x=0; x<4; x++)
    { 
      delay(1000);
      num1 = analogRead(inPin);
      delay(250);
      num2 = analogRead(inPin);
      delay(250);
      num3 = analogRead(inPin);
      def2 = ((num1 + num2 + num3) / 3) + sensitivity;
      if (def2 > def) def = def2;
    }
    
    for (char x=0; x<6; x++)
    { 
      delay(1000);
      num1 = analogRead(inPin);
      delay(250);
      num2 = analogRead(inPin);
      delay(250);
      num3 = analogRead(inPin);
      def2 = ((num1 + num2 + num3) / 3) + sensitivity;
      if (def2 < def) def = def2;
    }
    
    // Write Default Background Noise //
    EEPROMWriteInt(1, def);
    EEPROM.write(0, 24);
    
    digitalWrite(outPin, HIGH);
    delay(150);
    digitalWrite(outPin, LOW);
  }
  
  #if outputToSerial
    Serial.begin(38400);
  #endif
  
  prevButton = getcap(1<<PINB0);
  def = EEPROMReadInt(1);
}

// ------------------------------------------------------------------------------------------------------------------------ //
void loop()  
{
  lastValue = analogRead(inPin);
  
  if (isOn)
  {
    switch (stage)
    {
      case 0: if (lastValue > def) { lastMillis = millis() + clapTime; stage = 1; delaySomeTime(debounceTime); } break;   
      case 1: if (lastValue > def) { stage = 5; lastMillis = millis() + waitBeforeRetry; } else if (millis() > lastMillis) { stage = 2; lastMillis = millis() + clapTime; } break;
      case 2: if (lastValue > def) { lastMillis = millis() + clapIdle; stage = 3; delaySomeTime(debounceTime); } else if (millis() > lastMillis) { stage = 5; lastMillis = millis() + waitBeforeRetry; } break;
      case 3: if (lastValue > def) { stage = 5; lastMillis = millis() + waitBeforeRetry; } else if (millis() > lastMillis) stage = 4; break;
      case 4: if (lastValue < def) { isOn = !isOn; } stage = 0; break;
      
      case 5: // This is the Wait Before Retrying stage //
        if (lastValue > def) lastMillis = millis() + waitBeforeRetry; else if (millis() > lastMillis) stage = 0;
        break;
    }
  }
  
  #if outputToSerial
    if (stage != prevStage)
    {
      Serial.println(stage, DEC);
      prevStage = stage;
    }
  #endif
  
  checkButton();
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkNewOn()
{
  if (isOn != prevIsOn)
  {
    digitalWrite(outPin, isOn);
    prevIsOn = isOn;
    delay(delayAfterSwitch);
  }
}

// ------------------------------------------------------------------------------------------------------------------------ //
void delaySomeTime(unsigned long ms)
{
  uint16_t start = (uint16_t)micros();

  while (ms > 0) 
  {
    if (((uint16_t)micros() - start) >= 1000) 
    {
      ms--;
      start += 1000;
    }
    checkButton();
  }
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkButton()
{
  curButton = getcap(1<<touchPin);
  
  if (curButton != prevButton)
  {
    prevButton = curButton;
    if (wasButtonLow == 1 && curButton > 1)
    {
      isOn = !isOn;
      wasButtonLow = 0;
      stage = 0;
      checkNewOn();
      delay(500);
    }
    if (curButton <= 1) wasButtonLow = 1;
  }
  
  checkNewOn();
}

// ------------------------------------------------------------------------------------------------------------------------ //
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 2; i++) 
  {
    if( (PINB & pin) ) break;
  }
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

My you have been busy! Nice work!

Thanks.

Last night the lights would turn off just by opening the bathroom door or by speaking, so I had to revisit the code. Also, we had some power spikes here and in one of those the device wouldn't work anymore, as it got a loud background noise when it powered up again, so I had to come with another solution. :wink:

In the next few days we will know if this is really good now. 8)

I really love working with the Arduino IDE, its just pure fun.

Do you think people need some Fritzing files on how I connected the whole thing up? Its actually easy, as the ATtiny85 has so few pins. :wink:

Wk

Its working much better with the new code now, yeah! Its still a bit too sensitive at the default values, so, when I close the bathroom door, the clicks the door makes shut down the lights. But that's ok, its not often. :wink:

Wk

I had to update the code, as the lights were turning off with no apparent reason, so I did some hacks to the code and now its 99% perfectly. Before, closing a door would turn the lights off too.

// Arduino Clapper - by WilliamK @ Wusik.com & Beat707.com - September 06 2011 - V 1.2.0 //
// On V1.2.0, when powering up, it will flash the output them detect for 10 seconds any ambient noise and save into the EEPROM and flash the output once its finished //

#include <EEPROM.h>

#define inPin A1                // Pin input for the audio sensor
#define outPin 0               // Output pin to active external device (use relay for 110/220V)
#define touchPin PINB4         // Must be in PINB# format (digital pin 8 ~ 13 = PINB0 ~ PINB5)
#define clapTime 250           // How long to wait between claps
#define clapIdle 1000          // How long to wait after 2 claps before turning on external device
#define debounceTime 100        // Debounce time, to remove double inputs due to echoing
#define waitBeforeRetry 3000   // How long to wait before trying again after a failed set of claps or loud background noise/sounds
#define delayAfterSwitch 500   // How long to wait after a switch has happened
#define defaultSensitivity 50  // 50 should be ok for most uses
#define outputToSerial 0       // Outputs Stage information to the Serial Device
#define force_new_background 0 // If set to 1 it will force a new Noise Background check

// ------------------------------------------------------------------------------------------------------------------------ //
int def2, num1, num2, num3, def = 0;
uint8_t isOn = false;
uint8_t prevIsOn = false;
unsigned long lastMillis = millis();
uint8_t stage = 0;
#if outputToSerial
  uint8_t prevStage = 9;
#endif
int sensitivity = defaultSensitivity;
int lastValue = 0;
uint8_t prevButton = 0;
uint8_t curButton = 0;
uint8_t wasButtonLow = 1;

// ------------------------------------------------------------------------------------------------------------------------ //
void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);
  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}

// ------------------------------------------------------------------------------------------------------------------------ //
unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address);
  byte highByte = EEPROM.read(p_address + 1);
  return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}

// ------------------------------------------------------------------------------------------------------------------------ //
void setup()  
{
  pinMode(outPin, OUTPUT);
  pinMode(inPin, INPUT);
   
  if (EEPROM.read(0) != 24 || force_new_background) // Check for the Background Noise //
  { 
    delay(2000);

    digitalWrite(outPin, HIGH);
    delay(150);
    digitalWrite(outPin, LOW);
    
    for (char x=0; x<4; x++)
    { 
      delay(1000);
      num1 = analogRead(inPin);
      delay(250);
      num2 = analogRead(inPin);
      delay(250);
      num3 = analogRead(inPin);
      def2 = ((num1 + num2 + num3) / 3) + sensitivity;
      if (def2 > def) def = def2;
    }
    
    for (char x=0; x<6; x++)
    { 
      delay(1000);
      num1 = analogRead(inPin);
      delay(250);
      num2 = analogRead(inPin);
      delay(250);
      num3 = analogRead(inPin);
      def2 = ((num1 + num2 + num3) / 3) + sensitivity;
      if (def2 < def) def = def2;
    }
    
    // Write Default Background Noise //
    EEPROMWriteInt(1, def);
    EEPROM.write(0, 24);
    
    digitalWrite(outPin, HIGH);
    delay(150);
    digitalWrite(outPin, LOW);
  }
  
  #if outputToSerial
    Serial.begin(38400);
  #endif
  
  prevButton = getcap(1<<PINB0);
  def = EEPROMReadInt(1);
}

// ------------------------------------------------------------------------------------------------------------------------ //
void loop()  
{
  lastValue = analogRead(inPin);
  
  if (isOn)
  {
    switch (stage)
    {
      case 0: if (lastValue > (def+10)) { lastMillis = millis() + clapTime; stage = 1; delaySomeTime(debounceTime); } break;   
      case 1: if (lastValue > (def+10)) { stage = 5; lastMillis = millis() + waitBeforeRetry; } else if (millis() > lastMillis) { stage = 2; lastMillis = millis() + clapTime; } break;
      case 2: if (lastValue > (def+10)) { lastMillis = millis() + clapIdle; stage = 3; delaySomeTime(debounceTime); } else if (millis() > lastMillis) { stage = 5; lastMillis = millis() + waitBeforeRetry; } break;
      case 3: if (lastValue > (def+10)) { stage = 5; lastMillis = millis() + waitBeforeRetry; } else if (millis() > lastMillis) stage = 4; break;
      case 4: if (lastValue < def) { isOn = !isOn; } stage = 0; break;
      
      case 5: // This is the Wait Before Retrying stage //
        if (lastValue > (def+10)) lastMillis = millis() + waitBeforeRetry; else if (millis() > lastMillis) stage = 0;
        break;
    }
  }
  
  #if outputToSerial
    if (stage != prevStage)
    {
      Serial.println(stage, DEC);
      prevStage = stage;
    }
  #endif
  
  checkButton();
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkNewOn()
{
  if (isOn != prevIsOn)
  {
    digitalWrite(outPin, isOn);
    prevIsOn = isOn;
    delay(delayAfterSwitch);
  }
}

// ------------------------------------------------------------------------------------------------------------------------ //
void delaySomeTime(unsigned long ms)
{
  uint16_t start = (uint16_t)micros();

  while (ms > 0) 
  {
    if (((uint16_t)micros() - start) >= 1000) 
    {
      ms--;
      start += 1000;
    }
    checkButton();
  }
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkButton()
{
  curButton = getcap(1<<touchPin);
  
  if (curButton != prevButton)
  {
    prevButton = curButton;
    if (wasButtonLow == 1 && curButton > 1)
    {
      isOn = !isOn;
      wasButtonLow = 0;
      stage = 0;
      checkNewOn();
      delay(500);
    }
    if (curButton <= 1) wasButtonLow = 1;
  }
  
  checkNewOn();
}

// ------------------------------------------------------------------------------------------------------------------------ //
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 2; i++) 
  {
    if( (PINB & pin) ) break;
  }
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

When you connected the sound sensor...

Did you power it from the Arduino's 5v? Or was it powered by something higher? (Ebay description speaks of supplying "<=12v"... 5v seems a LOT "less than", but it would be so nice if the device was as simple as I am hoping... (^_^)

Yes, I used the 5V, it lowers the sensitivity a lot, but still works. If you need the full-range-sensitivity, use 12V.

Wk

Here's a new code which works much better.

// Arduino Clapper - by WilliamK @ Wusik.com & Beat707.com - November 06 2011 - V 1.4.0 //
// On V1.4.0, a volume checker is placed which checks for background noise x sound "pops".

#define inPin A1               // Pin input for the audio sensor
#define outPin 0               // Output pin to active external device (use relay for 110/220V)
#define touchPin PINB4         // Must be in PINB# format (digital pin 8 ~ 13 = PINB0 ~ PINB5)

// ------------------------------------------------------------------------------------------------------------------------ //
uint8_t isOn = false;
uint8_t prevIsOn = false;
uint8_t prevButton = 0;
uint8_t curButton = 0;
uint8_t wasButtonLow = 1;

unsigned long sensorValue = 0;
unsigned char counter = 0;
unsigned long backgroundNoise = 0;
unsigned char claps = 0;
unsigned long milliS = millis();

// ------------------------------------------------------------------------------------------------------------------------ //
void setup()  
{
  pinMode(outPin, OUTPUT);
  pinMode(inPin, INPUT);
  
  prevButton = getcap(1<<PINB0);
}

// ------------------------------------------------------------------------------------------------------------------------ //
void loop()  
{  
  if (isOn)
  {
    sensorValue += analogRead(inPin);
    counter++;
    if (counter > 125)
    {
      if (backgroundNoise > 0 && sensorValue > (backgroundNoise+1400))
      {
        claps++;
        if (claps == 2) milliS = millis() + 1000; else milliS = millis() + 4000;
      }
      if (sensorValue > backgroundNoise) backgroundNoise = sensorValue;
        else if (backgroundNoise > sensorValue && backgroundNoise >= 400) backgroundNoise -= 400;
      counter = 0;
      sensorValue = 0;
    }
    delayMicroseconds(250);
  
    if (milliS > 0 && millis() > milliS)
    {
      if (claps == 2)
      {
        isOn = !isOn;
        checkNewOn();
      }
      
      claps = milliS = 0;
    }
  }
  
  checkButton();
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkNewOn()
{
  if (isOn != prevIsOn)
  {
    digitalWrite(outPin, isOn);
    prevIsOn = isOn;
    sensorValue = backgroundNoise = claps = counter = milliS = 0;
    delay(2000);
  }
}

// ------------------------------------------------------------------------------------------------------------------------ //
void checkButton()
{
  curButton = getcap(1<<touchPin);
  
  if (curButton != prevButton)
  {
    prevButton = curButton;
    if (wasButtonLow == 1 && curButton > 1)
    {
      isOn = !isOn;
      wasButtonLow = 0;
      checkNewOn();
      delay(500);
    }
    if (curButton <= 1) wasButtonLow = 1;
  }
  
  checkNewOn();
}

// ------------------------------------------------------------------------------------------------------------------------ //
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 2; i++) 
  {
    if( (PINB & pin) ) break;
  }
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

http://www.ebay.com/itm/Sound-Sensor-Module-Arduino-Sensor-Shield-MCU-PIC-/120758238742?pt=LH_DefaultDomain_0&hash=item1c1dc07e16

Is this sensor capable or recording audio too?
Or does it only measure energy levels?

Can someone suggest a programmable clap project ? Similar to secret knock..so one can program it in a way the light with 2 claps, the TV 3 claps, and so ???

Mixx Tail Cocktail advertisement reference?