Running an action for "x" seconds after a switch closes

I’m new at coding and looking for some help here.

My project is to us a UNO and a motor driver to PWM a solenoid to activate a proportional hydraulic valve. However I do not want to PWM the solenoid all the time. I only want to PWM the solenoid when a switch is closed. I also only want it to PWM the solenoid for 3 seconds after the switch closes. Then when the switch opens, repeat after the switch closes again.

So far i have this:

void setup()
{
  Serial.begin(9600);
  pinMode( 1, INPUT);
  pinMode( 13 , OUTPUT);

}

void loop()
{
  if (( ( digitalRead(1) ) == ( HIGH ) ))
  {
    digitalWrite( 13 , HIGH );
    delayMicroseconds( 100 );
    digitalWrite( 13 , LOW );
    delayMicroseconds( 900 );
  }
}

I can make the 10% PWM cycle active when the switch is closed and stop when the switch is open. But what I’m having trouble with is getting the code to only run the PWM for 3seconds until it sees the switch open and close again.

The searches I’ve come up with so far have not been what I’m looking for or to far above my head right now.

Thanks for the help

Don’t use pin 1 as it is used by Serial communications.

Look at ‘change in state and the blink without delay’ in the IDE examples.

BTW
What is ‘your’ definition of PWM.

Thanks for the links I'll take a look

My definition for PWM is Pulse Width Modulation

One easy way to “do X for time interval Y when event Z”:

unsigned long TimerStart = 0;
const unsigned long TimeIntervalY = 3000;  // Three Seconds

void loop()
{
  if (Z)
    timerStart = millis();

  if (TimerStart != 0 && millis() - TimerStart < TimeIntervalY)
  {
    Do X
  }
  else
  {
    TimerStart = 0;
  }
}

KEwert:
Thanks for the links I'll take a look

My definition for PWM is Pulse Width Modulation

Are you aware there are PWM pins on the Arduino?

You can
analogWrite(myPWMpin, 0 to 255)

Thanks John your code got me there 99% of the way. However just one problem, its working a little backwards of what I need.

With the switchPin pulled LOW the pwmPin is inactive (which is what I need), but when I pull the switchPin HIGH, the pwmPin runs continuously and never stops. Then when I pull the switchPin LOW, the controller waits for 3 seconds and then turns off the pwmPin.

What I need is when the switchPin is pulled HIGH, I need the pwmPin to run for 3 seconds and then turn off until it sees the switchPin cycle LOW to HIGH again.

Here is the code I have now:

const int switchPin = 8;
const int pwmPin = 13;
unsigned long timerStart = 0;
const unsigned long TimeIntervalY = 3000;  // Three Seconds
  
void setup()
{
  pinMode( switchPin, INPUT);
  pinMode( pwmPin , OUTPUT);

}
void loop()
{
  if (( ( digitalRead(switchPin) ) == ( HIGH ) ))
    timerStart = millis();

  if (timerStart != 0 && millis() - timerStart < TimeIntervalY)
  {
    digitalWrite( pwmPin , HIGH );
    delayMicroseconds( 100 );
    digitalWrite( pwmPin , LOW );
    delayMicroseconds( 900 );
  }
  else
  {
   timerStart = 0;
  }
}

Did you read and understand these discussions?

delayMicroseconds( 900 ); //This is a blocking line of code and circumvents using the BWD technique.

/*
  My project is to us a UNO and a motor driver to PWM a solenoid to activate a proportional hydraulic valve.
  However I do not want to PWM the solenoid all the time.

  I only want to PWM the solenoid when a switch is closed.                        <-----<<<<<

  I also only want it to PWM the solenoid for 3 seconds after the switch closes.  <-----<<<<<

  Then when the switch opens, repeat after the switch closes again.
*/

const int switchPin             = 8;
const int pwmPin                = 13;

const unsigned long operateTime = 3000ul;  //three seconds
const unsigned long offTime     = 900ul;   //in microseconds
const unsigned long onTime      = 100ul;   //in microseconds

