PWMing an LED using momentary switches

Hi,

I am trying to make a small controller box using some momentary push buttons and leds. Each led is connected to a PWM pin and the buttons are wired in a resistor ladder of sorts to an analog pin (But that is beside the point).

The issue I am having is that I would like to be able to just tap one of the momentary buttons (tap, not hold) and have one of my leds fade on and off, sort of like that “breathing” led on macbooks. I have seen how to make this fading effect before, but they all require putting the code into void loop which doesn’t really work in my case. I am sorry for being so naive about programming, but I cannot figure out how to fade these leds without constantly holding the momentary switch down.

There must be some sort of way to “call” a fade function in void loop only to have it activated by the pushbuttons right? :blush:

Here is my super simple code, notice that right now I am only turning the leds on and off instead of pwm fading them:

int j = 1; // integer used in scanning the array designating column number
//2-dimensional array for assigning the buttons and there high and low values
int Button[21][3] = {{1, 837, 845}, // button 1
                     {2, 730, 738}, // button 2
                     {3, 605, 611}, // button 3
                     {4, 318, 323}, // button 4
                     {5, 178, 179}, // button 5
                     {6, 91, 92}, // button 6
                     {7, 896, 900}, // button 1 + button 2
                     {8, 877, 882}, // button 1 + button 3
                     {9, 851, 857}, // button 1 + button 4
                     {12, 816, 822}, // button 2 + button 3
                     {13, 760, 770}, // button 2 + button 4
                     {16, 670, 678}; // button 3 + button 4

int analogpin = 5; // analog pin to read the buttons
int label = 0;  // for reporting the button label
int counter = 0; // how many times we have seen new value
long time = 0;  // the last time the output pin was sampled
int debounce_count = 50; // number of millis/samples to consider before declaring a debounced input
int current_state = 0;  // the debounced input value
int ButtonVal;

int bled = 3;
int yled = 5;
int gled = 6;
int rled = 9;

void setup()
{
  pinMode(bled, OUTPUT);
  pinMode(yled, OUTPUT);
  pinMode(gled, OUTPUT);
  pinMode(rled, OUTPUT);

}

void loop()
{
   // If we have gone on to the next millisecond
  if (millis() != time)
  {
    // check analog pin for the button value and save it to ButtonVal
    ButtonVal = analogRead(analogpin);
    if(ButtonVal == current_state && counter >0)
    { 
      counter--;
    }
    if(ButtonVal != current_state)
    {
      counter++;
    }
    // If ButtonVal has shown the same value for long enough let's switch it
    if (counter >= debounce_count)
    {
      counter = 0;
      current_state = ButtonVal;
      //Checks which button or button combo has been pressed
      if (ButtonVal > 0)
      {
        ButtonCheck();
      }
    }
    time = millis();
  }
  
}

void ButtonCheck()
{
  // loop for scanning the button array.
  for(int i = 0; i <= 21; i++)
  {
    // checks the ButtonVal against the high and low vales in the array
    if(ButtonVal >= Button[i][j] && ButtonVal <= Button[i][j+1])
    {
      // stores the button number to a variable
      label = Button[i][0];
      Action();      
    }
  }
}

void Action()
{
  if(label == 1)
  {
    digitalWrite(bled, LOW);
    digitalWrite(yled, LOW); 
    digitalWrite(gled, LOW);
    digitalWrite(rled, HIGH); 
  }
  if(label == 2)
  {
    digitalWrite(bled, LOW);
    digitalWrite(yled, LOW); 
    digitalWrite(gled, HIGH);
    digitalWrite(rled, LOW);
  }
  if(label == 3)
  {
    digitalWrite(bled, LOW);
    digitalWrite(yled, HIGH); 
    digitalWrite(gled, LOW);
    digitalWrite(rled, LOW); 
  }
  if(label == 4)
  {
    digitalWrite(bled, HIGH);
    digitalWrite(yled, LOW); 
    digitalWrite(gled, LOW);
    digitalWrite(rled, LOW);
  }
 }

Thank you so much for any help.

        ButtonCheck();

Dumb name. First, you don't really have any buttons connected to the Arduino do you? If so, put them back on your shirt, and get some switches. They will be far more reliable.

Second, the name implies that you are going to check the switches. It doesn't imply that you are going to DO anything about what you find.

Third, the function should return a value. Setting a global variable is not a good programming practice.

  if (millis() != time)
  {
// Snipped some stuff
    time = millis();
  }

The value returned by millis() will not equal the value returned last time one (or two) milliseconds later. What ARE you trying to do here?

In Action(), another dumb name - there would be no sense in calling the function unless some sort of action was expected; use name that describes WHAT the action is, you light up a single LED based on which switch was pressed. I see no attempt to change the brightness of an LED. Where is there any attempt to fade an LED?

There is no attempt to fade an led in my code, because I did not know how to call the function using a momentary switch.

I am not using push buttons like the ones you solder directly to circuit boards, I am using momentary switches that are made to be integrated into a case.

Like I said before, all of these buttons are wired up to one pin in a resistor ladder array, which is why I have to read the value every couple of milliseconds. It is wired like this:

Analog pin 5 | Ground--1K-- -- |-------- ---|--------|-------| | | | | btn1 btn2 btn3 btn4 | | | | 220 Ohm 390 Ohm 680 Ohm 2.2k |--------|--------|-------|-------|-- +5V

I am very rusty with C, which is why I am not sure how to fade the leds and read the button values at the same time.

because I did not know how to call the function using a momentary switch.

I'm sure it's probably just a semantics issue, but you can't call a function using a switch. You have to read the state of a pin that the switch is attached to, and use the state to determine whether, or not, to call the function.

I am not using push buttons like the ones you solder directly to circuit boards, I am using momentary switches that are made to be integrated into a case.

Doesn't matter. A momentary contact switch, a push-button switch, a toggle switch, or a piece of wire are either connected or not. The process of reading a pin that any one of these is connected to is exactly the same.

Like I said before, all of these buttons are wired up to one pin in a resistor ladder array, which is why I have to read the value every couple of milliseconds.

Or once a minute. Or once a week. Or once a year. The frequency doesn't matter. You read the switches as frequently, or infrequently, as is relevant. The weird stuff you are doing with millis() is just that.

So are you saying that I am reading the switch TOO fast? I didn't think it would matter that much.

So are you saying that I am reading the switch TOO fast? I didn't think it would matter that much.

No. I didn't say that. You can read the switches on every pass through loop(), if you want to. The Arduino doesn't care whether anything happens on an iteration of loop() or not.