IR Remote LED Inputs

I need some advice on how to go about this.

So I setup the IR remote and coded buttons 1, 2 and 3.

Pressing Button 1= LED 1 turns on, pressing Button 1 again, LED turns off.

Pressing Button 2= LED 2 turns on, blinks on a pattern of "On for 50millisecond, Off for 50millisecond, On 50millisecond , then turns Off the LED for 850millisecond" loop, pressing Button 2 again turns the LED 2 off. (Code for Button 2 works perfectly as what Button 2 is programmed.)

Pressing Button 3= LED 3 turns on, blinks on a pattern of "On for 100millisecond, Off for 900millisecond" loop. (Code for Button 3 also works perfectly as what Button 3 is programmed.)

They all work perfectly fine if I turn them on INDIVIDUALLY.

The problem starts if I turn on buttons 2 and 3 at the same time.(Button 1 has no problem at all.)

I was expecting Button 2 would let its LED blink independently, the same goes for Button 3.
But what actually happens is:

Button2 Strobe Pattern runs, and Button3 LED waits for Button2's LED sequence, then Button 3 Strobe Pattern runs, Button 2 LED waits for Button 3's Strobe Pattern.

I know, it is the delay code that's the culprit.
I've spent the past 2 days reading about millis and FSM and related stuff, and I was never so lost in my whole life.

So what is the most efficient way to code it that it if I turn on Button 2 and Button 3 at the same time, their respective pattern runs independently and simultaneously.
(To be more specific, even if I turn off Button 2, and leave Button 3 on, Button 3 still continues to do it's thing and vice versa. Think of it as a switch in the aircraft where you can toggle button 2 on/off, the same goes for button 3. Oh and it actually is a lighting system, for anAircraft RC project.)

Code for reference(I know it is still coded in delay function, because I cant wrap my head around the millis function yet):

/*
  source: www.electroschematics.com
  You'll need to change the led pins and the codes
  accordingly to your configuration and IR remote
*/

#include <IRremote.h>

const int RECV_PIN = 12; // the pin where you connect the output pin of TSOP4838
const int led1 = 3; //NAV
const int led2 = 2; //STROBE WING
const int led3 = 4; //STROBE TAIL
const int led4 = 5; //BEACON
boolean itsONled[13];  // Defaults to 'false'
/*old code int itsONled[] = {0,0,0,0};
/* the initial state of LEDs is OFF (zero)
  the first zero must remain zero but you can
  change the others to 1's if you want a certain
  led to light when the board is powered */
#define code1  12495 // code received from button 1
#define code2  6375 // code received from button 2
#define code3  31365 // code received from button 3

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);   // you can comment this line
  irrecv.enableIRIn();  // Start the receiver
  pinMode(led1, OUTPUT);   //NAV
  pinMode(led2, OUTPUT);   //STROBE WING
  pinMode(led3, OUTPUT);   //STROBE TAIL
  pinMode(led4, OUTPUT);   //BEACON
}

void loop()
{
  static unsigned long previousMillis = 0;
  // if led2 is 'on', show the blink pattern once per second.
  if (itsONled[2] && millis() - previousMillis >= 1000)
  {
    previousMillis = millis();

    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
    delay(50);
    digitalWrite(led2, LOW);
    delay(50);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW);
    delay(50);
    digitalWrite(led2, LOW);
  }
  if (itsONled[4] && millis() - previousMillis >= 1000)
  {
    previousMillis = millis();

    digitalWrite(led4, HIGH);
    delay(50);
    digitalWrite(led4, LOW);
    delay(50);
     }


  if (irrecv.decode(&results))
  {
    unsigned int value = results.value;
    switch (value)
    {
      case code1:
        if (itsONled[1])         // if first led is on then
        {
          digitalWrite(led1, LOW);   // turn it off when button is pressed
          itsONled[1] = false;           // and set its state as off
        }
        else                          // else if first led is off
        {
          digitalWrite(led1, HIGH); // turn it on when the button is pressed
          itsONled[1] = true;          // and set its state as on
        }
        break;
      case code2:
        if (itsONled[2])
        {
          digitalWrite(led2, LOW);
          itsONled[2] = false;
        }
        else
        {
          itsONled[2] = true;
        }
        break;
        case code3:
        if (itsONled[4])         
        {
          digitalWrite(led4, LOW);  
          itsONled[4] = false;           
        }
        else                         
        {
          itsONled[4] = true;
        }
        break;

    }
    Serial.println(value); // you can comment this line
    irrecv.resume(); // Receive the next value
  }
}

