state machine code for led's

Hi all, going to be cheeky.
I bought 2 arduinos to mount in a model helicopter to flash and fade some nav lights.
Here is the cheeky bit.
I have watched videos and read examples and forum posts but the programming is beyond me as far as state machines go and i have found no post with an indication of how i can fade and blink led's in a loop that would only be powered up for 15 mins max.
Is it too cheeky to ask if someone is willing to write a bit of code for me so if nothing else, i can pick apart what is happening in sections eg: a loop with two clearly separate bits of code, with one double flashing led with a 1/2 second delay between flashes then pause say 1.5 to 2 seconds and repeat and a 2nd bit of code to fade in and out two led's at say 2 seconds to fade in then 2 seconds to fade out. these 2 sets of led's behaviour is not required to be in unison, they need to overlap their 'state' independently. this whole 'loop' would need to run up to 15 minutes because that's more than enough time that my flight battery will provide.
I just can't get my head round the language and when i bought the arduinos, i thought the language would be easier for me to understand.
Thanks for your time, regards,
Robs brain cell on behalf of Rob
Cheers

This forum works best when you post your code (following instructions) and tell us what it does versus what you want it to do. Anything else is "cheeky".

The Arduino IDE makes it relatively easy to write your own software and we can assist.

If you want code written for you, go to the section entitled "Gigs and Collaborations" and bring your wallet.

thanks :slight_smile:

Have a look at MultiBlink4 in my code repository (link below). It will probably do what you need out of the box with just a few changes to the data table.

Like..

These..

or

These...

Or maybe..

These?

-jim lee

I always prefer to do these sorts of things with classes and objects.

A class is a way of bundling together some state and some code. The bit of code that does fading needs a bundle of variables to keep track of where the fade is at, and likewise the flasher needs some variables to know here the flash is at. And these things don't need to know about one another. So using classes makes a lot of sense.

Hang on - let me dig out some LEDs ..

Ok. I have LEDs in 5,6, 9,10.

I am going to make a Flasher class and a Fader class. The flasher class will have a small array of uint32_t, indicating the on/off times. The fader class will have a single uint32_t for the fade time in mills.

They will also need some state - the flasher needs to know which "step" of the flashing sequence it is at and when that step started, and the fader needs to know whether it is fading up or down and when it started doing that.

Both components need to know which pin they are talking to, so let's do that first:

struct Flasher {
  const byte pin;

  Flasher(byte attachPin) : pin(attachPin) 
  {}
};

struct Fader {
  const byte pin;

  Fader(byte attachPin) : pin(attachPin) 
  {}
};

void setup() {
  // put your setup code here, to run once:
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:

}

The code that looks like this:

  Fader(byte attachPin) : pin(attachPin) {}

is called a constructor. Its job is to initialise the variables inside a class int a correct initial state.

Now that I have that mush code, I will instantiate two instances of each class.

Fader  fader1(5), fader2(6);
Flasher flasher1(9), flasher2(10);

Having done that, I would rather do the pinMode call inside the class itself. This needs to be done at setup, not at instantiation. So I will make a setup() method in the class and call it. The method can be called anything, but to keep things consistent I prefer to call it "setup".

struct Flasher {
  const byte pin;

  Flasher(byte attachPin) : pin(attachPin) 
  {}

  void setup() {
    pinMode(pin, OUTPUT);
  }
};

struct Fader {
  const byte pin;

  Fader(byte attachPin) : pin(attachPin) 
  {}

  void setup() {
    pinMode(pin, OUTPUT);
  }
};

Fader  fader1(5), fader2(6);
Flasher flasher1(9), flasher2(10);

void setup() {
  flasher1.setup();
  flasher2.setup();
  fader1.setup();
  fader2.setup();
}

void loop() {
  // put your main code here, to run repeatedly:

}

-- I'll break this up into mutiple posts on this thread, ok?

Next, I will add some terms to the constructor to hold the sequence values. I will also initialise the other variables.

The fader is simple. All I need is a single variable holding the fade time. I will initialise the fader into "getting brighter" state, and I will pretend that the initial fade started at time 0.

