Turning a pin HGH for 1 minute then LOW after a condition

Hi there; It's hot here in Tanzania.

I'm trying to follow the post, coding without delay().

When a sensor is HIGH, I want a pin (labeled fanPin and led) to to HIGH too for 1 minute then turn them LOW when the time is up ; regardless of sensor state (HIGH or LOW).
Here is where I get lost; When the elapsedTime greater than 1 minute and the the sensor is still HIGH, the code is keep looping and those intended pin never get LOW.

In general, I need to control a window with a dc motor, hence I want to turn the motor on for 1 min to open, the power off the motor.
Any advice I can accept, and sorry for not following the rules, if my question is badly asked.

here are my sketch:

int led = 13;
int fanPin = 8;
int sensor = 2;
unsigned long startTime;
unsigned long elapsedTime;
unsigned long currentTime;
long oneMinute = 10000;

unsigned long previousTime = 0;
bool timeRunning = 1; // true if still waiting for delay to finish

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);   // initialize the digital pin as an output.
  pinMode(fanPin, OUTPUT);
  pinMode(sensor, INPUT);
  digitalWrite(led, LOW); // turn led off
  digitalWrite(fanPin, LOW);
  digitalWrite(sensor, LOW);
 
}

void loop() {
  currentTime = millis();
  if ( (digitalRead(sensor) == HIGH) || (timeRunning == 1)){ // pin with internal pullup, button 
    if (timeRunning == 0){
      startTime =millis();
      timeRunning = 1; // flag to show timer is started
      digitalWrite(led, HIGH); // motor is powerled
      digitalWrite(fanPin, HIGH);
      }
    elapsedTime = currentTime - startTime;
    if (elapsedTime >=oneMinute){
      digitalWrite(fanPin, LOW);
      digitalWrite(led, LOW);// unpower the motor 
      timeRunning = 0;
    
    }
  }
}

Your problem is that you have no state information to tell you that the window is already open, so your code just blindly try to open it again and again if the sensor is high.

You could add a boolean WindowIsOpen variable to help.

Or you could never set timeRunning back to 0. If you take this route, you'll probably have to refactor your code when you add something to close the window, but it should get your code working to your current requirements.

You need to clarify what you want to happen if the sensor is still HIGH after 1 minute, once you've turned off ? is there a 10 minute delay before which you don't want to activate fanPin for example ? (or are you ever closing that window?)

Welcome and congratulation for posting of the very first post with code tags (</>) and with enough clarification of the problem.

You may experiment your ideas (what you has expressed in your posted code) on the following start-up (working) codes. We need to begin from somewhere simple and then gradually add the complexities.

int led = 13;
int fanPin = 8;
int sensor = 2;
unsigned long startTime;
unsigned long elapsedTime;
unsigned long currentTime;
unsigned long oneMinute = 60000;//10000; unit ms

unsigned long previousTime = 0;
bool timeRunning = false;//1; // true if still waiting for delay to finish

void setup() 
{
  Serial.begin(9600);
  pinMode(led, OUTPUT);   // initialize the digital pin as an output.
  pinMode(fanPin, OUTPUT);
  pinMode(sensor, INPUT);   //engage external pull-down`  `
  digitalWrite(led, LOW); // turn led off
  digitalWrite(fanPin, LOW);
  // digitalWrite(sensor, LOW);

}

void loop()
{
  currentTime = millis();
  if (digitalRead(sensor) == HIGH)
  {
    digitalWrite(led, HIGH);
    digitalWrite(fanPin, HIGH);
    timeRunning = true;
    while ((millis() - currentTime) <= oneMinute)
    {
      ;
    }
    digitalWrite(led, LOW);
    digitalWrite(fanPin, LOW);
    timeRunning = false;
  }
}

GolamMostafa:
…code

@GolamMostafa

I think advanced users in the forum should help newcomers move away from slow Serial communication with their PCs. so I feel we should not post any code withSerial.begin(9600);as a best practice. Start moving everyone to 115200 or more. Current PCs and Arduinos have no problems dealing with that baud rate.

On this code:

    while ((millis() - currentTime) <= oneMinute)
    {
      ;
    }

