Using Millis to blink two leds at differant durations

The project is for a fuel injection trigger with an ignition spark.
Linear/delays was not satisfactory.
I have modified a code from Robojax single led it works if I use Led1 or Led2 but when run both together output becomes random?? As I have written now they should both be working at same time.
What am I missing new to arduino

const int LED1pin = 13;
const long LED1onDuration = 100;// OFF time for LED
const long LED1offDuration = 1000;// ON time for LED
const int LED2pin = 10;
const long LED2onDuration = 100;// OFF time for LED
const long LED2offDuration = 1000;// ON time for LED


int LED1State =HIGH;// initial state of LED
int LED2State =HIGH;// initial state of LED




long rememberTime=0;// this is used by the code

void setup() {
  pinMode(LED1pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED1pin,LED1State);// set initial state
   pinMode(LED2pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED2pin,LED2State);// set initial state
}

void loop() {
  // Robojax LED blink with millis()

 if( LED1State ==HIGH )
 {
    if( (millis()- rememberTime) >= LED1onDuration){   
    LED1State = LOW;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime) >= LED1offDuration){     
    LED1State =HIGH;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }

 // Robojax LED blink with millis()
 digitalWrite(LED1pin,LED1State);// turn the LED ON or OFF

 
 if( LED2State ==HIGH )
 {
    if( (millis()- rememberTime) >= LED2onDuration){   
    LED2State = LOW;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime) >= LED2offDuration){     
    LED2State =HIGH;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }

 // Robojax LED blink with millis()
 digitalWrite(LED2pin,LED2State);// turn the LED ON or OFF

}// loop ends

You need separate remember times for the LEDs.

Use two variables:

remember1Time

remember2Time

Thanks Guys that was it perfect

Ok Eventually got it to do what I want with a 1199MS time but it does creep.
Fuel injects for 8ms. coil charges 10ms giving a 2ms delay till coil off Spark fires.
1199Ms Loop But if I try to change time to 2199mm total. the oscilloscope indicates.
coil charge 10ms starts 2ms before injector and fires at the same time injector off No delay. but also time creeps.
Any Ideas what i am missing, only new to arduino.


const int LED1pin = 12;
const long LED1onDuration = 8 ;// ON time for LED Fuel Injector
const long LED1offDuration = 1191;// OFF time for LED Fuel Injector
const int LED2pin = 10;
const long LED2onDuration = 10;// ON time for LED ignition coil charge time
const long LED2offDuration = 1189;// OFF time for LED Coil fired 2MS delay


int LED1State =LOW;// initial state of LED
int LED2State =LOW;// initial state of LED




long rememberTime1=0;// this is used by the code
long rememberTime2=0;// this is used by the code

void setup() {
  pinMode(LED1pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED1pin,LED1State);// set initial state
   pinMode(LED2pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED2pin,LED2State);// set initial state
  delay(2000);
}

void loop() {
  // Robojax LED blink with millis()

 if( LED1State ==HIGH )
 {
    if( (millis()- rememberTime1) >= LED1onDuration){   
    LED1State = LOW;// change the state of LED
    rememberTime1=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime1) >= LED1offDuration){     
    LED1State =HIGH;// change the state of LED
    
    rememberTime1=millis();// remember Current millis() time
    }
 }
// Robojax LED blink with millis()
 digitalWrite(LED1pin,LED1State);// turn the LED ON or OFF
  
   if( LED2State ==HIGH )
 {
    if( (millis()- rememberTime2) >= LED2onDuration){   
    LED2State = LOW;// change the state of LED
    rememberTime2=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime2) >= LED2offDuration){     
    LED2State =HIGH;// change the state of LED
    
    rememberTime2=millis();// remember Current millis() time
    }
 }
 
 // Robojax LED blink with millis()
 
digitalWrite(LED2pin,LED2State);// turn the LED ON or OFF
}// loop ends

The millis-timer is a handy way to deal with timing specific code. It uses very little memory, so it can be used on a Arduino Uno. The modern processors can run multitasking, and then all this millis-timer hassle is no longer needed.

Have you read the Blink Without Delay page ? https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
There is also a way to keep the millis-timer in sync with the time, so it does not creep at all.

Please use "unsigned long" for variables that work with the millis() function.
If there is one timing thing to do, then you need one millis-timer.

Can you explain in words what you want ?
Is is this:
Every 2199 ms:

  • 0 ms start inject
  • 8 ms later stop inject, start coil
  • 10 ms later stop coil
  • 2 ms later ?

Hello
Post a timing diagram.

Add the interval instead. Any imprecision will accumulate over time otherwise. Also get rid of the delay function calls.

Depending on the resolution you need you might have to use a hardware timer.

I have watched numerous video on blink without delay but they dont quite suit my purpsoe
I need to be able to have eveyrything ajustable as i will be expermenting to get the fuel air mixture right to get the fuel to ignite,The hope is to get detonation.
First I am Trying

  • 0 ms start inject and charge coil
  • 8 ms later stop inject
  • 2 ms later turn off coil to fire the spark.

so
unsigned long rememberTime1=0;// this is used by the code
unsigned long rememberTime2=0;// this is used by the code