struct Fader {
  const byte pin;
  const uint32_t fadeTime;

  uint32_t startTime;
  boolean gettingBrighter;

  Fader(byte attachPin,  uint32_t fadeTime) : 
    pin(attachPin),
    fadeTime(fadeTime)
  {
    startTime = millis();
    gettingBrighter = true;
  }

  void setup() {
    pinMode(pin, OUTPUT);
  }
};

Fader  fader1(5, 1000L), fader2(6, 1616L);

I set the startTime and gettingBrighter in the body go the constructor because these are variables. It's unnecessary - I could have done it using the colon syntax.

I use 1616 as the other fade the because 1616/1000 is the golden ratio :slight_smile: .

The flasher is a bit trickier. I want to hold the flash sequence in an array. I want this array to be any length, so I'll build it outside the constructor. But how will I indicate to the constructor it's length? I'll tell you what - I'll adopt the convention that the last item in the array is always a zero. This make sense, because why would you bother having a flash length of zero? So as the flasher reads through its flash length array, a length of zero indicates "return to the start of the sequence".

struct Flasher {
  const byte pin;
  const uint32_t *sequence;

  int sequenceIndex;
  boolean flashOn;
  uint32_t startTime;

  Flasher(byte attachPin, const uint32_t *sequence) : pin(attachPin) , sequence(sequence)
  {
    flashOn = false;
    sequenceIndex = 0;
    startTime = millis();
  }

  void setup() {
    pinMode(pin, OUTPUT);
  }
};

uint32_t sequence1[] = {1000, 0};
uint32_t sequence2[] = {250, 500, 250, 2000, 0};

Flasher flasher1(9, sequence1), flasher2(10, sequence2);

And now for the magic.

I will create a method inside both Flasher and Fader which will be called each time loop executes. To keep things consistent, I'll call it "loop". This method will look at millis, look at the constants, look at the current state, and from there work out what to do with the led that it is attached to.

Fader is the easier of the two, so I'll start there.

struct Fader {
  const byte pin;
  const uint32_t fadeTime;

  uint32_t startTime;
  boolean gettingBrighter;

  Fader(byte attachPin,  uint32_t fadeTime) : 
    pin(attachPin),
    fadeTime(fadeTime)
  {
    startTime = millis();
    gettingBrighter = true;
  }

  void setup() {
    pinMode(pin, OUTPUT);
  }

  void loop() {
    if(millis() - startTime >= fadeTime) {
      startTime = millis();
      gettingBrighter = !gettingBrighter;
    }

    if(gettingBrighter) {
      analogWrite(pin, (millis()-startTime)/((double) fadeTime) * 255);
    }
    else {
      analogWrite(pin, 255-(millis()-startTime)/((double) fadeTime) * 255);
    }
  }
};

Notice how loop doesn't need to worry about the fact that it's not the only fader in existence. Inside a method, variable names relate to some particular instance of the class. When I call fader1.loop(), loop() uses the variables in fader1. I don't need a swag of separate names for things.

The flasher is a bit more complicated:

struct Flasher {
  const byte pin;
  const uint32_t *sequence;

  int sequenceIndex;
  boolean flashOn;
  uint32_t startTime;

  Flasher(byte attachPin, const uint32_t *sequence) : pin(attachPin) , sequence(sequence)
  {
    flashOn = true;
    sequenceIndex = 0;
    startTime = millis();
  }

  void setup() {
    pinMode(pin, OUTPUT);
    //start with the LED on
    digitalWrite(pin, HIGH);
  }
  
  void loop() {
    if(millis() - startTime >= sequence[sequenceIndex]) {
      sequenceIndex++;
      if(sequence[sequenceIndex] == 0) {
        sequenceIndex = 0;
      }
      startTime = millis();

      flashOn = !flashOn;
      digitalWrite(pin, flashOn ? HIGH : LOW);
      
    }
  }
};