that’s a pretty bad demonstration of using millis() (and overuse of expression)… why don’t you just call delay(oneMinute); this would make it easier for OP to understand what you do (and oneMinute could be defined as a const)

Why do you declare and use timeRunning for? that adds to the confusion

it would have been also a good idea to suggest to declare the pins as const byte.

with that in mind, your code becomes simpler to read:

const byte ledPin = 13;
const byte fanPin = 8;
const byte sensorPin = 2;
const unsigned long oneMinute = 60000ul;

void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);   // initialize the digital pin as an output. LOW by default
  pinMode(fanPin, OUTPUT);
  pinMode(sensorPin, INPUT);   //engage external pull-down if needed
}

void loop()
{
  if (digitalRead(sensorPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(fanPin, HIGH);
    delay(oneMinute);
    digitalWrite(ledPin, LOW);
    digitalWrite(fanPin, LOW);
  }
}

but I’m not sure it meets the needs of OP

1 Like

J-M-L:
@GolamMostafa

1. Bd = 9600 or 115200
I prefer Bd = 9600 considering the ‚ÄėUART Frame Time‚Äô and Software UART Port which works well at lower Bd; otherwise 115200 is fine!

2. millis() function
The OP has used this function in his sketch. The millis() function will allow the OP to check the current HIGH/LOW status of his sensor if he desires.

3. timeRunning flag
As OP has used it in his sketch, I have intended to give a demonstration as to the situation when the flag should be activated/deactivated.

4. while ((millis() - currentTime) <= oneMinute)
while(millis() - currentTime <= oneMinute) would be suffice; but, I have preferred to associate millis() and currentTime by pair of parentheses in order to show OP that (millis() - currentTime) would be evaluated first and then the comparison.

OK - got your intent. may be you could have suggested exploration path as the construct as it stands as blocking code in the loop which is not a best practice if OP wanted to study the "without delay" construct

I disagree on the baud rate given this is Hardware Serial as slow baud rates (esp. when debugging) can create artifacts due to the small outgoing buffer that can pause code for longer than needed and creates side effects on other time critical elements - but you are entitled to your view of course.

J-M-L:
On this code:

    while ((millis() - currentTime) <= oneMinute)

{
     ;
   }



that's a pretty bad demonstration of using millis()

I referred to his previous suggestion to use that code as ‚Äúblink without delay, with delay‚ÄĚ.

When the elapsedTime greater than 1 minute and the the sensor is still HIGH, the code is keep looping and those intended pin never get LOW.

You need to detect when an input becomes HIGH or LOW rather than when it is HIGH or LOW. Take a look at the StateChangeDetection example in the IDE

UKHeliBob:
You need to detect when an input becomes HIGH or LOW rather than when it is HIGH or LOW. Take a look at the StateChangeDetection example in the IDE

Thanks; I'll look it

GolamMostafa:
1. Bd = 9600 or 115200
I prefer Bd = 9600 considering the ‚ÄėUART Frame Time‚Äô and Software UART Port which works well at lower Bd; otherwise 115200 is fine!

2. millis() function
The OP has used this function in his sketch. The millis() function will allow the OP to check the current HIGH/LOW status of his sensor if he desires.

3. timeRunning flag
As OP has used it in his sketch, I have intended to give a demonstration as to the situation when the flag should be activated/deactivated.

4. while ((millis() - currentTime) <= oneMinute)
while(millis() - currentTime <= oneMinute) would be suffice; but, I have preferred to associate millis() and currentTime by pair of parentheses in order to show OP that (millis() - currentTime) would be evaluated first and then the comparison.

Thanks buddy for such detailed reply, sure I’m trying to avoid the use of delay so I can monitor other inputs

wildbill:
Your problem is that you have no state information to tell you that the window is already open, so your code just blindly try to open it again and again if the sensor is high.

You could add a boolean WindowIsOpen variable to help.

Or you could never set timeRunning back to 0. If you take this route, you'll probably have to refactor your code when you add something to close the window, but it should get your code working to your current requirements.

While reading your reply; I get the idea but once I start coding, things becomes trickier.
I'll need something to indicate the window is open or close for sure;
I've exhausted my mind today