Pushbutton to start/stop LED Sequence

Hi All,

I have been trying to adapt the Standard pushbutton sketch to start a pulsing LED and then to turn it off again at the next push.

At the Moment, it Kind of works. but pushing the button advances the pulse one brightness Level at a time up and down.

That being the case, it is clear to me that I have my Loop wrong, but I am not quite sure how to correct it to get the effect that I am looking for.

Below is the code that I have so far. Any suggestions would be well apreciated.

const int buttonPin = 2;     // the number of the pushbutton pin

const byte LED_Pulse =  6;
const unsigned long PULSE_Interval = 10000UL;  //  Requires PWM. Time from beginning to Pulse in until Pulse out completes 10000 for slow pulse
unsigned long TIMER_Pulse = 0;
int STATE_Pulse = LOW ;  

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(led_testPin, OUTPUT); 
  pinMode (LED_Pulse,OUTPUT) ;
    Serial.begin(9600);
  TIMER_Pulse = millis () ; 
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

 

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    
   // this is all that's new to the code 
   // toggles the ledState variable each time the button is pressed 
      if (buttonState == HIGH) {
        
        /*********************************************************
         *             Pulse LED                                                                        *
         ********************************************************/
          TIMER_Pulse = millis(); // For some reason this has to be in the loop
          STATE_Pulse = 128+127*cos(2*PI/PULSE_Interval*TIMER_Pulse);
          
          analogWrite(LED_Pulse, STATE_Pulse);           // sets the value (range from 0 to 255)  
    } 
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

@PixelWorks:

I guess I would like to help but I need more help from your part too. For instant could you define what want to happen? what are you seeing and if there any error state them..

right of the bat I could say, there must be an error in the code you just supplied. You didn't define your test_led. In your code also at no point what so ever did you used any Serial.print... it would be best not to add more then you need aka... you dont have to write Serial.begin ( );

Ouh man I cant understand what you are tying to do man... please enlighten me or any reader of this post?

Your pulsating (led intensity) is based on millis(), and millis() is advancing all the time, even when pulsating is stopped.
When you again start pulsating, led intensity doesn't continue from where you stopped, but from what millis() is at that moment. That makes the stepping up and down in intensit you see, not your button pushes.

Hi Ashraf,
thanks for your reply, sorry for the confusion, the test_led is just that for testing, I removed the declaration but forgot to remove it below, for my defense I can only say that it was something after midnight as I posted it. :slight_smile: Nevertheless, it is not needed. I have added the code again below with out that line so there is no confusion.

the Pulse_led is where the Music is playing, it should go dim to bright and from bright to dim again and again. Alone, this works just fine, I am trying to Combine this with a pushbutton so that the pulse LED starts off and then when I push the button, it starts pulsing (i.e. dim to bright, bright to dim, and so on) until I push the button again. The pushbutton is not an On/Off button, but rather the same as the reset button on the Arduino, it has an off state (not being pushed down) and an on state (only so Long as it is being pushed) which is why there is a debounce in the code.

So, the code below compiles fine, but pushing the pushbutton only advances the pulse by one brightness Level. when i push it again it advances to the next brightness Level... step by step all the way to the max brightness and then step by step back down to the min brightness at each push of the button. I hope that makes sense.

const int buttonPin = 2;     // the number of the pushbutton pin
const byte LED_Pulse =  6;
const unsigned long PULSE_Interval = 10000UL;  //  Requires PWM. Time from beginning to Pulse in until Pulse out completes 10000 for slow pulse
unsigned long TIMER_Pulse = 0;
int STATE_Pulse = LOW ;  

// Variables will change:
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode (LED_Pulse,OUTPUT) ;
    Serial.begin(9600);
  TIMER_Pulse = millis () ; 
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

 

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    
   // this is all that's new to the code 
   // toggles the ledState variable each time the button is pressed 
      if (buttonState == HIGH) {
        
        /*********************************************************
         *             Pulse LED      (works 2013-06-10)         *
         ********************************************************/
          TIMER_Pulse = millis(); // For some reason this has to be in the loop
          STATE_Pulse = 128+127*cos(2*PI/PULSE_Interval*TIMER_Pulse);
          
          analogWrite(LED_Pulse, STATE_Pulse);           // sets the value (range from 0 to 255)  
    } 
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

