1

I'm currently working on a traffic lights project with Arduino Uno. I'm supposed to switch between different modes when I press an external switch. There are 4 modes, mode 0: all leds are off, mode 1: red led blinks with 1 sec on 1 sec off, mode 2: yellow led blinks with 1 sec on 1 sec off, however in mode 3: I have potentiometer dependent delays. (up to 10 sec)

My question is that, how can I stop a mode immediately after I press the switch and change the mode without waiting the current mode to finish.

// Change the speed with delay using potentiometer,
#include <EEPROM.h>

short rPin = 4; // red led connected to D4
short yPin = 5; // yellow led connected to D5
short gPin = 6; // green led connected to D6
short switchPin = 3; // where the switch is connected

short potPin = 2; // input pin for the PM
short val = 0;    // variable to store the value coming from the PM

short timeOut = 300; // switch debounce noise handling,
volatile short last_change_time = 0;

static short dTime = 0; // Static Variable, that holds the last change, effects
                        // every function.
static short d = 0; // current d value.

static short mode = 0;

// EEPROM current address
int addr = 0;

void pressed() {
  int difference = millis()-last_change_time;
  if(difference > timeOut || last_change_time == 0)
  {
    if (mode >= 3){
    mode = 0;
      } 
    else {
      mode = mode + 1;
    }
  }
  else
  {
    //Serial.println("NO");
  }
  last_change_time = millis();
}

void setup()
{
  pinMode(rPin, OUTPUT);
  pinMode(yPin, OUTPUT);
  pinMode(gPin, OUTPUT);
  pinMode(switchPin, INPUT);
  Serial.begin(9600);
  attachInterrupt(1,pressed,FALLING); // digital pin 2 // pressed
}

void loop()
{
  if (mode == 3) mode3();  
  if (mode == 2) mode2();
  if (mode == 1) mode1();
  if (mode == 0) mode0();
  val = analogRead(potPin);
  if (val < 170) {
    d = 1;
  }
  else if ( (val >= 170) && (val < 340))
  {
    d = 2;
  }
  else if ((val >= 340)&&(val < 510))
  {
    d = 3;
  }
  else if ((val >= 510)&&(val < 680))
  {
    d = 4;
  }
  else if ((val >= 680) && (val < 850))
  {
    d = 5;
  }
  else if ((val >= 850) && (val < 1023))
  {
    d = 6;
  }
}


void serialEvent() {
  while (Serial.available()) {
  int value = Serial.parseInt();
  if (value == 1){
  Serial.print("d: ");
  Serial.print(d);
  Serial.print("  mode: ");
  Serial.print(mode);
  Serial.print("\n");
  }
}
}

void mode0() {
  while(mode == 0){
  digitalWrite(rPin, LOW);
  digitalWrite(yPin, LOW);
  digitalWrite(gPin, LOW);
  }
}

void mode1() {
  while(mode == 1){
  digitalWrite(yPin, LOW);
  digitalWrite(gPin, LOW);
  digitalWrite(rPin, HIGH);
  delay(1000);
  digitalWrite(rPin, LOW);
  delay(1000);
  }
}

void mode2() {
  while(mode == 2){
  digitalWrite(rPin, LOW);
  digitalWrite(gPin, LOW);
  digitalWrite(yPin, HIGH);
  delay(1000);
  digitalWrite(yPin, LOW);
  delay(1000);
  }
}


void mode3(){
  interrupts();
  while(mode == 3){
  digitalWrite(rPin, HIGH);
  delay(9*d*1000);
  digitalWrite(yPin, HIGH);
  delay(d*1000);
  digitalWrite(rPin, LOW);
  digitalWrite(yPin, LOW);
  digitalWrite(gPin, HIGH);
  delay(10*d*1000);
  digitalWrite(gPin, LOW);
  delay((d)*1000);
  digitalWrite(gPin, HIGH);
  delay(d*1000);
  digitalWrite(gPin, LOW);
  delay(d*1000);
  digitalWrite(yPin, HIGH);
  delay(d*1000);
  digitalWrite(yPin, LOW);
  }
}
2

1 Answer 1

0

Think about it: once you enter one of your "mode" loops you never check the status of the switch (pot) again. Make sense? The finite state machine suggestion is good but to keep it simple, just break out the code where you are checking the switch and setting the mode into its own function, then call it within each mode loop.

void mode0() {
  while(mode == 0){
  digitalWrite(rPin, LOW);
  digitalWrite(yPin, LOW);
  digitalWrite(gPin, LOW);

  checkSwitch(); // this will potentially change the 'mode' so the while loop with exit if the mode has changed.
  }
}

Update: Delay hack

Not really recommended but I suppose one way to use the delay approach and not lock out all interaction would be to break the delay down to a minimum and check for input in a for loop - something like:

void uglyDelayHack(int delayAmount, int lastMode){

 for (int i = 0; i < delayAmount; i++){

   delay(1); // 1 millisecond delay

   // call to a function that checks for input and changes mode 
   checkForInput(); 

   // get out of the fake delay if mode has changed
   // assumes "mode" is a global variable
   if (lastMode != mode) return;
 }
}
Sign up to request clarification or add additional context in comments.

5 Comments

however, I'm already able to change the mode, but I have to wait to end the delays within the mode function.Let's say, I pressed the switch when mode3 is running, my code is able to change the mode, "but" waiting to finish mode3. While loops are redundant there, I can delete while loops. So, do you have any suggestion on how to interrupt a mode immediately after I press the switch?
If you want more responsiveness, you can't use delay() as that is non-interruptable. You would need to come up with some simple FSM (as someone suggested earlier) to cycle through the various states you want to display, and manage your delay time by storing the milliseconds of the start of a state and comparing that to the current millis().
Thank you man, is this really work? I mean, could you please explain it with a simple code block? I will be really appreciated.
A FSM can be just a simple switch/case structure (or if/else). It will feel like a lot of work just to get simple blinky lights working correctly, etc. I'd suggest taking a pitstop from the project to read up a bit and actually do a diagram and a simple test sketch. See: mathertel.de/Arduino/FiniteStateMachine.aspx I suppose one way you could cheat: see my updated answer.
Thank you very much, I solved my problem with a simple FSM approach. It worked...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.