Traffic light pedestrian crossing help please.

Hi,

I have written a sketch for a traffic light pedestrian crossing which is working great. I want to add a feature that when the red man lights up I want to be able to press the button again from there. At the moment you cant press the button again until the traffic light goes to green. I have added a comment into the code where I want the button to become active again. Do I have to use millis or put another if, else statement in?

Please see code below.

//ASSIGNES LEDS TO PIN NUMBERS
#define buttonPin 2
#define greenMan 6
#define redMan 7
#define buzzPin 8
#define waitPin 9
#define redLight 11
#define amberLight 12
#define greenLight 13


//DELAY TIMES
int waitTime = 10000;
int getReadyToStop = 5000;
int roadClearPeriod = 2000;
int beepTime = 300;
int greenManFlash = 500;
int pedestrianClearPeriod = 6000;
int getReadyToGo = 3000;

//BEEPING TONE
int beepTone = 3000;
int beepDuration = 200;

int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

bool crossState;


void setup() {
  pinMode(redLight, OUTPUT);         //RED LED OF THE TRAFFIC LIGHTS
  pinMode(amberLight, OUTPUT);       //AMBER LED OF THE TRAFFIC LIGHTS
  pinMode(greenLight, OUTPUT);       //GREEN LED OF THE TRAFFIC LIGHTS
  pinMode(buttonPin, INPUT_PULLUP);  //PEDESTRIAN CROSS CALL BUTTON
  pinMode(greenMan, OUTPUT);         //GREEN MAN LED OF THE PEDESTRIAN CROSSING
  pinMode(redMan, OUTPUT);           //RED MAN LED OF THE PEDESTRIAN CROSSING
  pinMode(buzzPin, OUTPUT);          //CROSSING AUDIO BEEPING
  pinMode(waitPin, OUTPUT);          //WAIT LED OF THE PEDESTRIAN CROSSING

  digitalWrite(greenLight, HIGH);     //TURN ON THE GREEN LED OF THE TRAFFIC LIGHTS
  digitalWrite(redMan, HIGH);      //TURN ON THE RED MAN LED OF THE PEDESTRIAN CROSSING


  buttonState = digitalRead(buttonPin);
  lastButtonState = buttonState;
 


}

void loop() {

  // Read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  

  // Compare the buttonState to its previous state
  if (buttonState != lastButtonState) //Changed
  
  {
    if (buttonState == LOW) //New press, so change valve flag
    {
      crossState = !crossState;
  }
  lastButtonState = buttonState; // Save the current state as the last state, for next time through the loop

  }
  if (crossState) 
  {
    digitalWrite (waitPin, HIGH);      //TURN ON THE WAIT LED OF THE PEDESTRIAN CROSSING
    delay(waitTime);                   //DELAY AFTER PEDESTRIAN CROSS BUTTON PRESSED
    digitalWrite(greenLight, LOW);     //TURN OFF THE GREEN LED OF THE TRAFFIC LIGHTS
    digitalWrite(amberLight, HIGH);    //TURN ON AMBER LED OF THE TRAFFIC LIGHTS
    delay(getReadyToStop);             //DELAY TIME FOR THE AMBER LED
    digitalWrite(amberLight, LOW);     //TURN OFF AMBER LED OF THE TRAFFIC LIGHTS
    digitalWrite(redLight, HIGH);      //TURN ON RED LED OF THE TRAFFIC LIGHTS
    delay(roadClearPeriod);            //WAIT TO TURN ON THE GREEN MAN LED OF THE PEDESTRIAN CROSSING
    digitalWrite(redMan, LOW);         //TURN OFF THE RED MAN LED OF THE PEDESTRIAN CROSSING
    digitalWrite(greenMan, HIGH);      //TURN ON THE GREEN MAN LED OF THE PEDESTRIAN CROSSING
    digitalWrite(waitPin, LOW);

    //AUDIO TONE FOR CROSSING
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);
    tone(buzzPin, beepTone, beepDuration);
    delay(beepTime);

    //GREEN MAN FLASHING WARNING
    digitalWrite(greenMan, LOW);
    delay (greenManFlash);
    digitalWrite(greenMan, HIGH);
    delay (greenManFlash);
    digitalWrite(greenMan, LOW);
    delay (greenManFlash);
    digitalWrite(greenMan, HIGH);
    delay (greenManFlash);
    digitalWrite(greenMan, LOW);
    delay (greenManFlash);
    digitalWrite(greenMan, HIGH);
    delay (greenManFlash);
    digitalWrite(greenMan, LOW);
    delay (greenManFlash);
    digitalWrite(redMan, HIGH); //TURN ON THE RED MAN LED OF THE PEDESTRIAN CROSSING
      /*!!!!!!!!!!THIS IS THE POINT I WANT THE BUTTON TO BE ACTIVE AGAIN TO BE ABLE RUN ANOTHER BIT OF CODE
      IF THE BUTTON IS PRESSED!!!!!!!!!!.*/
    delay(pedestrianClearPeriod);

    //ALLOW TRAFFIC TO MOVE
    digitalWrite(redLight, HIGH); //TURN ON THE RED LED OF TRAFFIC LIGHT
    digitalWrite(amberLight, HIGH); //TURN ON THE AMBER LED OF THE TRAFFIC LIGHT
    delay(getReadyToGo);
    digitalWrite(greenLight, HIGH); //TURN ON THE GREEN LED OF THE TRAFFIC LIGHT
    digitalWrite(redLight, LOW);  //TURN OFF THE RED LED OF THE TRAFFIC LIGHT
    digitalWrite(amberLight, LOW);  //TURN OFF THE AMBER LED OF THE TRAFFIC LIGHT
     {
while (digitalRead(buttonPin) == HIGH);
  }

  }

  
}

