Help with Coding to get LED's Working as I would Like

Status
Not open for further replies.

Sound Man

New member
Hi everyone.

I am putting together a Midi Keypad which has 3 push switches to send midi notes to a computer to operate software. The midi side of things is working ok but what I am having trouble with is getting the LED's which are built into the push switches to work as I would like them to. The push switches have built in RGB indicator LED's and my plan is to arrange the coding so that for example the first switch lights up Green normally. When the switch is pressed the Green LED will go off briefly and the Blue LED will flash about 3 times indicating that the midi note has been sent to the computer.

I have managed to get the Blue LED's to flash ok when the switch is pressed but what I am having trouble with is getting the Green LED to go Off while the Blue LED is flashing. I first tried doing it with the Delay () coding and found out that that causes the program to also delay. After searching the net I came across the following Timer Library here and swapped Delay () for t.pulse () to add the delay to the Green LED. The result is that the LED goes Off ok when the switch is pressed but sometimes it doesn't come back on and when it does it's not always when the Blue LED has stopped flashing.

I've come to the thinking that the best way to do this would be to put the coding together so that the Green LED goes off for the duration that the Blue LED is pulsing but I don't know how to do this. Any help with this would be very much appreciated. Sorry for the long winded description.

Below is the coding that I have put together so far:-

Code:
/*
  Palladium Remote Keypad with twin LED's

  Created: 3 Dec 2016 by Sims Sound Systems

  You must select MIDI from the "Tools > USB Type" menu
*/

#include <Timer.h>
#include <Bounce.h>


// the MIDI channel number to send messages
const int channel = 1;

Timer t;

int blinkNextCue = 0;           // Button pressed
int blinkPreviousCue = 0;
int blinkFXaux = 0;

int NextCueLEDstate = LOW;
int PreviousCueLEDstate = LOW;
int FXauxLEDstate = LOW;

long previousNextCueMillis = 0;
long previousPreviousCueMillis = 0;
long previousFXauxMillis = 0;

long NextCueBlinkInt = 200;
long PreviousCueBlinkInt = 200;
long FXauxBlinkInt = 200;

int NextCueButtonLED = 8;  // Green LED
int NextCueLED = 9;  // Blue LED
int PreviousCueButtonLED = 6;  // Red LED
int PreviousCueLED = 7;  // Blue LED
int FXauxButtonLED = 5;    // Amber LED (Red & Green LED's connected together)
int FXauxLED = 4;  // Blue LED


// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce NextCueButton = Bounce(10, 5);
Bounce PreviousCueButton = Bounce(11, 5);
Bounce FXauxButton = Bounce(12, 5);


void setup() {
  // Setup input pins for "active low"
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);

  // Setup output pins
  pinMode(NextCueButtonLED, OUTPUT);     // Button not pressed
  pinMode(NextCueLED, OUTPUT);                 // Button pressed
  pinMode(PreviousCueButtonLED, OUTPUT);
  pinMode(PreviousCueLED, OUTPUT);
  pinMode(FXauxButtonLED, OUTPUT);
  pinMode(FXauxLED, OUTPUT);
  
  // Set initial LED values.
       // HIGH = LED OFF,   LOW = LED ON  (Common Anode LEDs)

  digitalWrite(NextCueButtonLED, LOW);
  digitalWrite(NextCueLED, HIGH);
  digitalWrite(PreviousCueButtonLED, LOW);
  digitalWrite(PreviousCueLED, HIGH);
  digitalWrite(FXauxButtonLED, LOW);
  digitalWrite(FXauxLED, HIGH);
}


