concurrent millis function

I am looking at developing a very basic program for my research purposes. Two LED lights are randomly triggered for a set period of 3 seconds. If the user then clicks the correct button, a answer of correct is returned. Now here the problem comes in and its probably due to my limited understanding of the millis function unfortunately.

Each time after a light has been triggered for the 3 sec, I want a delay of 0.5sec before a random light triggers again. Ideally I dont want to do this using the delay function.

Any help would be greatly appreciated!

const int LEDLeftPin = 6;
const int LEDRightPin = 5;

const int ButtonLeftPin = 13;
const int ButtonRightPin = 12;
  
int rand_val;

int ButtonLeftState, ButtonRightState;

boolean ButtonPressed = false;
boolean TestComplete = false;

long previousMillis = 0;
long interval = 2000;

int loopNo = 0;
const int TotalLoops = 9;

int CorrectAnswer = 0;

void setup(){
  Serial.begin(9600);
  pinMode(LEDLeftPin,OUTPUT);
  pinMode(LEDRightPin,OUTPUT);

  pinMode(ButtonLeftPin,INPUT);
  pinMode(ButtonRightPin,INPUT);

  randomSeed(analogRead(0));
}

void loop(){
  
  unsigned long currentMillis = millis();
  
  if((currentMillis - previousMillis >= interval) && (loopNo <= TotalLoops)) {
    previousMillis = currentMillis;
    rand_val = random(0,2);
    ButtonPressed = false;
    loopNo++;
    Serial.println(rand_val);
    Serial.println(loopNo);
    
    //Activate lights
   
    if(rand_val == 0) {
         digitalWrite(LEDLeftPin,HIGH);
         digitalWrite(LEDRightPin,LOW);
    }
    
    else if(rand_val == 1) {
          digitalWrite(LEDRightPin,HIGH);
          digitalWrite(LEDLeftPin,LOW);
      }      
  }
 
 //Delaying light
 
 if((currentMillis - previousMillis >= interval - 500) && (currentMillis - previousMillis >= interval)){
   digitalWrite(LEDLeftPin,LOW);
   digitalWrite(LEDRightPin,LOW);
 }
 
 
    
  //Buttons 0 is pressed and 1 us unpressed
  
  ButtonRightState = digitalRead(ButtonRightPin);
  ButtonLeftState = digitalRead(ButtonLeftPin);
 
 //Left button test   
    
  if((ButtonLeftState == 0) && (rand_val == 0) && (!ButtonPressed)){
    ButtonPressed = true;
    CorrectAnswer++;
    Serial.println("Correct");
      }
 //Correct percentage - when loop 15 runs, calculate percentage of correct answers
 
 if((loopNo == TotalLoops + 1) && (!TestComplete)){
   TestComplete = true;
   Serial.println("Accuracy of %");
   Serial.print(CorrectAnswer);
 }
}

It sounds like you are describing a state machine. At any one time the system is in a particular state doing something until it is moved to a new state either by time elapsing or input of some kind.

I find it easiest to program this using switch/case with the cases being the state numbers and the code for each case taking user input and updating the state number appropriately or when the appropriate time has elapsed as in

if (millis() - stateStartTime >= statePeriod)
{
  //update the state number, which does not have to the next number
  state = approprateStateNumber;
  stateStartTime = millis();  //save the start time for the new state if it is to be time based rather than input based.
  break;
}

Next time though the switch/case the code for the changed state number will be executed

Maybe someone could explain this to me. I cant seem to use the below twice in once feature

if(currentMillis - previousMillis >= interval){

As soon as i use this if statement more than once, the second one does not work.

As soon as i use this if statement more than once, the second one does not work.

It's most likely a coding error, then. Since we can't see your code, you'll need to fix it.

Sorry about that, here is the code. Im looking to run the Serial.println"LED not registered" 3 seconds after the initial variable is chosen in the beginning.

const int LEDLeftPin = 6;
const int LEDRightPin = 5;

const int ButtonLeftPin = 13;
const int ButtonRightPin = 12;
  
int rand_val;

int ButtonLeftState, ButtonRightState;

boolean ButtonPressed = false;
boolean LEDNotRegistered = false;
boolean TestComplete = false;

long previousMillis = 0;
long interval = 3000;

int loopNo = 0;
const int TotalLoops = 9;

int CorrectAnswer = 0;
int WrongAnswer = 0;

void setup(){
  Serial.begin(9600);
  pinMode(LEDLeftPin,OUTPUT);
  pinMode(LEDRightPin,OUTPUT);

  pinMode(ButtonLeftPin,INPUT);
  pinMode(ButtonRightPin,INPUT);

  randomSeed(analogRead(0));
}

void loop(){
  unsigned long currentMillis = millis();
  int test = interval + (interval * loopNo);
  
  if((currentMillis - previousMillis == interval) && (loopNo <= TotalLoops)) {
    previousMillis = currentMillis;
    rand_val = random(0,2);
    ButtonPressed = false;
    loopNo++;
    
    Serial.println(rand_val);
    Serial.println(loopNo);
    
    //Activate lights
   
    if(rand_val == 0) {
         digitalWrite(LEDLeftPin,HIGH);
         digitalWrite(LEDRightPin,LOW);
    }
    
    else if(rand_val == 1) {
          digitalWrite(LEDRightPin,HIGH);
          digitalWrite(LEDLeftPin,LOW);
      }      
  }
 
 //Delaying light
     
  //Buttons 0 is pressed and 1 us unpressed
  
  ButtonRightState = digitalRead(ButtonRightPin);
  ButtonLeftState = digitalRead(ButtonLeftPin);
 
 //Left button test   
    
  if((ButtonLeftState == 0) && (rand_val == 0) && (!ButtonPressed)){
    ButtonPressed = true;
    CorrectAnswer++;
    Serial.println("Correct");
      }      
   else if(((ButtonRightState == 0) && (rand_val == 0) && (!ButtonPressed)) ||((ButtonLeftState == 0) && (rand_val == 1) && (!ButtonPressed))){
    ButtonPressed = true;
    WrongAnswer++;
    Serial.println("Wrong");
      }
    
    if((currentMillis - previousMillis == interval) && (loopNo <= TotalLoops) && (!ButtonPressed)) {
      ButtonPressed = true;
      Serial.println("LED not registered");
    }
 
 //to test whether user did not register LED. In time span(interval) if buttonstate = 0 && buttonpress = false.     
      
 //Correct percentage - when loop 10 runs, calculate percentage of correct answers
 
 if((!TestComplete) && ( currentMillis == 3000 + (TotalLoops +1) * interval)){
   TestComplete = true;
   Serial.println("Accuracy of %");
   Serial.print(CorrectAnswer);
 }
}

== :wink:

Seems to be working now. This milli timing thing is really doing my head in =(

Thanks for the help!

const int LEDLeftPin = 6;
const int LEDRightPin = 5;

const int ButtonLeftPin = 13;
const int ButtonRightPin = 12;
  
int rand_val;

int ButtonLeftState, ButtonRightState;

boolean ButtonPressed = false;
boolean LEDNotRegistered = false;
boolean TestComplete = false;
boolean NotRun = false;

long previousMillis = 0;
long interval = 3000;

int loopNo = 0;
const int TotalLoops = 9;

int CorrectAnswer = 0;
int WrongAnswer = 0;

void setup(){
  Serial.begin(9600);
  pinMode(LEDLeftPin,OUTPUT);
  pinMode(LEDRightPin,OUTPUT);

  pinMode(ButtonLeftPin,INPUT);
  pinMode(ButtonRightPin,INPUT);

  randomSeed(analogRead(0));
}

void loop(){
  unsigned long currentMillis = millis();
  int test = interval + (interval * loopNo);
  
  if((currentMillis - previousMillis <= interval) && (loopNo <= TotalLoops) &&(!NotRun)) {
    previousMillis = currentMillis;
    NotRun = true;
    rand_val = random(0,2);
    ButtonPressed = false;
    loopNo++;
    
    Serial.println(rand_val);
    Serial.println(loopNo);
    
    //Activate lights
   
    if(rand_val == 0) {
         digitalWrite(LEDLeftPin,HIGH);
         digitalWrite(LEDRightPin,LOW);
    }
    
    else if(rand_val == 1) {
          digitalWrite(LEDRightPin,HIGH);
          digitalWrite(LEDLeftPin,LOW);
      }      
  }
 
 //Delaying light
     
  //Buttons 0 is pressed and 1 us unpressed
  
  ButtonRightState = digitalRead(ButtonRightPin);
  ButtonLeftState = digitalRead(ButtonLeftPin);
 
 //Left button test   
    
  if((ButtonLeftState == 0) && (rand_val == 0) && (!ButtonPressed)){
    ButtonPressed = true;
    NotRun = false;
    CorrectAnswer++;
    Serial.println("Correct");
      }      
   else if(((ButtonRightState == 0) && (rand_val == 0) && (!ButtonPressed)) ||((ButtonLeftState == 0) && (rand_val == 1) && (!ButtonPressed))){
    ButtonPressed = true;
    NotRun = false;
    WrongAnswer++;
    Serial.println("Wrong");
      }
    
    if((currentMillis - previousMillis == interval) && (loopNo <= TotalLoops) && (!ButtonPressed)) {
      ButtonPressed = true;
      NotRun = false;
      Serial.println("LED not registered");
    }
 
 //to test whether user did not register LED. In time span(interval) if buttonstate = 0 && buttonpress = false.     
      
 //Correct percentage - when loop 10 runs, calculate percentage of correct answers
 
 if((!TestComplete) && ( currentMillis == 3000 + (TotalLoops +2) * interval)){
   TestComplete = true;
   Serial.println("Accuracy of %");
   Serial.print(CorrectAnswer);
 }
}

You still have ==

if((currentMillis - previousMillis == interval) && (loopNo <= TotalLoops) && (!ButtonPressed)) {
      ButtonPressed = true;
      NotRun = false;
      Serial.println("LED not registered");
    }

Make sure that you want <= or do you want >=

This milli timing thing is really doing my head in

The principle is easy.
Remember the time something started by saving the value of millis() at that point.
Every now and again, usually each time through the loop() function, compare the millis() value now with the millis() value when the timing started.
If it is greater than or equal to the required interval then take the necessary action.
If not then go away and do something else until the next check.

Using themillis() - timeStarted >= intervalform of code to do the test avoids problems with millis() rolling over to zero after 49 and a bit days

The demo several things at a time illustrates the use of millis() and may be helpful.

if((!TestComplete) && ( currentMillis == 3000 + (TotalLoops +2) * interval)){

This looks very strange. What are you trying to achieve.

If the value of currentMillis is derived from millis() it virtually certain that this will never be true. I would even be surprised if it works if you replace == with >= or <= as appropriate.

…R