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
asked Nov 15, 2018 at 10:32
2

2 Answers 2

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); 
} 
answered Nov 15, 2018 at 10:59
5
  • 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... Commented Nov 15, 2018 at 12:03
  • @rachetfreak is confusing now() and millis(). Commented Nov 15, 2018 at 12:09
  • @hmppp sorry I did indeed mix up now() and millis(). It's fixed now in the answer. Commented Nov 15, 2018 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. Commented Nov 15, 2018 at 12:48
  • @rachetfreak, tried with 10s function, am able to get it uploaded and worked! thank you so much :) Commented Nov 16, 2018 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.

answered Nov 15, 2018 at 12:07
3
  • 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? :/ Commented Nov 15, 2018 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. Commented Nov 15, 2018 at 12:32
  • I tried both the codes the sample implementation give a error message that getMaximum is not declared. :/ Commented Nov 15, 2018 at 12:46

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.