Many Thanks,
Mike.

i think your trying to add a crosswalk button

you need to write your main look code using millis() so that it doesn't block allowing code to test for a button press

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

Thanks @Robin2, I shall go through this now.

Look thru this thread which covers traffic lights and crosswalk.

You may get some ideas from the discussion.

https://forum.arduino.cc/index.php?topic=685038.msg4607535#msg4607535

Looking at the below code from the link Robin2 provided. How would I get it so void blink() runs for 10 seconds then stops and then void fade() starts and runs for 10 seconds and stops?

I managed to get the code in my first post to almost run properly using millis but couldn't get each function to sequence one after the other. If I can get the below code to sequence one after the other, I can build from that.

unsigned long blinkStartMillis;
unsigned long fadeStartMillis ;
unsigned long currentMillis;
const unsigned long blinkPeriod = 1000;  //blink period
const unsigned long fadePeriod = 10;  //fade period
const byte blinkLedPin = 13;    //this LED will blink
const byte fadeLedPin = 11;    //this LED will fade
byte brightness = 0;  //initial brightness of LED
byte increment = 1;  //amount to change PWM value at each change


void setup()
{
  Serial.begin(115200);  //start Serial in case we need to print debugging info
  pinMode(blinkLedPin, OUTPUT);
  blinkStartMillis = millis();  //start time of blinking LED
  fadeStartMillis = millis();  //start time of fading LED
}

void loop()
{
  currentMillis = millis();  //get the current time

  blink();
  fade();
}

void blink()  //function to blink an LED if the blink period has ended
{
  if (currentMillis - blinkStartMillis >= blinkPeriod)  //test whether the period has elapsed
  {
    digitalWrite(blinkLedPin, !digitalRead(blinkLedPin));  //if so, change the state of the LED
    blinkStartMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.

  }
  
}

void fade()    //function to fade an LED
{

  
  if (currentMillis - fadeStartMillis >= fadePeriod)  //test whether the period has elapsed
  {
    analogWrite(fadeLedPin, brightness);    //set the brightness of the LED
    brightness += increment;    //will wrap round because brightness is an unsigned data type
    fadeStartMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }

}

s200bym:
I managed to get the code in my first post to almost run properly using millis but couldn't get each function to sequence one after the other.

That sounds like you didn't know how to implement a state machine.

I'll look it up now, thanks.

I am obviously doing something wrong here! I am trying to switch between Tone Without Delay and Blink Without Delay but that is not happening.

What I get is, when I start the sketch nothing happens, I press the button and I get a constant tone and solid led (not flashing). I press the button again and nothing happens, it just stays the same.

Have I got a confliction somewhere?

//ASSIGNES LEDS TO PIN NUMBERS
#define buttonPin 2
#define greenMan 6
#define tonePin 8


unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
int toneInterval = 100;
int toneHz = 3000;
int toneDuration = 200;

boolean outputTone = false; // Records current state



int ledState = LOW;
int interval = 300;


int state = 0;
int old = 0;
int buttonPoll = 0;



void setup() {
  // put your setup code here, to run once:
  pinMode (tonePin, OUTPUT);
  pinMode (greenMan, OUTPUT);
  pinMode (buttonPin, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:


  buttonPoll = digitalRead(buttonPin);
  if (buttonPoll == 0) {
delay(20);
    buttonPoll = digitalRead(buttonPin);
    if (buttonPoll == 0) {
      state = old + 1;
    }
  }
  else {

delay(100);

  }



  switch (state) {


    case 1: {

        unsigned long currentMillis = millis();


        if (outputTone) {

          if (currentMillis - previousMillis >= toneDuration) {
            previousMillis = currentMillis;
            noTone(tonePin);
            outputTone = false;
          }
        } else {

          if (currentMillis - previousMillis >= toneInterval) {
            previousMillis = currentMillis;
            tone(tonePin, toneHz);
            outputTone = true;
            old = state;
            break;
          }

        }
      }



    case 2: {

        unsigned long currentMillis = millis();


        if (currentMillis - previousMillis >= interval) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;

          // if the LED is off turn it on and vice-versa:
          if (ledState == LOW) {
            ledState = HIGH;
          } else {
            ledState = LOW;
          }

          // set the LED with the ledState of the variable:
          digitalWrite(greenMan, ledState);
          old = state;
          break;

        }

      }
  }

}

No sketch "without delay" can ever use delay(). Already, your button switch input routine delays 100ms every single time through loop() because you have 'else {delay(100)} in there. You have to remove all the delay() calls. You can't just add millis() and expect it to work.

Also your state variable is incremented forever, there is nothing that I can see to limit it to 1 or 2, the only cases you handle. Normally, state changes are made with an assignment to 'state'. It's initialized to zero also, which is very confusing as there is no case "0". You have a strange auxiliary variable called 'old' and it's far from clear what it does. There is no inline documentation to indicate what a state of 1 or 2 even means. Normally you would use an enum constant to give it a human readable name. Failing that, you can at least use a regular constant so it can have a name.