What about
const long LED1onDuration etc will they be constant or do they need to be unsigned also?

What is supposed to trigger this chain of events?

I would have to start to learn how to do intervals.
The delay is only in the setup "run once" just to give me time to get the rest of the components ready so it doesn't fire before I m ready.

I am using the arduino to fire a Coil over spark cap and an 400cc fuel injector running at 75PSI to atomize the fuel.

I havent got a burn or fuel ignition as yet. fuel ratio and spark are going to be critical.

I may have to look at intervals.
With the suggestions so far timing still drifting.
and when i change the total time (add 1000ms) the coil turns on 2ms before the injector fires not 2ms after.

You can do something like this. It compiles but I've not tested it.

#define INJECTION_TIME 8

#define CHARGE_TIME 10

// Here we define the different states this task can be in
enum FuelInjectionState {
  WaitTrigger,
  WaitInjection,
  WaitCharge,
  Done
};

static uint8_t getTrigger(void) {
  // TODO return a true value on a trigger (a push button for example)
  return 1;
}

static void startInjection(void) {
  // TODO start the fuel injection here
}

static void stopInjection(void) {
  // TODO stop the fuel injection here
}

static void startCharge(void) {
  // TODO start the coil charging here
}

static void stopCharge(void) {
  // TODO stop the coil charging here
}

static void fuelInjectionTask(void) {

  // We keep these variables within function scope to shield
  // them from being unintentionally altered. The static keyword
  // makes sure that they keep their values between the calls to the function.
  static uint32_t t = 0;
  static enum FuelInjectionState currentState = WaitTrigger;

  switch (currentState) {

    case WaitTrigger:

    // Here we determine whether our trigger event has happened.
    if (getTrigger()) {
      // We set the current time and start the injection and charge.
      // Setting the currentState variable makes the next call to this
      // function enter the WaitInjection case.
      t = millis();
      startInjection();
      startCharge();
      currentState = WaitInjection;
    }
    
    break;

    case WaitInjection:

    // If INJECTION_TIME has passed, we stop the injection and
    // advance the state machine to the WaitCharge case.
    if (millis() - t >= INJECTION_TIME) {
      stopInjection();
      currentState = WaitCharge;
    }

    // If the previous if statement is not true, this is the only statement that will happen.
    // Since we're continuously just breaking out of the switch statement the state machine will not
    // do anything for INJECTION_TIME milliseconds.
    break;

    case WaitCharge:

    // If CHARGE_TIME has passed, we stop the coil charging and
    // advance the state machine to the done state. 
    if (millis() - t >= CHARGE_TIME) {
      stopCharge();
      currentState = Done;
    }

    // Same as previous case.
    break;

    case Done:
    // In this state nothing will be done for now. It would be ideal to determine whether it's okay to return
    // to the WaitTrigger state. Ex. the pushbutton has been released again or a cooldown time has passed.
    break;
    
  }
  
}

void setup() {
  
}

void loop() {
  // This function has to be called periodically.
  // Keep in mind that this is only deterministic if you call the fuelinjectionTask() function, 
  // atleast every CHARGE_TIME or (CHARGE_TIME - INJECTION_TIME), whichever is lowest, milliseconds. So long delays and alike has got to go.
  // It doesn't really matter whether it's called from the loop() function or if you set up a hardware timer to do it.
  fuelInjectionTask();
}

Edit: I realize that me using the terms case and state interchangeably might be a bit confusing. I mean the same thing.

Hi thank you for the code it is a bit over my head but.
If I have understood your code it will require a button trigger.
which will be ok to calibrate the initial fuel air mix and fire time.
will it be able to repeat the final program with differant time between cycles similar to a pulse jet engine.

You're welcome. Read the comments carefully and try to play around with it a bit and it should make sense. Feel free to ask if clarification is needed.

It doesn't have to be a button. It could be anything.

I'm not familiar with pulse jet engines, but the trigger could be a timespan.

Edit: Just to clarify, the code is not meant to be a complete solution, just a starting point you can build on.

OK Thanks It looks like another learning curve.

Thought I was going ok now stuck on something simple.
'ButtonPin' was not declared in this scope
I will have to sleep. Midnight here.
looks like no testing with this code in the morning.
This is where I got to

const int InjectPin = 12;
const int IgnitionPin = 10;


int InjectState =LOW;// initial state of LED
int IgnitionState =LOW;// initial state of LED

#define INJECTION_TIME 8

#define CHARGE_TIME 10

// Here we define the different states this task can be in
enum FuelInjectionState {
  WaitTrigger,
  WaitInjection,
  WaitCharge,
  Done
};
static uint8_t getTrigger(void) {
 
int pb = digitalRead(2);// read pin 2



  // TODO return a true value on a trigger (a push button for example)
  return 1;
}

static void startInjection(void) {
  InjectState =HIGH;
  // TODO start the fuel injection here
}

static void stopInjection(void) {
  InjectState =LOW;
  // TODO stop the fuel injection here
}

static void startCharge(void) {
  IgnitionState =HIGH;
  // TODO start the coil charging here
}

