Button timer with PWM output

I don't know if it's possible to do pulses with PWM function. After I press the button, id like the led to stay on for 500 milliseconds while still being able to keep the PWM function with the potentiometer. This is my first project and Iv'e been reading the Arduino book all day with no luck haha.

How can two different functions be made available concurrently on a single output pin?

For example, the PWM output may remain off while the LED is held HIGH, and then the PWM signal resumes afterward.

So is the PWM always on? what if I put the switch in series with the potentiometer signal wire? I wouldn't be able to do any delay or timing function though. Im just wondering if its possible to interrupt the PWM output. If need be I can move the switch output. I've only been using arduino and first time coding since yesterday sorry.

Hi @sampchains ,

Welcome to the forum..

You mean something like this..

#define BTN_PIN 2
#define LED_PIN 11
#define POT_PIN A0


unsigned long lastBtn;
unsigned long btnDebounce = 50;
byte btnState = HIGH;

bool ledActive = false;
unsigned long ledStart;
unsigned long ledRunTime = 500;

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);

}

void loop() {

  unsigned long now = millis();

  if (now - lastBtn >= btnDebounce) {
    byte b = digitalRead(BTN_PIN);
    if (b != btnState) {
      lastBtn = now;
      btnState = b;
      if (b == HIGH) {
        //press and release
        if (!ledActive) {
          ledActive = true;
          ledStart = now;
        }
      }
    }
  }

  if (ledActive) {
    if (now - ledStart >= ledRunTime) {
      //stop
      ledActive = false;
      analogWrite(LED_PIN, 0);
    } else {
      //led is active..
      int v = analogRead(POT_PIN);
      v = map(v, 0, 1023, 0, 255);
      analogWrite(LED_PIN, v);
    }
  }
}

press button to apply pwm to the led for 500ms..

have fun.. ~q

Ive just learned about the button debounce code and obviously analogread and write pins.


I fixed it, I learned that the arduino needs to read high or low with a pulldown resistor. So i added that and your code worked flawlessly. you sir are a genius and you have no idea how happy i am that this is working. thank you!

1 Like

sorry, fell asleep..

you probably got your button turned around..

when using those buttons I always use opposite corners, then you have no worries..

i configured the pin to use the internal pull up resistors, so with out pressing the button it should read HIGH, LOW when pressed..

and yes, good lesson for debouncing buttons and using a millis timers to time things..

~q

1 Like

again, thank you for the code. im currently trying to add a delay so that when I press the button it doesn't start the pulse for one second. I learned that the delay function isn't recommended so im messing around with millis intervals, but i keep getting errors. is it best to add this function at the start or right before analog read? sorry to bother.

void loop() {
 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis >= interval) {
   previousMillis = currentMillis;

Please, use code tags: and use 3 spaces for indentation.

void loop() 
{
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis >= interval) 
   {
      previousMillis = currentMillis;

gotcha, thank you

ok so i was able to make a delay, but now I want to make an adjustable delay with a 2nd potentiometer (0-2 seconds). Im not getting any errors, but now my variable delay is after the pulse only letting me hit the button from the delay. I want the delay to be when I press the button, then the it sends the pulse. I realize this is probably the easiest fix, but im not very smart haha clearly. Here is what I have so far, I added the minimum time value delay in map assuming that I can get rid of btn debounce now?

#define BTN_PIN 2
#define LED_PIN 11
#define POT_PIN A0
#define POT_PIN1 A1

unsigned long lastBtn = 0;
int interval = 1000;
byte btnState = HIGH;

bool ledActive = false;
unsigned long ledStart;
unsigned long ledRunTime = 100;

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);

}

void loop() {
  
  unsigned long now = millis();
  
 int v1 = analogRead(POT_PIN1);
  interval = map(v1, 0, 1023, 10, 2000); 
  
  if (now - lastBtn >= interval) {
    byte b = digitalRead(BTN_PIN);
    if (b != btnState) {
      lastBtn = now;
      btnState = b;
      if (b == HIGH) {
        if (!ledActive) {
          ledActive = true;
          ledStart = now;
        }
      }
    }
  }

  if (ledActive) {
    if (now - ledStart >= ledRunTime) {
      ledActive = false;
      analogWrite(LED_PIN, 0);
    } else {
      int v = analogRead(POT_PIN);
      v = map(v, 0, 1023, 0, 255);
      analogWrite(LED_PIN, v);
    }
  }
}

No you can not remove the button debouncing code, buttons bounce, you need it..

Did you fix your button wiring, should only be 2 wires on it, one to ground one to pin2, use opposite corners, looking at you wiring i don’t think that button will register a press the way it is currently wired..

