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
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);
}
}
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
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.