How can I keep an alarm on for at least 4 seconds after it had been triggered?

New to all of this and would appreciate some help. How can I keep an alarm on for a period of time (4 seconds) after it had been triggered and the threshold is no longer exceeded? If the threshold continues to be exceeded I would like the alarm to continue sounding but if the threshold was triggered for an instant I would like the alarm to sound for a minimum of 4 seconds.

I found an example online and changed it up a bit but cannot figure out how to keep the alarm on for a certain period of time. Also, it is important that the serial printer not be impacted when a delay is set as I would like to continue to take readings at a different pace (other than every 4 seconds). Thanking you in advance for your help.

/*
Analog Input
Demonstrates analog input by reading an analog sensor on analog pin 0 and
turning on alarm connected to digital pin 13 for at least 4 seconds when
threshold is exceeded. Alarm should stop sounding once sensorValue is below threshold
but alarm should always sound for at least 4 seconds.
*/

int sensorPin = A0; // select the input pin for the analog sensor
int alarmPin = 13; // select the pin for the piezo alarm
int sensorValue = 0; // variable to store the value coming from the sensor

void setup() {
// declare the alarmPin as an OUTPUT:
pinMode(alarmPin, OUTPUT);
Serial.begin(9600);
}

void loop() {
int threshold = 512;
if(analogRead(sensorPin) > threshold)
{
digitalWrite(alarmPin, HIGH);
}
else{ digitalWrite(alarmPin, LOW);
}
int sensorValue = analogRead(A0);
Serial.println(sensorValue);

}

give this a try after carefull reading ... (not tested)

int sensorPin = A0;    // select the input pin for the analog sensor
int alarmPin = 13;     // select the pin for the piezo alarm
int sensorValue = 0;  // variable to store the value coming from the sensor

unsigned long switchoff = 0;
int threshold = 512;

void setup() 
{
  // declare the alarmPin as an OUTPUT:
  pinMode(alarmPin, OUTPUT);
  Serial.begin(9600); 
}

void loop() 
{
  // measurement
  sensorValue = analogRead(A0);
  // display
  Serial.println(sensorValue);
  // action
  if(sensorValue  > threshold) 
  {
     digitalWrite(alarmPin, HIGH);
     switchoff = millis()+4000;
  }

  if (millis() > switchoff && switchoff > 0)
  {
    digitalWrite(alarmPin, LOW);
    switchoff = 0;
  }
}

Thanks Rob! Works perfectly. As a newbie I had to laugh after reading your disclaimer "give this a try after careful reading" as I am illiterate to the code (but working hard to remedy that) and still can't believe I haven't set my minicontroller on fire yet! I really appreciate the help. Would you mind if I ask another question or two?

Is there a way that I can also set a delay so that the alarm will not trigger for a certain period of time (2 seconds) after the threshold has been exceeded? This way I can filter out any noise or false triggers.

Also, how could I serial print a number (say 500) when the alarm is triggered and have it stay at that number for the time that the alarm stays triggered. The number should fall back to 0 after the alarm is disengaged. This way I will eventually be able to plot the data for the analog input and alarm to see what was happening to the analog signal and how often and for how long the alarm was triggered over a period of time (buying a data logger from Adafruit).

Thanks again for the help.

I changed the code around but can't figure out how to create a delay that would prevent the alarm from sounding once it is activated (to avoid false triggers). Could someone take a peek and let me know where I am going wrong? I highlighed the problem areas in red. As I am new writing the actual code for examples is very helpful. The below sketch works perfectly except for the switchOn delay. I appreciate the help.

//Alarm program that will trigger alarm after short delay and will keep the alarm on for a minimum amount of time.

int sensorPin = A0; // input pin for the analog sensor
int alarmPin = 13; // pin for the piezo alarm
unsigned int sensorValue = 0; // stores value coming from the sensor
unsigned int alarmStarted = 0; // stores when last alarm started
unsigned int alarmEnded = 0; // stores when last alarm ended
unsigned int alarmCount = 0; // stores number of times alarm was triggered
unsigned long duration = 0; // stores total seconds alarmState was HIGH
unsigned int average = 0; // stores average length of time each alarm was on
int alarmState=LOW; // sets the inital alarmState to off
int lastAlarmState=LOW; // sets the inital lastAlarmState to off
unsigned switchOff = 0; // stores min time alarm needs to be on for
unsigned switchOn = 0; // stores min time of alarm delay
unsigned int threshold = 512; // threshold value needed to set off alarm