the interval was being used as the button debounce delay??

give this a try..

/*
  https://forum.arduino.cc/t/button-timer-with-pwm-output/1419547/
*/



#define BTN_PIN 2
#define LED_PIN 11
#define POT_PIN A0
#define POT2_PIN A1


unsigned long lastBtn;
unsigned long btnDebounce = 50;
byte btnState = HIGH;


unsigned long ledStart;
unsigned long ledRunTime = 500;

enum StatesSystem {
  state_Idle,
  state_Wait,
  state_Run
};

StatesSystem sysState = state_Idle;

unsigned long waitStart;
unsigned long waitTime = 1000;

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);

}

void loop() {

  unsigned long now = millis();

  int v;

  v = analogRead(POT2_PIN);
  waitTime = map(v, 0, 1023, 10, 2000);


  if (now - lastBtn >= btnDebounce) {
    byte b = digitalRead(BTN_PIN);
    if (b != btnState) {
      lastBtn = now;
      btnState = b;
      if (b == HIGH) {
        //press and release
        if (sysState == state_Idle) {
          sysState = state_Wait;
          waitStart = now;
        }
      }
    }
  }


  switch (sysState) {
    case state_Wait:
      if (now - waitStart >= waitTime) {
        sysState = state_Run;
        ledStart = now;
      }
      break;
    case state_Run:
      if (now - ledStart >= ledRunTime) {
        //stop
        state_Sys = state_Idle;
        analogWrite(LED_PIN, 0);
      } else {
        //led is active..
        v = analogRead(POT_PIN);
        v = map(v, 0, 1023, 0, 255);
        analogWrite(LED_PIN, v);
      }
      break;
  }
}

added a state machine into the mix..

in a simulator but have not compiled, their server is currently too busy..

have fun.. ~q

It woukd be clearer of kitty-corner pins were used:

Works but (or and) a pressed button reads HIGH.

I'd like to see a graph of the wokwi server wait time over the course of a week or so! I've only noticed it's really busier the more of a hurry I am in. :expressionless:

a7

i’ve never seen it that high before, didn’t even bother trying to wait..

~q

thank you, I've fixed the wiring. It amazes me how many ways you can wire components & code for the same function. Im very new to this


I just had to change the state_Sys to sysState. THank you!!!! it works just how I wanted it.

1 Like

going to try and add another Potentiometer to be able to change the pulse timing from 5ms to 100ms.

should be easy..

read it into v and map it directly to led run time..

~q

Couldn't wait to try it after work, this is what I did. I cant believe I made it work haha. I also made the switching frequency 8Khz and it got rid of my IGBT noise (just had to upscale my millis now to match previous durations). Thank you for helping me. this is a great community and I definitely will have some more upcoming projects.

/*
  https://forum.arduino.cc/t/button-timer-with-pwm-output/1419547/
*/



#define BTN_PIN 2
#define LED_PIN 5
#define POT_PIN A0
#define POT2_PIN A1
#define POT3_PIN A2


unsigned long lastBtn;
unsigned long btnDebounce = 50;
byte btnState = HIGH;


unsigned long ledStart;
unsigned long ledRunTime = 1000;

enum StatesSystem {
  state_Idle,
  state_Wait,
  state_Run
};

StatesSystem sysState = state_Idle;

unsigned long waitStart;
unsigned long waitTime = 1000;

void setup() {
  Serial.begin(115200);
  TCCR0B = TCCR0B & 0b11111000 | 0x02;
  pinMode(BTN_PIN, INPUT_PULLUP);

}

void loop() {

  unsigned long now = millis();

  int v;

  v = analogRead(POT2_PIN);
  waitTime = map(v, 0, 1023, 10, 5000);


  if (now - lastBtn >= btnDebounce) {
    byte b = digitalRead(BTN_PIN);
    if (b != btnState) {
      lastBtn = now;
      btnState = b;
      if (b == HIGH) {
        //press and release
        if (sysState == state_Idle) {
          sysState = state_Wait;
          waitStart = now;
        }
      }
    }
  }
  
  v = analogRead(POT3_PIN);
  ledRunTime = map(v, 0, 1023, 5, 2000);
     

  switch (sysState) {
    case state_Wait:
      if (now - waitStart >= waitTime) {
        sysState = state_Run;
        ledStart = now;
      }
      break;
    case state_Run:
      if (now - ledStart >= ledRunTime) {
        //stop
        sysState = state_Idle;
        analogWrite(LED_PIN, 0);
      } else {
        //led is active..
        v = analogRead(POT_PIN);
        v = map(v, 0, 1023, 0, 255);
        analogWrite(LED_PIN, v);
      }
      break;
  }
}
1 Like