void loop() {
  // Update all the buttons.
  NextCueButton.update();
  PreviousCueButton.update();
  FXauxButton.update();


  // Check each button for "falling" edge.
  // Send a 'MIDI Note On' message when each button is pressed
  if (NextCueButton.fallingEdge()) {
    usbMIDI.sendNoteOn(126, 99, channel);  // Midi Channel 126 = F#10
    t.pulse(NextCueButtonLED, 10 * 400, HIGH); // Green LED off delay
    blinkNextCue = 6;   // Blue LED flash rate
  }
  
  if (PreviousCueButton.fallingEdge()) {
    usbMIDI.sendNoteOn(127, 99, channel);  // Midi Channel 127 = G10
    t.pulse(PreviousCueButtonLED, 10 * 400, HIGH); // Red LED off delay
    blinkPreviousCue = 6;   // Blue LED flash rate
  }

  if (FXauxButton.fallingEdge()) {
    usbMIDI.sendNoteOn(0, 99, channel);  // Midi Channel 0 = C0
    t.pulse(FXauxButtonLED, 10 * 400, HIGH); // Amber LED off delay
    blinkFXaux = 6;   // Blue LED flash rate
  }

  t.update();
  
  // Check each button for "rising" edge
  // Send a 'MIDI Note Off' message when each button is released
  if (NextCueButton.risingEdge()) {
    usbMIDI.sendNoteOff(126, 0, channel);  // Midi Channel 126 = F#10
  }
  if (PreviousCueButton.risingEdge()) {
    usbMIDI.sendNoteOff(127, 0, channel);  // Midi Channel 127 = G10
  }
  if (FXauxButton.risingEdge()) {
    usbMIDI.sendNoteOff(0, 0, channel);  // Midi Channel 0 = C0
  }


  // MIDI Controllers should discard incoming MIDI messages.
  while (usbMIDI.read()) {
    // Ignore incoming messages
  }
  unsigned long currentNextCueMillis = millis();
  unsigned long currentPreviousCueMillis = millis();
  unsigned long currentFXauxMillis = millis();
  
  if ((blinkNextCue > 0) || (NextCueLEDstate == LOW)) {  
    if(currentNextCueMillis - previousNextCueMillis > NextCueBlinkInt) {  
      // save the last time you blinked the LED  
      previousNextCueMillis = currentNextCueMillis;    
  
  
      // if the LED is off turn it on and vice-versa:  
      if (NextCueLEDstate == LOW) {  
        NextCueLEDstate = HIGH;  
      } else {  
        NextCueLEDstate = LOW;  
      }  
      // set the LED with the ledState of the variable:  
      digitalWrite(NextCueLED, NextCueLEDstate);  
      blinkNextCue--;  
    }  
  }  

  if ((blinkPreviousCue > 0) || (PreviousCueLEDstate == LOW)) {  
    if(currentPreviousCueMillis - previousPreviousCueMillis > PreviousCueBlinkInt) {  
      // save the last time you blinked the LED  
      previousPreviousCueMillis = currentPreviousCueMillis;    
  
  
      // if the LED is off turn it on and vice-versa:  
      if (PreviousCueLEDstate == LOW) {  
        PreviousCueLEDstate = HIGH;  
      } else {  
        PreviousCueLEDstate = LOW;  
      }  
      // set the LED with the ledState of the variable:  
      digitalWrite(PreviousCueLED, PreviousCueLEDstate);  
      blinkPreviousCue--;  
    }  
  }  

  if ((blinkFXaux > 0) || (FXauxLEDstate == LOW)) {  
    if(currentFXauxMillis - previousFXauxMillis > FXauxBlinkInt) {  
      // save the last time you blinked the LED  
      previousFXauxMillis = currentFXauxMillis;    
  
  
      // if the LED is off turn it on and vice-versa:  
      if (FXauxLEDstate == LOW) {  
        FXauxLEDstate = HIGH;  
      } else {  
        FXauxLEDstate = LOW;  
      }  
      // set the LED with the ledState of the variable:  
      digitalWrite(FXauxLED, FXauxLEDstate);  
      blinkFXaux--;  
    }  
  }  

}
 
This is one of the fundamental things you need to learn to go from simple linear sketches (where you do one thing, wait for a response, and do the next) and go on to a more complicated system where you are controlling multiple things, and you have to juggle doing all of the things on a single processor.

This Adafruit tutorial is one of many to discuss how to control things independently without going to a fully threaded system: https://learn.adafruit.com/multi-tasking-the-arduino-part-1/all-together-now?view=all
 
LED FLASHER class using elapsedMillis

@MichaelMeissner pointed to where I was going to point - but I paused to make a Teensy Specific elapsedMillis example version of that LED FLASHER class code that follows as changed from this :: multi-tasking-the-Arduino >> a-classy-solution.

Changes:
> Took out the manual math to watch time and added PJRC Teensy elapsedMillis to the class
> elapsedMillis is also usefully shown in the loop code to change the test state output changes
> The FLASHER class code seemed limiting - no way to start/stop/change the cycle rate after compile time - except to not call .Update and manually read/set pin.
- Added :: void UpdateTimes( uint32_t on, uint32_t off )
- Added :: void UpdateState( FlashState setState ) // enum FlashState { fOFF = 0, fON, fStayOFF, fStayON };
> Changed to unsigned 32 bit times values, and used enum for State

The class is below and sample usage of the two new interfaces to update the FLASHER object at runtime. I only have the LED on pin13, and a spare Teensy on pin 12 that is reporting Frequency with FreqMeasure.countToFrequency() :: numbers on led12 [50 to 500 Hz] a bit fast for watching an LED.