void setup(){
pinMode(alarmPin, OUTPUT); // enable output on the alarmPin
Serial.begin(9600); // start serial printer
alarmState=digitalRead(13); // reads pin 13 to set alarmState to HIGH or LOW
}

void loop() {

sensorValue = analogRead(A0); // read analog pin 0 to determine sensorValue
lastAlarmState=alarmState; // stores last value for alarmState
alarmState=digitalRead(13); // reads pin 13 to set alarmState to HIGH or LOW

if(sensorValue > threshold) {
digitalWrite(alarmPin, HIGH); // turn on alarm when threshold is exceeded
switchOn = millis()+4000; // delay alarm from sounding for a # of millis
switchOff = millis()+4000; // keep alarm on for a min of # millis
alarmStarted = millis(); // start timer when alarm is triggered
}

if (millis() > switchOn && switchOn > 0) {
digitalWrite(alarmPin, HIGH); // turn alarmPin on after a delay of millis
switchOn = 0; // reset switchOn delay timer back to 0
}
if (millis() > switchOff && switchOff > 0) {
digitalWrite(alarmPin, LOW); // turn alarmPin off after a delay of millis
switchOff = 0; // reset switchOff timer back to 0
}

if(alarmState==HIGH && lastAlarmState==LOW) {
alarmCount++; // add 1 to counter each time new alarm triggers
}

if(alarmState == HIGH) {
duration = millis(); // stores total seconds alarmState was HIGH
}

Serial.println(sensorValue); // print what the current sensorValue is
Serial.println(alarmCount); // print the number of times alarm was triggered
Serial.println(duration/1000); // print the total seconds alarmState was HIGH
Serial.println(average = (duration/alarmCount)/1000); // print avg secs for ea alarm
delay(250); // wait here 250 millis before moving on

}

Could someone take a peek and let me know where I am going wrong?

A very quick peak reveals that you are posting code incorrectly. After a couple of posts, you should learn how to post code correctly. Above the text entry box, there are a series of buttons. We know you found them, because you colored your text. One of them has a # on it. Select that BEFORE pasting code. Do not try to color-code code. Color-coding is for text (and should be removed as an option, in my opinion).

Look at the comments you wrote here:

     digitalWrite(alarmPin, HIGH); // turn on alarm when threshold is exceeded
     switchOn = millis()+4000;     // delay alarm from sounding for a # of millis

Now, why you want to set a time in the future to turn the alarm on, AFTER you turn the alarm on escapes me.

If you delay 2 seconds, the alarm will still sound, even if it is triggered by noise?!
Why nt trying Rob's running average to smooth out the reading instead?
http://arduino.cc/playground/Main/RunningAverage

liudr; Thank you for the suggestion. I also would like to delay the alarm from sounding even for a legitimate trigger. Do you know how I could alter the code to make that happen?

