Yet ANOTHER millis() blink with different on/off durations

I was bored this evening - so here's the same old' millis() blink - but showing different on/off durations. Indenting has been pushed - to help identify the separate blocks of code! Also demonstrates conditional compilation with #define #ifdef and #endif

//----------------------------------------------
// BLINK ON-BOARD LED using millis() 
// Demonstrating variable length on/off duration.
// Also illustrate using a function() without parameters
//----------------------------------------------
#define SERIAL_COMMENTS  115200 //comment-out, UNDEFine or delete if not required
//----------------------------------------------
#define LED_pin 13  // ths inbuilt UNO LED
//----------------------------------------------
unsigned long state_started_at;

// these /could/ be a smaller data type - sufficient to hold the durations
unsigned long blink_on_duration = 100;  // mSecs LED on
unsigned long blink_off_duration = 1000;  // mSecs LED off

bool LED_state = LOW;  // initial state will be toggled as part of setup()

//----------------------------------------------
// set the LED pin direction to OUTPUT, and enable Serial if it is needed
// then send the initial LED_state out to the LED
//----------------------------------------------
void setup() {
    pinMode (LED_pin, OUTPUT);
                #ifdef SERIAL_COMMENTS  // these lines can be deleted if you understand the code
                    // ensure serial is opened -before- calling toggle - so the LED_state can be displayed !
                    Serial.begin(SERIAL_COMMENTS);
                #endif
    toggle_LED();   // call a function to invert the LED_state
}

//----------------------------------------------
void loop() {
    // depending on prevailing state and period - toggle LED to the 'other' state
    if (LED_state) { // if the LED state is currently ON
        // and the ON duration has elapsed
        if  (millis() - state_started_at >= blink_on_duration) {
                #ifdef SERIAL_COMMENTS  // these lines can be deleted if you understand the code
                    Serial.print("ON duration elapsed...");
                #endif
            toggle_LED();
        }
    } else { // then, the LED state must be OFF
        // and the OFF duration has elapsed
        if  (millis() - state_started_at >= blink_off_duration) {
                #ifdef SERIAL_COMMENTS  // these lines can be deleted if you understand the code
                    Serial.print("OFF duration elapsed...");
                #endif
            toggle_LED();
        }
    }
}

//----------------------------------------------
// change the LED state from on->off and vice-versa with each call
//----------------------------------------------
void toggle_LED() {
    LED_state = !LED_state;  // invert the LED_state variable
                #ifdef SERIAL_COMMENTS  // these lines can be deleted if you understand the code
                    //------------------------
                    if (LED_state)
                        Serial.println ("TURN ON"); 
                    else
                        Serial.println ("TURN OFF"); 
                #endif
    //------------------------
    // start a new duration for current LED_state
    state_started_at = millis();
    digitalWrite(LED_pin, LED_state);  // push it out to the LED
}
//----------------------------------------------

Personally I would favour something like this

const byte ledPin = 13;
const unsigned long durations[] = {1000, 100};
byte indexToDurations = 0;
unsigned long startTime;

void setup()
{
  pinMode(ledPin, OUTPUT);
  startTime = millis();
}

void loop()
{
  if (millis() - startTime >= durations[indexToDurations])
  {
    digitalWrite(ledPin, !digitalRead(ledPin));
    startTime = startTime + durations[indexToDurations];
    indexToDurations = !indexToDurations;
  }
}

Yes, i agree if the purpose is solely to perform on/off blinking, but I feel it introduces too many skills inline for a beginner. - Indexing, arrays etc.

(I did consider folding the conditional block into a single line, but figured leaving it open would help newbies see the logoc more easily)

Most are looking for an understanding of why/how mills() can replace delay()
Good shot though, everything helps beginners grasp a bit more.

Cheers.

The inclusion of an array and an index index was deliberate as, I assume, was your use of a function and the scary looking #defines and #ifdefs, to say nothing of the truly nutty formatting.

For serial comments consider something like this:

// DebugMacros.h

/* Example of use:
   #define DEBUG          // <-----<<<< this line must appear before the include line
   #include <DebugMacros.h>
*/

//If you comment the line:  #define DEBUG
//The Macro lines are defined as blank, thus would be ignored by the compiler.
//If the line is NOT commented, these macros will be included in the sketch.
// examples:
// This  converts to         >>>>----->         This OR a Blank Line. 
//---–----------------------------------------------------------------------------------------
// DPRINTLN("Testing123");   >>>>----->     Serial.println("Testing123"); 
// DPRINTLN(0xC0FFEEul,DEC); >>>>----->     Serial.println(0xC0FFEEul,DEC);
// DPRINTLN(12648430ul,HEX); >>>------>     Serial.println(12648430ul,HEX);
// DPRINTLNF("This text came from flash");  Serial.println(F("This text came from flash"));
// DPRINT(myVariable);       >>>>----->     Serial.print(myVariable);
// DELAY(100);               >>>>----->     delay(100);
// SERIALBEGIN(9600);        >>>>----->     Serial.begin(9600);
// PINMODE(13,OUTPUT);       >>>>----->     pinMode(13,OUTPUT);
// TOGGLEd13;                >>>>----->     PINB = 0x20;  // D13 Toggle,for UNO ONLY
 
#ifdef DEBUG
//#define DPRINT(args...)  Serial.print(args)             //OR use the following syntax:
#define SERIALBEGIN(...)   Serial.begin(__VA_ARGS__)
#define DPRINT(...)        Serial.print(__VA_ARGS__)
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#define DRINTF(...)        Serial.print(F(__VA_ARGS__))
#define DPRINTLNF(...)     Serial.println(F(__VA_ARGS__)) //Printing text using the F macro
#define DELAY(...)         delay(__VA_ARGS__)
#define PINMODE(...)       pinMode(__VA_ARGS__)
#define TOGGLEd13          PINB = 0x20                    //For the UNO only
 
#else
#define SERIALBEGIN(...)   //blank line
#define DPRINT(...)        //blank line
#define DPRINTLN(...)      //blank line
#define DPRINTF(...)       //blank line
#define DPRINTLNF(...)     //blank line
#define DELAY(...)         //blank line
#define PINMODE(...)       //blank line
#define TOGGLEd13          //blank line 
 
#endif
//***************************************************************

Consider this kind of format for updating a timing variable.

while ( currentMillis - millisOne >= delayTime )
    {
      millisOne = millisOne + delayTime;
    }