unsigned long interval          = offTime;
unsigned long timerStart;
unsigned long previousMillis;
unsigned long previousMicros;

byte lastState;
byte currentState;
byte outputState;

boolean enableFlag = false;     //if true, we are timing


//****************************************************************************************
void setup()
{
  pinMode(switchPin, INPUT);          //switch pushed gives HIGH
  lastState = digitalRead(switchPin);

  pinMode(pwmPin , OUTPUT);
  //ensure solenoid is off
  outputState = LOW;
  digitalWrite(pwmPin, outputState);

} //END of setup()

//****************************************************************************************
void loop()
{
  //***************************************
  //the switch is currently HIGH? and we are within 3 seconds?
  if (enableFlag == true && millis() - timerStart < operateTime)
  {
    if (micros() - previousMicros >= interval)
    {
      previousMicros = micros();

      //select next interval and pin level
      if (interval == onTime)
      {
        interval = offTime;
        outputState = LOW;
      }
      else
      {
        interval = onTime;
        outputState = HIGH;
      }

      digitalWrite(pwmPin, outputState);
    }

  } //END of if((enableFlag == true && millis() - timerStart < operateTime)

  else
  {
    //we are now finished, cancel this timing period
    enableFlag = false;

    //reset conditions
    interval = offTime;
    //ensure the solenoid is off
    outputState = LOW;
    digitalWrite(pwmPin, outputState);
  }

  //***************************************
  //time to check the switches?
  if (millis() - previousMillis > 50) //every 50ms
  {
    previousMillis = millis();

    checkSwitches();
  }

} //END of loop()


//****************************************************************************************
void checkSwitches()
{
  currentState = digitalRead(switchPin);

  //has the switch changed state?
  if (lastState != currentState)
  {
    //update to the new state
    lastState = currentState;

    //do 'just pushed' switch stuff?
    if (currentState == HIGH)
    {
      //enable timing
      enableFlag = true;
      //initialize PWM timers
      timerStart = millis();
      previousMicros = micros();
    }

    //do 'just released' switch stuff
    else
    {
      //disable timing
      enableFlag = false;
    }
  }

} //END of checkSwitches()

//****************************************************************************************

Edit
Code updated

KEwert:
With the switchPin pulled LOW the pwmPin is inactive (which is what I need), but when I pull the switchPin HIGH, the pwmPin runs continuously and never stops. Then when I pull the switchPin LOW, the controller waits for 3 seconds and then turns off the pwmPin.

My example covered the “run for 3 seconds” part. I left the “state change detection” part up to you, as pointed out by other people. Here is a quick edit to put in the “state change detection” part:

const int switchPin = 8;
const int pwmPin = 13;
unsigned long TimerStart = 0;
const unsigned long TimeIntervalY = 3000;  // Three Seconds

void setup()
{
  pinMode( switchPin, INPUT);
  pinMode( pwmPin, OUTPUT);
}

void loop()
{
  bool switchIsOn = digitalRead(switchPin) == HIGH;
  static bool switchWasOn = false;

  if (switchIsOn && !switchWasOn)
    TimerStart = millis();  // Start the timer each time the switch changes to ON

  switchWasOn = switchIsOn;

  if (TimerStart != 0 && millis() - TimerStart < TimeIntervalY)
  {
    digitalWrite( pwmPin , HIGH );
    delayMicroseconds( 100 );
    digitalWrite( pwmPin , LOW );
    delayMicroseconds( 900 );
  }
  else
  {
    TimerStart = 0;  // Interval is done
  }
}

Thanks again John, it working great now.

Now I'll just have to study up on what you have done because you use some things in that code i was never aware of. After reading the links others posted and such I could make then happen individually, but combining it all together is where i was getting lost. Also I read the using millis() sticky post(which i somehow overlooked before) and the timing part is making much more sense to me now.

Thanks for the help everyone

BTW
The code I posted in post #7 ‘avoids’ the blocking effect of delayMicroseconds().

Keeping your sketches nonblocking keeps them responsive.