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
-
What "sound sensor" are you using?Majenko– Majenko2018年11月15日 10:43:50 +00:00Commented Nov 15, 2018 at 10:43
-
Hi i am using grove sound sensor: wiki.seeedstudio.com/Grove-Sound_Sensor and grove water sensor: wiki.seeedstudio.com/Grove-Water_Sensorhmppp– hmppp2018年11月15日 11:45:26 +00:00Commented Nov 15, 2018 at 11:45
2 Answers 2
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);
}
-
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– hmppp2018年11月15日 12:03:02 +00:00Commented Nov 15, 2018 at 12:03
-
@rachetfreak is confusing
now()
andmillis()
.Majenko– Majenko2018年11月15日 12:09:30 +00:00Commented Nov 15, 2018 at 12:09 -
@hmppp sorry I did indeed mix up now() and millis(). It's fixed now in the answer.ratchet freak– ratchet freak2018年11月15日 12:22:42 +00:00Commented 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.hmppp– hmppp2018年11月15日 12:48:50 +00:00Commented Nov 15, 2018 at 12:48
-
@rachetfreak, tried with 10s function, am able to get it uploaded and worked! thank you so much :)hmppp– hmppp2018年11月16日 05:59:38 +00:00Commented Nov 16, 2018 at 5:59
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:
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.
-
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– hmppp2018年11月15日 12:30:44 +00:00Commented 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.Majenko– Majenko2018年11月15日 12:32:00 +00:00Commented Nov 15, 2018 at 12:32
-
I tried both the codes the sample implementation give a error message that getMaximum is not declared. :/hmppp– hmppp2018年11月15日 12:46:23 +00:00Commented Nov 15, 2018 at 12:46
Explore related questions
See similar questions with these tags.