0

I am student that is new to Arduino and working on a project to trigger an alert if the sound level detected exceeds the threshold for a period of 2 mins. But I am stuck, would like to check how do I write a code to analog read sound sensor input and light up sensor if the readings is above datum for 2 mins? I had simple code but it triggers the light up immediately. :/

I have combined the coding together and this is the new code that worked with the help gotten:

    #define led 4 // led to D4 
const int soundsensor= A0; //sound sensor to A0
const int threshold= 100; // to set the threshold value for sound sensor
int ssanalogread; //name of sound sensor analog read
bool wasOver;//add to globals
unsigned long firstDetect;


void setup() {
  Serial.begin(9600);
  pinMode(led,OUTPUT);
  pinMode(soundsensor,INPUT);// to get input from sound sensor

} // end void setup


void loop() {

     sound1();

} // close void loop


void sound1() {

  ssanalogread=analogRead(soundsensor); // reads analog data from sound sensor
  Serial.println(ssanalogread);

   if ((ssanalogread > threshold)){ //replace if else
      if(!wasOver){
       firstDetect = millis();
   }
   if(millis() - firstDetect > 1*10*1000){
      digitalWrite(led,HIGH); //turns led on if the sensor reads more than threshold
   } //end if
      wasOver = true;
   } // end first if
  else {
     wasOver = false;
     digitalWrite(led,LOW); 
  } // end else

} //end loop


//this code works and is ok to run. can adjust the timing
1

You set a timestamp when the sound first exceeds the threshold and only set the output high when millis() - firstDetect > 2*60*1000

//add to globals
bool wasOver;
unsigned long firstDetect;

//replace if else
if ((ssanalogread > threshold)){
   if(!wasOver){
       firstDetect = millis();
   }
   if(millis() - firstDetect > 2*60*1000){
      digitalWrite(led,HIGH); //turns led on if the sensor reads more than threshold
   } //end if
   wasOver = true;
} else {
   wasOver = false;
   digitalWrite(led,LOW); 
} 
|improve this answer|||||
  • Hi Ratchet, thank you so much for your enlightenment! I have combine your coding together with mine (edited in original post), however there's an error message of : "exit status 1 Error compiling for board Arduino/Genuino Uno." :/ Not sure if i defined now() correctly... – hmppp Nov 15 '18 at 12:03
  • @rachetfreak is confusing now() and millis(). – Majenko Nov 15 '18 at 12:09
  • @hmppp sorry I did indeed mix up now() and millis(). It's fixed now in the answer. – ratchet freak Nov 15 '18 at 12:22
  • @rachetfreak and Majenko thanks both for the prompt assistance! i couldn't get the led to light up for this code after 2 mins. It was observed from the serial monitor that the data was about 270++. had adjusted my threshold to 200, however the light sensor still couldn't light up. I am using Grove base shield for this. – hmppp Nov 15 '18 at 12:48
  • @rachetfreak, tried with 10s function, am able to get it uploaded and worked! thank you so much :) – hmppp Nov 16 '18 at 5:59
1

This is actually a lot harder than you might at first think.

Your "sound sensor" is little more than a microphone and amplifier. It gives you an audio waveform - whereas what you are interested in is the peak power.

An audio waveform goes both positive and negative:

enter image description here

The "peak" of the waveform can both be positive (above the line) or negative (below the line).

To get that peak you have to rapidly sample over a short period and find both the maximum and minimum values, and get the difference between them.

However, the Arduino can't see negative values on the ADC - so you only get the upper portion of the waveform, which is less than ideal. Really you should add a DC offset to the output of the sound sensor to bring the signal up to the middle of the ADC range (adding a 10kΩ + 10kΩ voltage divider across the input pin to +5V/GND would do the job).

If you don't add a DC offset then you can rapidly sample for a short period of time and work out the maximum value:

uint16_t getMaximum(uint8_t pin, uint32_t t) {
    uint16_t maximum = 0;
    uint32_t ts = millis();
    while (millis() - ts < t) {
        uint16_t sample = analogRead(pin);
        if (sample > maximum) {
            maximum = sample;
        }
    }
    return maximum;
}

Now to get the maximum over, say, a 10ms period, you can:

uint16_t maximum = getMaximum(A0, 10);

However, if you add a DC offset it gets a little more tricky, but the results will be better:

uint16_t getMaximum(uint8_t pin, uint32_t t) {
    int16_t maximum = 0;
    int16_t minimum = 0;
    uint32_t ts = millis()
    while (millis() - ts < t) {
        // The -512 here removes the DC offset from the reading. 512 is half
        // the ADC range.
        int16_t sample = analogRead(pin) - 512;
        if (sample > maximum) {
            maximum = sample;
        }
        if (sample < minimum) {
            minimum = sample;
        }
    }

    // We now have a positive value as the maximum and a negative
    // as the minimum - or zero if none went into the max or min
    // region of the waveform.  Subtract a negative from a positive
    // is like adding a positive to a positive.  But we only want
    // a positive result, so we'll get the absolute value.
    return abs(maximum - minimum);
}

Now that you actually have your peak-peak value of your waveform over a short period you can use it to work out when the sound goes above a threshold and when it goes below, and how long it's been above that threshold. The basic method is:

  • Is the sound above the threshold?
    • Yes: Was it above the threshold before?
    • No: Set a timestamp and a flag to say it's above the threshold.
    • Yes: Has it been above > 2 minutes?
      • Yes: light the LED
    • No: Was it above the threshold before?
    • Yes: Has it been above > 2 minutes?
      • Yes: Extinguish the LED

The thing here is to know that you are looking for changes in the "above the threshold" state to start your timing. A simple implementation may look like:

static uint32_t wentAbove = 0;
static bool isAbove = false;
const uint16_t threshold = 300;

uint16_t maxval = getMaximum(A0, 10);

if (maxval > threshold) {
    if (!isAbove) {
        isAbove = true;
        wentAbove = millis();
    } else {
        if (millis() - wentAbove > 120000) {
            digitalWrite(13, HIGH);
        }
    }
} else {
    if (isAbove) {
        isAbove = false;
        digitalWrite(13, LOW);
    }
}

Note: all code untested.

|improve this answer|||||
  • Hi Majenko, thank you for your detailed explanation. Sorry i am very new to programming and arduino and has some trouble understanding. Could you enlighten me what does uint32_t t in uint16_t getMaximum(uint8_t pin, uint32_t t) do and how should i define getMaximum? :/ – hmppp Nov 15 '18 at 12:30
  • unsigned 32-bit integer. It's the same as "unsigned long" - but explicit. You don't need to "define" these functions - I have defined them for you. Just copy and paste. – Majenko Nov 15 '18 at 12:32
  • I tried both the codes the sample implementation give a error message that getMaximum is not declared. :/ – hmppp Nov 15 '18 at 12:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.