Code:
// https://learn.adafruit.com/multi-tasking-the-arduino-part-1/all-together-now?view=all#a-classy-solution

// fOFF / fON :: Turn [Off /On] but continue cycle on next update
// fStayOFF / fStayON :: Turn [Off / On] and ignore calls to .Update
enum FlashState { fOFF = 0, fON, fStayOFF, fStayON };

class Flasher
{
    // Class Member Variables
    // These are initialized at startup
    int ledPin;      // the number of the LED pin
    uint32_t OnTime;     // milliseconds of on-time
    uint32_t OffTime;    // milliseconds of off-time

    // These maintain the current state
    FlashState ledState;                 // ledState used to set the LED
    elapsedMillis LEDem;   // will store last time LED was updated

    // Constructor - creates a Flasher
    // and initializes the member variables and state
  public:
    Flasher(int pin, uint32_t on, uint32_t off)
    {
      ledPin = pin;
      pinMode(ledPin, OUTPUT);

      OnTime = on;
      OffTime = off;

      ledState = fOFF;
      LEDem = 0;  // Reset the time
    }
    void UpdateTimes( uint32_t on, uint32_t off )
    {
      OnTime = on;
      OffTime = off;
    }
    void UpdateState( FlashState setState )
    {
      ledState = setState;
      LEDem = 0;  // Reset the time
      if ( ledState == fON || ledState == fStayON )
        digitalWrite(ledPin, HIGH);
      else
        digitalWrite(ledPin, LOW);
    }
    void Update()
    {
      // check to see if it's time to change the state of the LED
      if ((ledState == fON) && (LEDem >= OnTime))
      {
        ledState = fOFF;  // Turn it off
        LEDem = 0;  // Reset the time
        digitalWrite(ledPin, LOW);  // Update the actual LED
      }
      else if ((ledState == fOFF) && (LEDem >= OffTime))
      {
        ledState = fON;  // turn it on
        LEDem = 0;  // Reset the time
        digitalWrite(ledPin, HIGH);   // Update the actual LED
      }
    }
};

Flasher led12(12, 100, 200);
Flasher led13(13, 350, 350);

void setup()
{
  Serial.begin(57600);
  while ( !Serial && millis() < 4000);
  Serial.println( "::+-" );
  Serial.println( millis() );
  Serial.println( "::+- v0.8" );
}

elapsedMillis Testing;
uint32_t TestNext = 0;
uint32_t TestCount = 0;
void loop()
{
  led13.Update();
  led12.Update();
  if ( Testing > TestNext ) {
    TestNext += 4000; // next test in 4 seconds
    TestCount++;
    switch ( TestCount )  {
      case 1:
        led12.UpdateTimes( 1 , 1 );
        led13.UpdateTimes( 60 , 240 );
        Serial.println( "500Hz 12 and short on 13" );
        break;
      case 2:
        led12.UpdateTimes( 2 , 2 );
        led13.UpdateTimes( 240 , 60 );
        Serial.println( "250Hz 12 and long on 13" );
        break;
      case 3:
        led12.UpdateState( fStayON );
        led13.UpdateTimes( 500 , 500 );
        Serial.println( "0Hz 12 and .5s on/off 13" );
        break;
      case 4:
        led12.UpdateState( fON );
        led13.UpdateState( fStayON );
        Serial.println( "return to 250Hz 12 and on 13" );
        break;
      case 5:
        led12.UpdateTimes( 1 , 1 );
        led13.UpdateState( fStayOFF );
        Serial.println( "500Hz 12 and off 13" );
        break;
      case 6:
        led12.UpdateTimes( 10 , 10 );
        led13.UpdateState( fON );
        Serial.println( "50Hz 12 and return to .5s on/off 13" );
        break;
    default:
        TestCount = 0;
        TestNext = 0;
        Testing = 0;
        Serial.println( "\nrestarting test series" );
        break;
    }
  }
}

Updated Adafruit link to no delay() coding in Wiki_coming to show this.
 
Last edited:
Good luck. The code above doesn't do a blink - I added "UpdateCycle( uint32_t cnt )" to the class and it seems to test out okay. Does the specified # of cycles with time watched for transition - counts them through and stops. Only other thing I can think of would be having .Update() return the state : On, Off, JustWentOn, JustWentOff, SetOn, SetOff, CountN done. Re-Reading OP I think that would get you working.
 
Status
Not open for further replies.
Back
Top