Help With push buttons toggling LEDs

Hello, I am building a MIDI controller and I am having some issues. I want an LED to turn on when a button is pushed, and then turn off when the button is pushed for a second time. My current code only lights the LED when the button is held down. my prototype currently only has one button and one LED installed, but I am planning on using 4 or more of each. I know I could declare each button and LED individually, instead of using an array, but I was wondering if there is any way to get the LEDs to toggle without bloating the code. Any help would be much appreciated.

/*
  Based on Sketch built by Gustavo Silveira (aka Music Nerd)
  Modified by Dolce Wang
  LED Button code added by Samuel Vigil

  This code is only for Arduinos that use ATmega328 (like Uno, Mega, Nano, Beetle...)

*/


// Change values with //*** 


// LIBRARIES

                
#include <MIDI.h> // by Francois Best
MIDI_CREATE_DEFAULT_INSTANCE(); 


// BUTTONS
const int NButtons = 1; //***  total number of push buttons
const int buttonPin[NButtons] = {8}; //*** define digital pins connected from button to Arduino; (ie {10, 16, 14, 15, 6, 7, 8, 9, 2, 3, 4, 5}; 12 buttons)
                                        //** Button NOTE will go up chromatically.  ie. if button is digi pin 2, C; Pin 3, C#; Pin 3, D; etc
                                   
int buttonCState[NButtons] = {};        // stores the button current value
int buttonPState[NButtons] = {};        // stores the button previous value
int toggle;

// debounce
unsigned long lastDebounceTime[NButtons] = {0};  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    //* the debounce time; increase if the output flickers

//LEDs
const int NLEDs = 1; //***  total number of LEDs
const int LEDPin[NLEDs] = {4}; //*** define digital pins connected from Arduino to LEDs; (ie {10, 16, 14, 15, 6, 7, 8, 9, 2, 3, 4, 5}; 12 LEDs)

int LEDCState[NLEDs] = {};        // stores the current LED value
int LEDPState[NLEDs] = {};        // stores the previous LED state

//int mInputChannel;                // MIDI input channel

// POTENTIOMETERS
const int NPots = 1; //*** total numbers of pots (slide & rotary)
const int potPin[NPots] = {A0}; //*** Analog pins of each pot connected straight to the Arduino i.e 4 pots, {A3, A2, A1, A0};
                                          // have nothing in the array if 0 pots {}

int potCState[NPots] = {0}; // Current state of the pot; delete 0 if 0 pots
int potPState[NPots] = {0}; // Previous state of the pot; delete 0 if 0 pots
int potVar = 0; // Difference between the current and previous state of the pot

int midiCState[NPots] = {0}; // Current state of the midi value; delete 0 if 0 pots
int midiPState[NPots] = {0}; // Previous state of the midi value; delete 0 if 0 pots

const int TIMEOUT = 300; //** Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 10; //** Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[NPots] = {0}; // Previously stored time; delete 0 if 0 pots
unsigned long timer[NPots] = {0}; // Stores the time that has elapsed since the timer was reset; delete 0 if 0 pots


// MIDI
byte midiCh = 1; //** MIDI channel to be used; You can add more if you need to reorganize or have a billion buttons/pots
byte note = 36; //** First note to be used for digital buttons, then go up chromatically in scale according to the sequence in your "buttonPin" array
                // you can look up on a Midi Note chart; 36=C2; 60=Middle C
byte cc = 1; //** First MIDI CC to be used for pots on Analog Pins in order of the "potPin" array; then goes up by 1

// SETUP
void setup() { 

  Serial.begin(115200); //**  Baud Rate 31250 for MIDI class compliant jack | 115200 for Hairless MIDI
  toggle = 0;
  
  // Buttons
  // Initialize buttons with pull up resistors
  for (int i = 0; i < NButtons; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);
  }
  // LEDs
  for(int i = 0; i < NLEDs; i++) {
    pinMode(LEDPin[i], OUTPUT); // define LED pins as outputs
  }
//  MIDI.begin(MIDI_CHANNEL_OMNI);
  //mInputChannel = MIDI_CHANNEL_OMNI;
}


// LOOP
void loop() {
    buttons();
    //LEDs();
    potentiometers();
}


// BUTTONS
int buttons() {

  for (int i = 0; i < NButtons; i++) {
     
    
    buttonCState[i] = digitalRead(buttonPin[i]);  // read pins from arduino


    if ((millis() - lastDebounceTime[i]) > debounceDelay) {

      if (buttonPState[i] != buttonCState[i]) {
        lastDebounceTime[i] = millis();

        if (buttonCState[i] == LOW) {

          // Sends the MIDI note ON accordingly to the chosen board

MIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel
LEDCState[i] = HIGH;
//digitalWrite(LEDPin[i], HIGH);

        }
        else {

          // Sends the MIDI note OFF accordingly to the chosen board

MIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel
LEDCState[i] = LOW;
//digitalWrite(LEDPin[i], LOW);

        }
        
        if (buttonCState[i] != buttonPState[i]) {
          buttonPState[i] = buttonCState[i];
              if (buttonCState[i] == LOW) {   
              digitalWrite(LEDPin[i], HIGH);
            } 
            else {
              digitalWrite(LEDPin[i], LOW);
            }
            
        }
              
        buttonPState[i] = buttonCState[i];
        LEDPState[i] = LEDCState[i];
      }
    }
  }
}




// POTENTIOMETERS
void potentiometers() {


  for (int i = 0; i < NPots; i++) { // Loops through all the potentiometers

    potCState[i] = analogRead(potPin[i]); // reads the pins from arduino

    midiCState[i] = map(potCState[i], 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi

    potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot

    if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
      PTime[i] = millis(); // Stores the previous time
    }

    timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms

    if (timer[i] < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
      potMoving = true;
    }
    else {
      potMoving = false;
    }

    if (potMoving == true) { // If the potentiometer is still moving, send the change control
      if (midiPState[i] != midiCState[i]) {

        // Sends the MIDI CC 
        MIDI.sendControlChange(cc + i, midiCState[i], midiCh); // cc number, cc value, midi channel
            

        potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
        midiPState[i] = midiCState[i];
      }
    }
  }
}


















/*
void LEDButton(){
  for (int i = 0; i < NButtons; i++) {
    buttonCState[i] = digitalRead(buttonPin[i]);
    LEDCState[i] = digitalRead(LEDPin[i]);
      if (toggle == 1) {
        if (buttonCState == HIGH){
            digitalWrite(LEDPin[i], HIGH);
        } else {
            digitalWrite(LEDPin[i], LOW);
            toggle = 0;
            //chec = 1;
            while (buttonCState != HIGH) {
                buttonCState[i] = digitalRead(buttonPin[i]);       
        }   
        }
    }
    if (toggle == 0 /*&& chec == 0){
        if (buttonCState == HIGH) {
            digitalWrite(LEDPin[i], LOW);
        } else {
            digitalWrite(LEDPin[i], HIGH);
            toggle = 1;
            while (buttonCState != HIGH) {
                buttonCState[i] = digitalRead(buttonPin[i]);  
        }
       }
    }  
    //delay(100);
    buttonPState[i] = buttonCState[i];
    LEDPState[i] = LEDCState[i];    
  }
}*/








/*//LEDs
int LEDs(int i, int LEDPState) {
  //for (int i = 0; i < NLEDs; i++) {

      if (LEDPState == HIGH) {

        digitalWrite(LEDPin[i], HIGH);

        }
      else {
          
        digitalWrite(LEDPin[i], LOW);

        }
  return(LEDPState);
  }
//} */

Welcome to the forum

You need to detect when the button becomes pressed rather than when it is pressed
See the StateChangeDetection example in the IDE

So you want to TOGGLE the LED state each time the button is pressed. That would be something like:

// BUTTONS
int buttons()
{
  for (int i = 0; i < NButtons; i++)
  {
    buttonCState[i] = digitalRead(buttonPin[i]);  // read pins from arduino

    if ((buttonPState[i] != buttonCState[i]) &&
        (millis() - lastDebounceTime[i]) > debounceDelay)
    {
      // Button just changed and it's too late to be a bounce
      lastDebounceTime[i] = millis();
      buttonPState[i] = buttonCState[i];

      if (buttonCState[i] == LOW)  // Pressed
      {
        // The button was just pressed
        // Sends the MIDI note ON accordingly to the chosen board
        MIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel

        LEDCState[i] = !LEDCState[i]; // Toggle LED
        digitalWrite(LEDPin[i], LEDCState[i]);
      }
      else
      {
        // Button was just released

        // Sends the MIDI note OFF (ON with velocity 0)
        // accordingly to the chosen board
        MIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel

        // Note: LED state doesn't change when button is released
      }
    }
  }
}
#include <Control_Surface.h>  // https://github.com/tttapa/Control-Surface

// Create an array of push buttons that send out MIDI Note messages 
NoteButtonLatched buttons[] {
  {8, {36, CHANNEL_1}},
  {9, {37, CHANNEL_1}},
  {10, {38, CHANNEL_1}},
  {11, {39, CHANNEL_1}},
};
// Create an array of pins for the LEDs
const pin_t ledPins[] {4, 5, 6, 7};

// Get the length of an array
template <class T, size_t N> constexpr size_t len(T (&)[N]) { return N; }
static_assert(len(buttons) == len(ledPins), 
              "Error: requires same number of switches as LEDs");

// Create a potentiometer that sends MIDI Control Change messages
CCPotentiometer potentiometer {A0, {1, CHANNEL_1}};

// Instantiate a MIDI Interface to use
HardwareSerialMIDI_Interface midi {Serial, 115200};

void setup() {
  Control_Surface.begin();
  for (auto pin : ledPins)
    pinMode(pin, OUTPUT);
}

void loop() {
  Control_Surface.loop();

  // Loop over all switches and LEDs
  for (size_t i = 0; i < len(ledPins); ++i)
    // If the button was pressed, this means the toggled state changed
    if (buttons[i].getButtonState() == Button::Falling)
      // Update the LED state to reflect the toggled switch state
      digitalWrite(ledPins[i], buttons[i].getState() ? HIGH : LOW);
}

I see, I was trying to change the LED state in tandem with the button state, where your solution is more elegant, because the LED doesn't need to be updated.
This code works with my prototype. Thank you for your help.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.