If pin is high then timer starts.

So, im beginner in programming . Could someone can help me with the code. I want add the timer(delay), when pin 13 is high. So, when value is more than 70 then i want pin 13 high for about 3 minutes. There is code:

const int sensorPin= 0;
const int buzzerPin= 13;
int smoke_level;

void setup() {
Serial.begin(115200); //
pinMode(sensorPin, INPUT);//the smoke sensor will be an input to the arduino
pinMode(buzzerPin, OUTPUT);//the buzzer serves an output in the circuit
}

void loop() {
smoke_level= analogRead(sensorPin); //arduino reads the value from the smoke sensor
Serial.println(smoke_level);//prints just for debugging purposes,
if(smoke_level > 70){ //
digitalWrite(buzzerPin, HIGH);
}
else{
digitalWrite(buzzerPin, LOW);
}
}

Please correct your post above and add code tags around your code. [code] // your code here [/code]. it should look like this:// your code here

Also before pasting code, press ctrl-T in the IDE so that the lines are indented.

two options for your code:

Option one is just to add delay for 3 minutes after turning on the buzzer and then turning it LOW.

  if (smoke_level > 70) { //
    digitalWrite(buzzerPin, HIGH);
    delay(180000ul); // note the ul to ensure we pass an unsigned long to the function
    digitalWrite(buzzerPin, LOW);
  } // no need for else, the buzzer pin is LOW by default all the time

this is very simple and can do the job if you don't want to do anything else in the code. this is called an ACTIVE WAIT. you are stuck in the delay() and have no way to check other things while the buzzer is buzzing. can be painful if you want to turn it off for example...

An alternative approach is to manage state (a very simple state machine). Basically you have two states in your program, one is the Alarm is Off and one is the Alarm is On. The default state is Alarm is OFF and you transition the state Alarm is ON when the smoke detector level is above 70. you return to the state Alarm OFF after 3 minutes (regardless of the state of Smoke detector during those 3 minutes).

That approach has the merit to incur no active wait, the code just check in which state it is and decides what to do if one of the condition to transition state is reached. but then you can do other things of interest like blinking a led or whatever even while the buzzer is ON because there is no active wait.

here is what it could look like (not tested, justed typed in here)

const int sensorPin = 0;
const int buzzerPin = 13;
int smoke_level;

enum {ALARM_OFF, ALARM_ON} alarmStatus;
unsigned long alarmStartTime;
const unsigned long alarmDuration = 3ul * 60ul * 1000ul; // 3 minutes in ms. using 'ul' to force unsigned long calculation

void setup() {
  Serial.begin(115200); //
  pinMode(sensorPin, INPUT);//the smoke sensor will be an input to the arduino
  pinMode(buzzerPin, OUTPUT);//the buzzer serves an output in the circuit
  alarmStatus = ALARM_OFF;
}


void loop() {
  if (alarmStatus == ALARM_OFF) {
    // alarm is OFF, checks if we need to turn it ON
    smoke_level = analogRead(sensorPin); //arduino reads the value from the smoke sensor
    Serial.println(smoke_level);//prints just for debugging purposes,
    if (smoke_level > 70) {
      alarmStatus = ALARM_ON;
      alarmStartTime = millis();
      digitalWrite(buzzerPin, HIGH);
    }
  } else {
    // alarm is ON, checks if we need to turn it OFF
    if (millis() - alarmStartTime >= alarmDuration) {
      digitalWrite(buzzerPin, LOW);
      alarmStatus = ALARM_OFF;
    }
  }
}

Now - the code can do other things, like checking a button to stop the Alarm. That would just add a new transition condition, if Alarm is ON and I press on the button, then move to the state alarm OFF. --> I let you implement this and show us the code you get. (you need to do a bit of work!)

Use a variable for the start time

void loop ()
{
  static unsigned long buzzerStartTime = 0;
  ...
  ...
}

Set it when you detect the 70.

void loop ()
{
  static unsigned long buzzerStartTime = 0;
  ...
  ...
  if(smoke_level > 70)
  {
    if (buzzerStartTime == 0)
    {
       digitalWrite(buzzerPin, HIGH);
       buzzerStartTime = millis ();
    }
  }
}

And next you can test for the duration

void loop ()
{
 static unsigned long buzzerStartTime = 0;
 ...
 ...
 if(smoke_level > 70)
 {
   if (buzzerStartTime == 0)
   {
      digitalWrite(buzzerPin, HIGH);
      buzzerStartTime = millis();
   }
 }

 if (millis() - buzzerStartTime >= 180000UL)
 {
      digitalWrite(buzzerPin, LOW);
      buzzerStartTime = 0;
 }
}

buzzerStartTime serves two purposes; when 0 it acts as a flag indicating that the buzzer is off, if not 0 it's the time that the buzzer was started.

Note that if the smoke level is still exceeded after the 3 minutes, it will immediately stsrt beeping again. IT was not clear from your description if that is what you want or not.

sterretje:
buzzerStsrtTime serves two purposes; when 0 it acts as a flag indicating that the buzzer is off, if not 0 it's the time that the buzzer was started.

the small intellectual issue I have with that approach is that if you are very unlucky and smoke level goes above 70 just when in a bit more than 49 days at the time millis() rolls over then you initialize buzzerStartTime to zero and your flag is not really meaningful then. of course the way you wrote this is not an issue, either smoke level is still > 70 next time you get in the loop and you just trigger the buzzer again while it's already on and then buzzerStartTime takes a new value or if you've been unlucky and the level went straight below 70 the alarm will still sound and stop because you don't check buzzerStartTime to zero in the second test.

So in that case all works, but if the action was not to turn on a pin but increase by 10° the position of a servo, then you would end up possibly increasing it by 20° in that small rare case. Hence I tend to pay the price for an additional value and create a real state machine and use timing for only timing.

Talking about timing - as a side note, I would write if (millis() - buzzerStartTime >= 180000[color=red][b]ul[/b][/color]) just to be on the safe side

I'm still battling with that rollover, but point taken. Need to check it.

I think it will work without UL because all variables are unsigned long. But I changed it while you were replying to play it safe :wink:

sterretje:
I'm still battling with that rollover, but point taken. Need to check it.

I think it will work without UL because all variables are unsigned long. But I changed it while you were replying to play it safe :wink:

Yes - that does work indeed (code to verify this below), as I said it's just to be on the safe side and take good habits when playing with numbers. I know you understand this, it was more for beginners to learn best practices.

for example if you had written (3 * 60 * 1000) to spell out the 3 minute calculation then that would fail (but nowadays the compiler would warn you of integer overflow).

void setup()
{
  unsigned long test = 181000ul;
  Serial.begin(115200);
  if (test > 180000) Serial.println("Maths are working fine");
  else Serial.println("Something is wrong with my code");

  if (test > (3*60*1000)) Serial.println("Maths are working fine");
  else Serial.println("Something is wrong with my code");

}

void loop(){}