PS I may have posted something similar but this is more specific about the project I am working on, and I posted in under Project Guidance this time.

One obvious problem is that you use the same variable for previousMillis for more than one pattern

I am badly struggling with the FSM concept and millis, let alone integrating it in my code.

I am just basically doing educated guesses from the existing codes I had(credits to that other guy who helped me before in starting the whole coding.)

So, is FSM with a combination of millis the only way to make my project work?

If you want several LED patterns to run simultaneously then an FSM is not the right tool because by definition only one state, hence one pattern would be active at a time

I am short of time ATM but will look at your requirements and code later but I suspect that others will reply before me

It's ok no worries , I do appreciate your time for looking into my query. Hope to hear from you.

Hello
Well gues you need a button and a time handler.Those will handle the action request with a LED-sequence answer.

Would it be impossible through flagging and milli() timing?

I answered a very similar question just recently, showing how to turn a pattern of blinks into a Finite State Machine in a function. See below. Call the function every time through loop() and use the global "PatternNEnable" flag to turn it on or off.

You can have multiple simultaneous patterns by having multiple simultaneous FSM's. Make a function for each pattern and call ALL of them every time through loop().

Example for one pattern:

void LEDPattern1()
{
  static int state = 0;
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  // if this pattern isn't playing, reset to the beginning
  if (!Pattern1Enabled)
  {
    if (state != 0) // Pattern was in progress
    {
      // Turn off the LEDs and start over at state 0
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      state = 0;
    }
    return;
  }

  switch (state)
  {
    case 0:
      previousMillis = currentMillis;
      state = 1;
      break;

    case 1:
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      // delay(50);
      if (currentMillis - previousMillis > 50)
      {
        state = 2;
        previousMillis = currentMillis;
      }
      break;

    case 2:
      digitalWrite(led2, LOW);
      // delay(50);
      if (currentMillis - previousMillis > 50)
      {
        state = 3;
        previousMillis = currentMillis;
      }
      break;

    case 3:
      digitalWrite(led2, HIGH);
      digitalWrite(led3, LOW);
      // delay(50);
      if (currentMillis - previousMillis > 50)
      {
        state = 4;
        previousMillis = currentMillis;
      }
      break;

    case 4:
      digitalWrite(led2, LOW);
      // delay(1000);
      if (currentMillis - previousMillis > 1000)
      {
        state = 1;
        previousMillis = currentMillis;
      }
      break;
  }
}

Can I toggle the void LEDPattern1()under the section of if (irrecv.decode(&results)) ?

Not directly. You toggle a variable similar to this :

In the loop() you test that variable and call the matching pattern generation fsm.

// applying the un-delay technique, one timer is all you need
// I figured this out in 2015 while cleaning up SEDC (someone else's delay code).
// The worst case removed 13 delay() calls for the 1 timer!

void LEDPattern1()
{
  static int state = 0;
  static unsigned int previousMillis = 0;
  unsigned int currentMillis = millis() ;       // gets the low 16 bits to cover 1000ms
  unsigned int waitMillis;

  if ( waitMillis )  // 0 is false, not-0 is true
  {
      if (currentMillis - previousMillis >= waitMillis)
      {
        previousMillis = currentMillis;
        waitMillis = 0;
      }
      else
      {
        return;
      }
    }

  // if this pattern isn't playing, reset to the beginning
  if (!Pattern1Enabled)
  {
    if (state != 0) // Pattern was in progress
    {
      // Turn off the LEDs and start over at state 0
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      state = 0;
    }
    return;
  }

  switch (state)
  {
    case 0:
      previousMillis = currentMillis;
      state = 1;
      break;

    case 1:
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      // delay(50);
      waitMillis = 50;  
      state = 2;
      break;

    case 2:
      digitalWrite(led2, LOW);
      // delay(50);
      waitMillis = 50;  
      state = 3;
      break;

    case 3:
      digitalWrite(led2, HIGH);
      digitalWrite(led3, LOW);
      // delay(50);
      waitMillis = 50;  
      state = 4;
      break;

    case 4:
      digitalWrite(led2, LOW);
      // delay(1000);
      waitMillis = 1000;  
      state = 1;
      break;
  }
}
1 Like