PaulS; Thanks for the tip on how to post code the correct way (not sure of the difference but will find out next time using the # key). I appreciate your response but since I am new to this (like about a week!) and have been playing around with programming for the first time in my life it all looks greek to me. I am struggling to learn and would appreciate any help that you are willing to provide. Best way to help someone as green as me (in my humble opinion) is to provide the code that you are referring to so that I can learn what it does (I barely know what the code I am cobbling together does). Over time I will be able to fish on my own and will pass the help that those provided to me onto someone else who is trying to learn something for the first time. Please feel free to post code as examples if you like. Thanks again.

Do you know how I could alter the code to make that happen?

Yes. Think about how YOU would perform the action that you want the Arduino to perform.

You really need to separate the need for action (the alarm was triggered) from the action (scream).

The need for action is detected by this code:

  sensorValue = analogRead(A0);    // read analog pin 0 to determine sensorValue
   if(sensorValue  > threshold) {

So, what you do then is set a flag that indicates that action will be required. Do not actually perform any action.

Then, later, you check whether action is required, and if it is time to perform that action.

if(switchOn > 0 && millis() - switchOn)
{
   // Turn the alarm on
}

Now, I realize that the coding looks all Greek to you, so I suggest that you study this page:

Go through all your code. Look at each function call, operator, etc. Use the reference page as needed, to understand exactly what each line of code is doing. Feel free to ask if anything is unclear.

If I were sitting in the same room with you, we would talk about your code, until you understood exactly what it was doing. Understanding the code will not necessarily mean that you could create it from scratch, but not understanding it guarantees that you won't be able to.

There are many people that answer questions on the forum that feel the same as I do - that anyone that is making an effort to learn is to be helped as much as possible. You seem to be trying, so don't feel that any question is off-limits.

Thanks PaulS. I appreciate your advice. I have been trying to get the alarm to delay with your example since your last post. I still can't figure out where I am going wrong. I suppose the excitement of trying to complete my first project is getting the best of me. I will visit the site you referred to and the bookstore to begin my journey on learning a new language. In a few weeks I hope to understand a lot more than I do now. If you had the time and wanted to comment on what you see wrong with the below code (posted properly I hope as I did use the # button ) so that I can at least save this feeling a sense of accomplishment I would appreciate it.

Also, after the serial printer is running for a couple of minutes the led begins to dim and flutter until I close out the serial printer window and reopen it again. Then all runs well for another couple of minutes (with the exception of the alarm trigger delay not working) until the problem occurs again. Does this mean I filled up all the memory? I ordered a data logger from adafruit that will save to an SD card. If this is the problem hopefully the data-logger will solve it (lots of data to record)!

int sensorPin = A0;               // input pin for the analog sensor
int alarmPin = 13;                // pin for the piezo alarm
unsigned int sensorValue = 0;     // stores value coming from the sensor
unsigned int alarmStarted = 0;    // stores when last alarm started
unsigned int alarmEnded = 0;      // stores when last alarm ended
unsigned int alarmCount = 0;      // stores number of times alarm was triggered
unsigned long duration = 0;       // stores total seconds alarmState was HIGH 
unsigned int average = 0;         // stores average length of time each alarm was on
int alarmState=LOW;               // sets the inital alarmState to off
int lastAlarmState=LOW;           // sets the inital lastAlarmState to off
long switchOff = 0;               // stores min time alarm needs to be on for
long switchOn = 0;                // stores min time of alarm delay
unsigned int threshold = 512;     // threshold value needed to set off alarm


void setup(){
  pinMode(alarmPin, OUTPUT);       // enable output on the alarmPin
  Serial.begin(9600);              // start serial printer
  alarmState=digitalRead(13);      // reads pin 13 to set alarmState to HIGH or LOW
 }

void loop() {
  
  sensorValue = analogRead(A0);    // read analog pin 0 to determine sensorValue
  lastAlarmState=alarmState;       // stores last value for alarmState
  alarmState=digitalRead(13);      // reads pin 13 to set alarmState to HIGH or LOW
  
   if(sensorValue  > threshold) {
     switchOn = millis()-4000;     // delay alarm from sounding for a # of millis
     switchOff = millis()+4000;    // keep alarm on for a min of # millis
  }
  
   if (switchOn > 0 && millis() - switchOn) {
     digitalWrite(alarmPin, HIGH); // turn alarmPin on after a delay of millis
     switchOn = 0;                 // reset switchOn delay timer back to 0 
 }
 
   if (millis() > switchOff && switchOff > 0) {  
     digitalWrite(alarmPin, LOW);  // turn alarmPin off after a delay of millis
     switchOff = 0;                // reset switchOff timer back to 0
  }
 
   if(alarmState==HIGH && lastAlarmState==LOW) {  
     alarmCount++;                 // add 1 to counter each time new alarm triggers
  }  
  
   if(alarmState == HIGH) {
     duration = millis();          // stores total seconds alarmState was HIGH
     Serial.println("500");        // prints 500 while alarm is active
  } 
  
    if(alarmState == LOW) {
      Serial.println("0");         // prints 0 while the alarm is not active
  }
    
  Serial.println(sensorValue);     // print what the current sensorValue is
  Serial.println(alarmCount);      // print the number of times alarm was triggered
  Serial.println(duration/1000);   // print the total seconds alarmState was HIGH 
  Serial.println(average = (duration/alarmCount)/1000); // print avg secs for ea alarm
  delay(250);    // wait here 250 millis before moving on
}
   if (switchOn > 0 && millis() - switchOn) {
     digitalWrite(alarmPin, HIGH); // turn alarmPin on after a delay of millis
     switchOn = 0;                 // reset switchOn delay timer back to 0 
 }

The first line needs >= 0 at the end:

   if (switchOn > 0 && millis() - switchOn >= 0)
{

(It also needs the curly brace in the right place - on a line of its own. The rest of your code could stand to be improved the same way.)