static void stopCharge(void) {
  IgnitionState =LOW;
  // TODO stop the coil charging here
}

static void fuelInjectionTask(void) {

  // We keep these variables within function scope to shield
  // them from being unintentionally altered. The static keyword
  // makes sure that they keep their values between the calls to the function.
  static uint32_t t = 0;
  static enum FuelInjectionState currentState = WaitTrigger;

  switch (currentState) {

    case WaitTrigger:

    // Here we determine whether our trigger event has happened.
    if (getTrigger()) {
      // We set the current time and start the injection and charge.
      // Setting the currentState variable makes the next call to this
      // function enter the WaitInjection case.
      t = millis();
      startInjection();
      startCharge();
      currentState = WaitInjection;
    }
    
    break;

    case WaitInjection:

    // If INJECTION_TIME has passed, we stop the injection and
    // advance the state machine to the WaitCharge case.
    if (millis() - t >= INJECTION_TIME) {
      stopInjection();
      currentState = WaitCharge;
    }

    // If the previous if statement is not true, this is the only statement that will happen.
    // Since we're continuously just breaking out of the switch statement the state machine will not
    // do anything for INJECTION_TIME milliseconds.
    break;

    case WaitCharge:

    // If CHARGE_TIME has passed, we stop the coil charging and
    // advance the state machine to the done state. 
    if (millis() - t >= CHARGE_TIME) {
      stopCharge();
      currentState = Done;
    }

    // Same as previous case.
    break;

    case Done:
    // In this state nothing will be done for now. It would be ideal to determine whether it's okay to return
    // to the WaitTrigger state. Ex. the pushbutton has been released again or a cooldown time has passed.
    break;
    
  }
  
}

void setup() {
   pinMode(InjectPin,OUTPUT);// define LEDpin as output
  digitalWrite(InjectPin,InjectState);// set initial state
   pinMode(IgnitionPin,OUTPUT);// define LEDpin as output
  digitalWrite(IgnitionPin,IgnitionState);// set initial state
 pinMode(2,INPUT_PULLUP);
 pinMode(ButtonPin, INPUT); 
}

void loop() {
  {
  bool buttonValue = digitalRead(ButtonPin);
  //if (ButtonPinValue == 0(LOW)) // Does not work, use or LOW or 0
  if(buttonValue == LOW)
  {
    digitalWrite(Led, LOW);
  }
}
  // This function has to be called periodically.
  // Keep in mind that this is only deterministic if you call the fuelinjectionTask() function, 
  // atleast every CHARGE_TIME or (CHARGE_TIME - INJECTION_TIME), whichever is lowest, milliseconds. So long delays and alike has got to go.
  // It doesn't really matter whether it's called from the loop() function or if you set up a hardware timer to do it.
  fuelInjectionTask();
}

I have gone back to my original problem with millis.
i have creep between the two pulses after approx 50 seconds ( can deal with that at present as i only require a few cycles to see if I can get fuel ignition)
But timing on the osciloscope is fine for 1199ms. (Number found buy trial and error)

  • 0 ms start inject and charge coil
  • 8 ms later stop inject
  • 2 ms later turn off coil to fire the spark.
    If I try to change the time to say 2199ms or ?199ms
    timing on the osciloscope shows
  • 0 ms charge coil
  • 2 ms later start inject
    *8 ms later stop injector and turn off coil to fire the spark.

My 67 year old brain is missing something!


const int LED1pin = 12;
const unsigned long LED1onDuration = 8 ;// ON time for LED
const unsigned long LED1offDuration = 1191;// OFF time for LED
const int LED2pin = 10;
const unsigned long LED2onDuration = 10;// ON time for LED
const unsigned long LED2offDuration = 1189;// OFF time for LED


int LED1State =LOW;// initial state of LED
int LED2State =LOW;// initial state of LED




unsigned long rememberTime1=millis();// this is used by the code
unsigned long rememberTime2=millis();// this is used by the code

void setup() {
  pinMode(LED1pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED1pin,LED1State);// set initial state
   pinMode(LED2pin,OUTPUT);// define LEDpin as output
  digitalWrite(LED2pin,LED2State);// set initial state
  delay(2000);
}

void loop() {
  // Robojax LED blink with millis()

 if( LED1State ==HIGH )
 {
    if( (millis()- rememberTime1) >= LED1onDuration){   
    LED1State = LOW;// change the state of LED
    rememberTime1=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime1) >= LED1offDuration){     
    LED1State =HIGH;// change the state of LED
    
    rememberTime1=millis();// remember Current millis() time
    }
 }
// Robojax LED blink with millis()
 digitalWrite(LED1pin,LED1State);// turn the LED ON or OFF
  
   if( LED2State ==HIGH )
 {
    if( (millis()- rememberTime2) >= LED2onDuration){   
    LED2State = LOW;// change the state of LED
    rememberTime2=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime2) >= LED2offDuration){     
    LED2State =HIGH;// change the state of LED
    
    rememberTime2=millis();// remember Current millis() time
    }
 }
 
 // Robojax LED blink with millis()
 
digitalWrite(LED2pin,LED2State);// turn the LED ON or OFF
}// loop ends

**