See the code that resets the sequence index to zero? It works because I have adopted a "the sequence ends with a zero" convention. There are other ways to do it - use 0xFFFFFFFF, hold the sequence length separately.

Notice that if the sequence length is odd, the the flasher will run through the sequence but reverse on/off. This is how sequence1 works.

And here's the complete sketch, which seems to work just fine on the arduino sitting next to my keyboard.

struct Flasher {
  const byte pin;
  const uint32_t *sequence;

  int sequenceIndex;
  boolean flashOn;
  uint32_t startTime;

  Flasher(byte attachPin, const uint32_t *sequence) : pin(attachPin) , sequence(sequence)
  {
    flashOn = true;
    sequenceIndex = 0;
    startTime = millis();
  }

  void setup() {
    pinMode(pin, OUTPUT);
    //start with the LED on
    digitalWrite(pin, HIGH);
  }
  
  void loop() {
    if(millis() - startTime >= sequence[sequenceIndex]) {
      sequenceIndex++;
      if(sequence[sequenceIndex] == 0) {
        sequenceIndex = 0;
      }
      startTime = millis();

      flashOn = !flashOn;
      digitalWrite(pin, flashOn ? HIGH : LOW);
      
    }
  }
};

struct Fader {
  const byte pin;
  const uint32_t fadeTime;

  uint32_t startTime;
  boolean gettingBrighter;

  Fader(byte attachPin,  uint32_t fadeTime) : 
    pin(attachPin),
    fadeTime(fadeTime)
  {
    startTime = millis();
    gettingBrighter = true;
  }

  void setup() {
    pinMode(pin, OUTPUT);
  }

  void loop() {
    if(millis() - startTime >= fadeTime) {
      startTime = millis();
      gettingBrighter = !gettingBrighter;
    }

    if(gettingBrighter) {
      analogWrite(pin, (millis()-startTime)/((double) fadeTime) * 255);
    }
    else {
      analogWrite(pin, 255-(millis()-startTime)/((double) fadeTime) * 255);
    }
  }
};

Fader  fader1(5, 1000L), fader2(6, 1616L);

uint32_t sequence1[] = {1000, 0};
uint32_t sequence2[] = {250, 500, 250, 2000, 0};

Flasher flasher1(9, sequence1), flasher2(10, sequence2);

void setup() {
  flasher1.setup();
  flasher2.setup();
  fader1.setup();
  fader2.setup();
}

void loop() {
  // put your main code here, to run repeatedly:
  flasher1.loop();
  flasher2.loop();
  fader1.loop();
  fader2.loop();

}

The trick with this stuff is to divide and conquer. Try the fading piece first. Searching for arduino fade without delay should solve the problem of the red leds. Blink without delay nearly solves the tail rotor issue. Join them together and you're probably eighty percent of the way there. Once you have that working, if you're still in the dark, post it here for more suggestions as to how to get the double flash you're looking for.

Or, use PaulMurrayCbr's turnkey code. In doing so you will learn either a huuuuge amount, or absolutely nothing.

Which, depends; but either way the leds will blink :wink:

(I've bookmarked it for my later consumption.)

Thank you very much for all your replies and messages. Alot of your explanations contain descriptions and pointers for me to muse over mind you, i am still at a very early stage and am still getting slowly up to speed on the base language / syntax
I may not respond for a while after this but will keep coming back to each post as i understand each process on it's own and how it 'fits' into the bigger picture. I don't think my understanding of the basics of the coding is very high but I shall try to get it to sink in. The last bit of programming I did was on a zx spectrum and ql....god i feel old.
Once again chaps, cheers for your time and effort.

manor_royal:
Or, use PaulMurrayCbr's turnkey code. In doing so you will learn either a huuuuge amount, or absolutely nothing.

Which, depends; but either way the leds will blink :wink:

(I've bookmarked it for my later consumption.)

Also, check out the link in my sig where I work through a more complicated example.

http://paulmurraycbr.github.io/ArduinoTheOOWay.html

PaulMurrayCbr:
Also, check out the link in my sig where I work through a more complicated example.

Arduino the Object Way

Willco, thanks.