Here is an miserable attempt to Display the wiring, Fritzing would not install on my Computer so I hope this helps to understand the Setup.

Pushbutton


(-) ----- (Resistor 1)----- | 0 | ------- (to Arduino pin 2)
(+) --------------------- |___|

(Arduino pin 6) --------------___
___
(-) --------(Resistor 2) ------ _____D Pulsing LED

As the comment says

    // toggles the ledState variable each time the button is pressed

Led is only updating with every push, and as I said above, Led brightness is based on millis(). In my opinion not very elegant as dimming can go from full to no brightness if you make a short pause in the dimming.

I have added a variable, pulseTrue that tell if pulsating is active or not.

Your dimming formula has been replaced with a line that toggle pulseTrue.

Dimming formula now makes up a separate function, pulseLED(), that is called from first line in loop(). I don't know if it would make much difference to check pulseTrue before you call the function.

Finally, the modified code with some comments

const int buttonPin = 2;     // the number of the pushbutton pin
const int LED_TestPin =  13;      // the number of the LED pin

const byte LED_Pulse =  6;
const unsigned long PULSE_Interval = 10000UL;  //  Requires PWM. Time from beginning to Pulse in until Pulse out completes 10000 for slow pulse
unsigned long TIMER_Pulse = 0;
int STATE_Pulse = LOW ;

// Variables will change:
int pulseTrue;
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode (LED_Pulse, OUTPUT) ;
  Serial.begin(9600);
  TIMER_Pulse = millis () ;
}

void loop() {
  pulseLED(); //Here we call the new function to dim the LED.

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);



  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();

    // this is all that's new to the code
    // toggles the ledState variable each time the button is pressed
    if (buttonState == HIGH) {
      pulseTrue = !pulseTrue; //Toggle the dimming flag.
    }
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}
void pulseLED() { // Dimming in separate function.
  if (pulseTrue) {
    /*********************************************************
                   Pulse LED      (works 2013-06-10)
     ********************************************************/
    TIMER_Pulse = millis(); // For some reason this has to be in the loop
    STATE_Pulse = 128 + 127 * cos(2 * PI / PULSE_Interval * TIMER_Pulse);

    analogWrite(LED_Pulse, STATE_Pulse);           // sets the value (range from 0 to 255)
  }
}

As far as I can see, you only do something while the button is bouncing (due to if (reading != lastButtonState) and has become stable.

You should move the below out of the above if statement.

    // this is all that's new to the code
    // toggles the ledState variable each time the button is pressed
    if (buttonState == HIGH) {
      ...
      ...
    }

You also need to move test for the time out of the above if, else it will never evaluate to true. Reason is that once the above if statement no longer evaluates to true, there will not be a check anymore for the debounce delay.

The updated loop() code

void loop() {

/*** DEBOUNCE ***/  
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;

/*** ACTION ***/  

  if (buttonState == HIGH) {
    /*********************************************************
                   Pulse LED
     ********************************************************/
    TIMER_Pulse = millis(); // For some reason this has to be in the loop
    STATE_Pulse = 128 + 127 * cos(2 * PI / PULSE_Interval * TIMER_Pulse);

    analogWrite(LED_Pulse, STATE_Pulse);           // sets the value (range from 0 to 255)
  }
}

Gabriel_swe:
I have added a variable, pulseTrue that tell if pulsating is active or not.

Your dimming formula has been replaced with a line that toggle pulseTrue.

Dimming formula now makes up a separate function, pulseLED(), that is called from first line in loop(). I don't know if it would make much difference to check pulseTrue before you call the function.

sterretje:
You also need to move test for the time out of the above if, else it will never evaluate to true. Reason is that once the above if statement no longer evaluates to true, there will not be a check anymore for the debounce delay.

The updated loop() code

Thanks Gabriel
Thanks Sterretje,

I will give both your suggestions a try tomorrow and let you know how it went.

Gabriel_swe:
Finally, the modified code with some comments

Hi Gabriel,

your code started the pulse at the push of the button and the next push "only" pauses the pulsing wherever it happened to be (leaving it on), and then continues to pulse where it left off after the next push... at any rate, I just added an ELSE Statement (to turn it off) to your IF and now it is working like a charm. Thanks! :slight_smile:

 else
 STATE_Pulse = LOW;
  analogWrite(LED_Pulse, STATE_Pulse);