With John's version the function has its own timers -- it has to run every time void loop() goes around to keep updated but what it does depends on if a flag is set, Pattern1Enabled.

When you use timers, you can write tasks that signal each other through variables.

Code for a job spreads out, indent levels drop and debug can get easier.

State machines can have their own state machines, can have etc. Wait till you try deciphering text!

PS -- funny, I USED TO HAVE signature text saying

You can detect events in time to control events over time.

So this void LEDPattern1()is to be inserted before the void loop() ?

Does this also mean I get to toggle that void LEDPattern1() to on/off from this code:

if (irrecv.decode(&results))
  {
    unsigned int value = results.value;
    switch (value)
    {
      case code1:
        if (itsONled[1])         // if first led is on then
        {
          digitalWrite(led1, LOW);   // turn it off when button is pressed
          itsONled[1] = false;           // and set its state as off
        }
        else                          // else if first led is off
        {
          digitalWrite(led1, HIGH); // turn it on when the button is pressed
          itsONled[1] = true;          // and set its state as on
        }
        break; 

?

Sorry if I sound so lost. With your input and John's, I am deciphering the logic of the coding. Hopefully I can grasp the logic soon, everything is so overwhelming, I never expected coding a simple strobe pattern could be this deep. :slight_smile:

I post what I think you can get, I'm not too hopeful am I?

Maybe, I should have read the start, you didn't know about delay() being blocking code.

Nick Gammon made a very clear blog that can help with that, Gammon Forum : Electronics : Microprocessors : How to do multiple things at once ... like cook bacon and eggs

You've not described the light patterns for the 4 leds, either in this thread or the other one you opened: IR Control and Independent Strobe Patterns
It could be very easy if these are closely related. You could make a simple diagram like the green lines here to indicate on/off and a time line:
43L1z

Also say what resolution you require. To the second or millisecond or what ?

I am catching up, and I do find your inputs helpful.

Your inputs are what I need so I can understand better the things I read.

But again, thanks for the additional link, I will read it until I digest all the info. again thanks for your precious time in responding to my questions

PS I started coding literally 2 or 3 days ago so everything is new to me, and I'm getting brain cramps already.

With John's version the function has its own timers -- it has to run every time void loop() goes around to keep updated but what it does depends on if a flag is set, Pattern1Enabled to keep running. Pattern1Enabled = 0 stops the pattern.

If button 2 is pressed, set it to 1.

You have to make a pattern 2 function and a Pattern2Enabled for button 3.

Running Arduino without blocking will let you run void loop() at over 60KHz running light tasks, including a loop counter/display. From one execution of void loop() to the next taking around 16 microseconds average per small step, keeps quick responses from fast running code.

delay(1) wastes 16000 cpu cycles. Computing power depends on using cycles best.
You have lots more clues than you did 2 days ago!

Button 1 has 1 LED, goes on and off as simple as that.

Button 2 has 2 LED, 1st LED blinks at 50millisecond intervals for 2 times in 1 second, 2nd LED turns blinks once for 50 millisecond in 1 second

Button 3 has 1 LED, it blinks at 100 millisecond in 1 second.

with all the blink pattern mentioned above, what I wanted to happen is that each button works on its own and is not in any way affected by the codes of the other buttons

Hope that clears the light pattern part, hence I reposted this thread with a more detailed explanation of what happens vs what I want to happen.

I sure did have more clues to work with around on this, I appreciate the inputs. :slight_smile: