Traffic lights - from very simple to "how complicated do you want?"

Hello World!

Well I have recently started learning with the Arduino. I think its brilliant!
I have done the blinking LEDs and other simple examples, which were really useful.
I believe the best way to learn it to experiment.
So here is me learning about going from simple to complex using the example of the humble traffic light.

Version 1 a single set of traffic lights that go.
Red
Red & Amber
Green
Amber
Red
and repeats ad infinitum.

After that I will complicate them by imagining ever more complex road junctions, crossings, car sensors, different sequences for rush hour etc.

Come with me, it should be fun. If I get stuck, or write rubbish sketches, feel free to jump in!

Traffic Lights 1

red LED & Resistor to digital pin 13
amber LED & Resistor to digital pin 12
green LED & Resistor to digital pin 11

/*
*Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 *A set of Traffic Lights.
 *I am in the UK so it will be a UK set of traffic lights.
 *Should be easy to customise to any configuration in the world!
 *Come with me, it should be fun. 
 *I intend to  comment every line to start with
 *so it should be easy to follow.
 
 */

int red = 13;   //first of all associate a pin with the red light, in this case 13
int amber = 12; // associate pin 12 with the amber light
int green = 11; //and finally the green light with pin 11

int maindelay = 1500; //The timings of the lights are based around this number.
/*
 *The maindelay is an arbitary delay time, 
 *smaller is faster, larger is slower. 
 *I use it so the proportions stay the same. 
 *i.e. the wait is 4 times longer than the change
 */

void setup() {
  pinMode(red,OUTPUT);   //set the red pin as an output
  pinMode(amber,OUTPUT); //set the amber pin as an output
  pinMode(green,OUTPUT); //set the green pin as an output

  digitalWrite(red,HIGH); //Switch the red light on so we have something to start with
}

void loop(){

  digitalWrite(amber,HIGH); //Amber on, get ready to go
  delay(maindelay); //Wait 
  digitalWrite(green,HIGH); //Green on, go
  digitalWrite(red,LOW);    //Red off as green is on
  digitalWrite(amber,LOW);  //amber off, it's finished with
  delay(maindelay*4);       //give traffic time to pass
  digitalWrite(amber,HIGH); //amber on, stop if safe to do so
  digitalWrite(green,LOW);   //green off, it's finished with
  delay(maindelay);          //wait
  digitalWrite(amber,LOW);   //amber off
  digitalWrite(red,HIGH);    //red on, stop
  delay(maindelay*4);        //Time for whatever the traffic has been stopped for to happen.
  
  /*And we are back where we started. 
   *That's the end of this sequence. 
   *The light is back at red and the 
   *sequence can begin again.
   */
}

Well. I hope it works for you. I'll be back in a few days with another set of lights. I am thinking of a crossroads where North-South goes while East-West waits, and vice versa.

See you soon

Bookworm.

OK.

Part two. I have added a second set of traffic lights. As you might find at a crossroads or where two way traffic has to pass through a single lane (Such as an old hump back bridge).

I have added LEDs and resistors to pins 11(Green), 10(amber) and 9(red).

I have named the signals "north" and "east". I forsee there may be south and west signals at some point.
I have also created functions to turn each signal from red to green and vice versa. that's so the loop can call them as it needs them and I can call upon them in any sequence I need. They are no longer in a fixed order.

For now the controller starts up with both signals at red.
It then changes the north signal to green, waits a while and turns it back to red.
Then it does the same with the east signal.
The loop continues.

/*
 *A set of Traffic Lights.
 *I am in the UK so it will be a UK set of traffic lights.
 *Should be easy to customise to any configuration in the world!
 *Come with me, it should be fun. 
 *I intend to  comment every line to start with
 *so it should be easy to follow.
 
 */

int northRed = 13;   //first of all associate a pin number with the  Northern red light, in this case 13
int northAmber = 12; // associate pin 12 with the amber light
int northGreen = 11; //and finally the green light with pin 11

int eastRed = 8;  //a pin for the east red light, 8
int eastAmber = 9;  //a pin for the east amber light , 9
int eastGreen = 10;  //a pin for the east green light, 10

int maindelay = 1500; //The timings of the lights are based around this number.
/*
 *The maindelay is an arbitary delay time, 
 *smaller is faster, larger is slower. 
 *I use it so the proportions stay the same. 
 *i.e. the wait is 4 times longer than the change
 */

void setup() {
  pinMode(northRed,OUTPUT);   //set the north red pin as an output
  pinMode(northAmber,OUTPUT); //set the north amber pin as an output
  pinMode(northGreen,OUTPUT); //set the north green pin as an output
  pinMode(eastRed,OUTPUT);   //set the east red pin as an output
  pinMode(eastAmber,OUTPUT); //set the east amber pin as an output
  pinMode(eastGreen,OUTPUT); //set the east green pin as an output

  digitalWrite(northRed,HIGH); //Switch the red light on so we have something to start with
  digitalWrite(eastRed,HIGH); //switch the east red light on as well
}

void loop(){
  northtogreen();  //change the north signal to green
  delay(maindelay*4);  //wait for the traffic to pass
  northtored();  //change the north signal back to red
  delay(maindelay/2);  //small delay to allow traffic to clear junction
  easttogreen();  //change the east signal to green
  delay(maindelay*4);//wait for the traffic to pass
  easttored();  //change the east signal back to red
  delay(maindelay/2);  //small delay to allow the traffic to clear junction


  /*And we are back where we started. 
   *That's the end of this sequence. 
   *The light is back at red and the 
   *sequence can begin again.
   */
}

void northtored(){  //sequence of north lights going to red

    digitalWrite(northAmber,HIGH);  //Amber on, prepare to stop
  digitalWrite(northGreen,LOW);  //Green off, finished with
  delay(maindelay);              //Time for traffic to stop
  digitalWrite(northRed,HIGH);  //Red on, stop
  digitalWrite(northAmber,LOW);  //Amber off, finished with
}

void northtogreen(){  //sequence of north lights going to green

    digitalWrite(northAmber,HIGH);  //Amber on, prepare to go
  delay(maindelay);  //Time for traffic to see amber
  digitalWrite(northGreen,HIGH);  //green on, go
  digitalWrite(northRed,LOW);  //red off, finished with
  digitalWrite(northAmber,LOW);  //amber off, finished with
}

void easttored(){//sequence of east lights going to red

    digitalWrite(eastAmber,HIGH);  //Amber on, prepare to stop
  digitalWrite(eastGreen,LOW);  //Green off, finished with
  delay(maindelay);              //Time for traffic to stop
  digitalWrite(eastRed,HIGH);  //Red on, stop
  digitalWrite(eastAmber,LOW);  //Amber off, finished with

}

void easttogreen(){ //sequence of east lights going to green

    digitalWrite(eastAmber,HIGH);  //Amber on, prepare to go
  delay(maindelay);  //Time for traffic to see amber
  digitalWrite(eastGreen,HIGH);  //green on, go
  digitalWrite(eastRed,LOW);  //red off, finished with
  digitalWrite(eastAmber,LOW);  //amber off, finished with

}
/*
*Version History
 *
 * 1.2 Two traffic lights on opposite phases 
 *  -moved licence to bottom of sketch 
 *  -added version history
 *  -moved code to change lights out of the loop and into their own functions
 *
 * 1.1 Single Traffic Light
 *
 *Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 */

Now I can see that I have two pairs of functions that are very similar. Next stage will be to get rid of the duplication.

i.e.
Instead of northtored() and easttored() it needs a single function changetored() and send it "North" and it will change the north light to red, send it "east" and it will change the east light to red.

Not sure how to do that at the moment. I have a feeling the individual lights will have to be stored in arrays, each one being a whole set of lights.

Bear with me, or have a go yourself.

See you soon.

Well I'm glad I am doing this while the system is quite simple. Hopefully getting it sorted now will save having to rewrite masses of code.

I have written a small sketch using a 2 Dimentional array (Colours x Signal) to assign each output pin.

/*
* small sketch to try out 2 dimentional array
* in order to address individual signals and their
* respective lights.
*
* In this case each signal (Set of red,amber and green lights) is
* a row in the array "signal" and each column is either red, amber or green.
* I have 2 sets of signals which will be "north"(output pins 13,12 & 11)
* and "east" (Output pins 8,9 & 10).
*/


const int red = 0; //first column in array signal is red 
const int amber = 1;//second column in array signal is amber
const int green = 2;//third column in array signal is green
const int totalcolours = 3; //there are red, amber and green
const int north = 0; //first row in array signal is north
const int east = 1; // second row in array signal is east
const int totalsignals = 2; //at the moment there are two sets of signals
const int signal[totalsignals][totalcolours] ={    { 13,12,11  },
                                                                {  8, 9,10  }  }; // traffic lights array. 
//columns are red, amber, green
//rows are individual signals.

void setup() {

  for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    for (int j = 0; j < totalcolours; j++) { //cycle through the colours
      pinMode(signal[i][j],OUTPUT); //set the pins as outputs
    }
  }
}


void loop() {

for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    for (int j = 0; j < totalcolours; j++) { //cycle through the colours
      digitalWrite(signal[i][j],HIGH); //Switch a light on
      delay(250); //wait
      digitalWrite(signal[i][j],LOW);//switch that light off
      delay(100);//wait
    }
  }
}

/*
 *Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 */

The sketch slowly blinks each LED in turn.

Now I can

digitalWrite(signal[signal ID] [colour],HIGH or LOW);

to switch an individual LED on or off.

Next thing to do is to test that out thoroughly and transfer it into the main traffic lights sketch.

As always, bear with me or have a go yourself. If you do, let us know how you are getting on.

It works!!

It turned out easier to copy some of the traffic light sketch into the array sketch. So that's what I did.

It now appears to do exactly the same thing as before, turning north to green, then to red, then east to green and then red.

/*
 *A set of Traffic Lights.
 *I am in the UK so it will be a UK set of traffic lights.
 *Should be easy to customise to any configuration in the world!
 *Come with me, it should be fun. 
 *I intend to  comment every line to start with
 *so it should be easy to follow.
 
 */

const int maindelay = 1000;  //the tempo of the lights are based around 
//this delay. smaller = faster, larger=slower. The rhythm should  stay the same.
const int red = 0; //first column in array signal is red 
const int amber = 1;//second column in array signal is amber
const int green = 2;//third column in array signal is green
const int totalcolours = 3; //there are red, amber and green
const int north = 0; //first row in array signal is north
const int east = 1; // second row in array signal is east
const int totalsignals = 2; //at the moment there are two sets of signals
const int signal[totalsignals][totalcolours] ={    
  { 
    13,12,11    }
  ,
  {  
    8, 9,10    }  
}; // traffic lights array. 
//columns are red, amber, green
//rows are individual signals.

void setup() {

  for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    for (int j = 0; j < totalcolours; j++) { //cycle through the colours
      pinMode(signal[i][j],OUTPUT); //set the pins as outputs
    }
  }
  for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    digitalWrite(signal[i][red],HIGH); //light all the red lights
  }

}


void loop() {
  for (int signalID = 0; signalID < totalsignals; signalID++) { //cycle through the signals
    settogreen(signalID); //turn the signal called signalID to green
    delay(maindelay*2); //wait for traffic to flow
    settored(signalID);  //turn the lights back to red
    delay(maindelay);    //wait for traffic to clear
  }


}

void settogreen(int i){ //function to set a signal to green 
  digitalWrite(signal[i][amber],HIGH); //light the amber light
  delay(maindelay);//pause
  digitalWrite(signal[i][green],HIGH);//light the green light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light
  digitalWrite(signal[i][red],LOW);//extingish the red light
}

void settored(int i){//function to set a signal to red
  digitalWrite(signal[i][amber],HIGH);//light the amber light
  digitalWrite(signal[i][green],LOW);//extinguish the green light
  delay(maindelay);//pause
  digitalWrite(signal[i][red],HIGH);//light the red light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light

}


/*
*Version History
 *2.0 Two traffic lights on opposite phases
 *  - Each light can now be called by it's own address "signal[signalID][colour]"
 *  - rewrite loop to reflect new addresses
 *  - deleted duplicated functions
 *
 * 1.2 Two traffic lights on opposite phases 
 *  -moved licence to bottom of sketch 
 *  -added version history
 *  -moved code to change lights out of the loop and into their own functions
 *
 * 1.1 Single Traffic Light
 *
 *Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 */

It's also smaller (1932 bytes) than the original version of the sketch (2102 bytes).

Adding a new set of lights is as easy as

  • adding 1 to totalsignals
  • adding the pin numbers as an extra row
  • declaring a new signal, e.g. south and giving it the value 2

Then the sketch cycles all three sets of signals. You can add as many sets of lights as you like (until you run out of output pins).

I added a new signal "south" to pins 5 (Red), 6(amber) and 7(green).

here are the extra variable declarations and the new line in the array

const int south = 2; //south is the third row in the array.
const int totalsignals = 3; //now there are 3 sets of signals
const int signal[totalsignals][totalcolours] ={    
  { 13,12,11    },//the output pins for north
  {  8, 9,10    },//the output pins for east
  {  5, 6, 7    } //the new output pins for south
}; // traffic lights array. 
//columns are red, amber, green
//rows are individual signals.

I don't know why but after adding the third signal the sketch is even smaller(1924 bytes).

Not sure what to try next. maybe a button for pedestrians to request to cross plus the associated red and green man signal.

Bear with, or have a go. Let me know how you get on.

Bookworm.

Well. I haven't added a button yet.

I had a look at the loop and all I had put in there was a for() loop. It doesn't need that because, well, it is a loop anyway and it makes breaking into the sequence problematical. Any change would have to affect all the signals or wait until a complete cycle had finished.

So I have removed the for() loop.

I think it may be useful to have the arduino report back to the PC what is happening for debugging. So I have opened the serial port and each function sends a line of info when it is called.

/*
 *A set of Traffic Lights.
 *I am in the UK so it will be a UK set of traffic lights.
 *Should be easy to customise to any configuration in the world!
 *Come with me, it should be fun. 
 *I intend to  comment every line to start with
 *so it should be easy to follow.
 
 */

const int maindelay = 1000;  //the tempo of the lights are based around 
//this delay. smaller = faster, larger=slower. The rhythm should  stay the same.
const byte red = 0; //first column in array signal is red 
const byte amber = 1;//second column in array signal is amber
const byte green = 2;//third column in array signal is green
const byte totalcolours = 3; //there are red, amber and green
const byte north = 0; //first row in array signal is north
const byte east = 1; // second row in array signal is east
const byte totalsignals = 2; //at the moment there are two sets of signals
const int signal[totalsignals][totalcolours] ={    
  { 
    13,12,11      }
  ,
  {  
    8, 9,10      }
}; // traffic lights array. 
//columns are red, amber, green
//rows are individual signals.
byte signalID = 0; // the number of the "active" signal


void setup() {
  Serial.begin(9600); //opens the serial port and sets the baud at 9600
  for (byte i = 0; i < totalsignals; i++) { //cycle through the signals
    for (byte j = 0; j < totalcolours; j++) { //cycle through the colours
      pinMode(signal[i][j],OUTPUT); //set the pins as outputs
      Serial.print("setting pin ");
      Serial.print( signal[i][j]);
      Serial.println(" as output");//tell pc what is happening
    }
  }
  for (byte i = 0; i < totalsignals; i++) { //cycle through the signals
    digitalWrite(signal[i][red],HIGH); //light all the red lights
    Serial.print("setting signal ");
    Serial.print( i);
    Serial.println( " to red");// tell pc what is happening
  }

}


void loop() {

  if(signalID < totalsignals) {//make sure a valid signal is the active one.
    settogreen(signalID); //turn the signal called signalID to green
    delay(maindelay*2); //wait for traffic to flow
    settored(signalID);  //turn the lights back to red
    delay(maindelay);    //wait for traffic to clear
    signalID++; //cycle through the signals
  }
  else
  {
    signalID=0;//after cycling through all the signals set back to the first
  }



}

void settogreen(byte i){ //function to set a signal to green 
  Serial.print("Changing signal ");
  Serial.print(i);
  Serial.println(" to green");//tell pc what is happening
  digitalWrite(signal[i][amber],HIGH); //light the amber light
  delay(maindelay);//pause
  digitalWrite(signal[i][green],HIGH);//light the green light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light
  digitalWrite(signal[i][red],LOW);//extingish the red light
}

void settored(byte i){//function to set a signal to red
  Serial.print("Changing signal ");
  Serial.print(i);
  Serial.println(" to red");//tell pc what is happening
  digitalWrite(signal[i][amber],HIGH);//light the amber light
  digitalWrite(signal[i][green],LOW);//extinguish the green light
  delay(maindelay);//pause
  digitalWrite(signal[i][red],HIGH);//light the red light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light

}


/*
*Version History
 * 2.1.1 
 *  - took redundant for() loop out of void loop()
 *  - Opened the serial port and added debugging information feed from each function.
 * 2.1
 *  - changed variable type from INT to BYTE where the value will always be
 in the range 0 - 255 made sketch slightly smaller
 *2.0 Two traffic lights on opposite phases
 *  - Each light can now be called by it's own address "signal[signalID][colour]"
 *  - rewrite loop to reflect new addresses
 *  - deleted duplicated functions
 *
 * 1.2 Two traffic lights on opposite phases 
 *  -moved licence to bottom of sketch 
 *  -added version history
 *  -moved code to change lights out of the loop and into their own functions
 *
 * 1.1 Single Traffic Light
 *
 *Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 */

I do intend to add the pedestrian crossing request button next, unless you want to!

Let me know if you are finding this any use at all. I'll keep on writing and posting so I hope someone is.

Bookworm.

Great code. I will study your code and adapt the code for a traffic light system in the city I live : Toronto, ON, Canada.

I wonder in the UK it have an advance green ? for turning left <-- America ... ops... I mean : turning right <-- UK.

Now all you need do is add some sensors under each light so that when there is no bloody traffic comming the lights change back . none of this wait for hours shite

My wish for version 3.0:
Use millis() instead a delay.

I dont know if this works but I have made a stripboard with three sets of lights on and put a video of it on youtube. (Looks like it does in preview, fingers crossed).

Traffic sensing will be added to the sketch. There is no need to show a direction a green light if there is no traffic waiting after all.
Will have to scan all the signal's sensors each cycle and turn one with waiting traffic to green but without favouring the first signal every time, which I think could happen.

I haven't used millis() yet. Looks to be good as the delay between each light lighting, going out etc. makes the Arduino "Blind" to other events.

Advanced green will have to go in there too. If it's what I think it is we call it a filter arrow, so you will probably see reference to that.

Still haven't done the pedestrian crossing request and lights yet. That will probably be next. I used the time to do the stripboard signals.

Bear with me, or jump in and have a go.

Bookworm.

Well I added a button to pin 2 (Interrupt 0), a red led to pins 14 & 16 and a green to 15. That's my pedestrian controller. a button to request a crossing, a WAIT light to acknowledge the button press.
Then, when all the signals are at red the pedestrian gets a green light, crosses, the green flashes 5 times and then the ordinary cycle begins again.

I have added an interrupt for the button press. Pin2 is the input and is set high so the pull up is activated.

When the interrupt happens a function is called that sets a volatile variable (crossRequest) to 1, lights the WAIT light and sends a line to the serial monitor.

Then, when all the signals are at red the variable is tested and, if 1, calls a function to let the pedestrian cross and set the variable back to 0.

/*
 *A set of Traffic Lights.
 *I am in the UK so it will be a UK set of traffic lights.
 *Should be easy to customise to any configuration in the world!
 *Come with me, it should be fun. 
 *I intend to  comment every line to start with
 *so it should be easy to follow.
 
 */
//Global Variables and constants
const int maindelay = 1000;  //the tempo of the lights are based around this delay. smaller = faster, larger=slower. 
//The rhythm should  stay the same.

//Traffic signal variables and constants
const byte red = 0; //first column in array signal is red 
const byte amber = 1;//second column in array signal is amber
const byte green = 2;//third column in array signal is green
const byte totalcolours = 3; //there are red, amber and green
const byte north = 0; //first row in array signal is north
const byte east = 1; // second row in array signal is east
const byte totalsignals = 2; //at the moment there are two sets of signals
const int signal[totalsignals][totalcolours] ={    
  { 5, 6, 7},
  { 8, 9,10}
  }; // traffic lights array. 
//columns are red, amber, green
//rows are individual signals.
byte signalID = 0; // the number of the "active" signal

//pedestrian variables and constants
volatile byte crossRequest = 0;// The state of the crossing request button. to begin with it's low as it's not been requested.
const byte pedButton = 2;//the pedestrian cross request is on pin 2 (interrupt 0)
const byte pedWait = 16;//the pedestrian WAIT signal is on pin 16
const byte pedStop = 14;// the pedestrian STOP signal is on pin 14 (DONT WALK)
const byte pedGo = 15;// The pedestrian GO signal is on pin 15 (WALK)



void setup() {
  //set up serial output
  Serial.begin(9600); //opens the serial port and sets the baud at 9600
  
  // set up the signals
  for (byte i = 0; i < totalsignals; i++) { //cycle through the signals
    for (byte j = 0; j < totalcolours; j++) { //cycle through the colours
      pinMode(signal[i][j],OUTPUT); //set the pins as outputs
      Serial.print("setting pin ");
      Serial.print( signal[i][j]);
      Serial.println(" as output");//tell pc what is happening
    }
  }
  
  //set the signals to an initial state
  for (byte i = 0; i < totalsignals; i++) { //cycle through the signals
    digitalWrite(signal[i][red],HIGH); //light all the red lights
    Serial.print("setting signal ");
    Serial.print( i);
    Serial.println( " to red");// tell pc what is happening
  }
  
  //set up the pedestrian button and signal
  Serial.println("setting up the pedestrian crossing");
  pinMode(pedButton,INPUT); //set the pedestrian button as an input
  digitalWrite(pedButton, HIGH); //turn on the pull up resistor on the button to stop it floating
  pinMode(pedWait,OUTPUT);// Set the pedestrian WAIT signal as an output
  pinMode(pedStop,OUTPUT);//Set the pedestrian STOP signal as an output
  pinMode(pedGo,OUTPUT);//Set the pedestrian GO signal as an output
  digitalWrite(pedStop, HIGH);// set the pedestrian STOP light to an initial state
  
  
  attachInterrupt(0, pedestrianButton, CHANGE);// when a pedestrian presses the button,
//interrrupt what is happening and run the pedestrianButton function
  
}


void loop() {

  if(signalID < totalsignals) {//make sure a valid signal is the active one.
    settogreen(signalID); //turn the signal called signalID to green
    delay(maindelay*2); //wait for traffic to flow
    settored(signalID);  //turn the lights back to red
    delay(maindelay);    //wait for traffic to clear
    if(crossRequest ==1){//see if the pedestrian button has been pressed
  pedcross();//if it has, go to the pedestrian crossing function
  }
    signalID++; //cycle through the signals
  }
  else
  {
    signalID=0;//after cycling through all the signals set back to the first
  }



}

void settogreen(byte i){ //function to set a signal to green 
  Serial.print("Changing signal ");
  Serial.print(i);
  Serial.println(" to green");//tell pc what is happening
  digitalWrite(signal[i][amber],HIGH); //light the amber light
  delay(maindelay);//pause
  digitalWrite(signal[i][green],HIGH);//light the green light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light
  digitalWrite(signal[i][red],LOW);//extingish the red light
}

void settored(byte i){//function to set a signal to red
  Serial.print("Changing signal ");
  Serial.print(i);
  Serial.println(" to red");//tell pc what is happening
  digitalWrite(signal[i][amber],HIGH);//light the amber light
  digitalWrite(signal[i][green],LOW);//extinguish the green light
  delay(maindelay);//pause
  digitalWrite(signal[i][red],HIGH);//light the red light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light

}

void pedestrianButton(){//function for when pedestrian button is pressed
  crossRequest = 1;// now there is a request to cross 
  Serial.println( "Pedestrian request to cross received");// tell pc what is happening
  digitalWrite(pedWait,HIGH);// light the WAIT to acknowledge the button press. 
}

void pedcross(){// pedestrian crossing function
  Serial.println( "Pedestrian crossing start");// tell pc what is happening
  delay(maindelay);//pause for traffic to clear
  Serial.println( "Pedestrian may cross");// tell pc what is happening
  digitalWrite(pedWait, LOW);//switch off the WAIT light
  digitalWrite(pedStop, LOW);//switch off the STOP light
  digitalWrite(pedGo, HIGH);//Switch on the GO light
  delay(maindelay*2);//pause for pedestrians to cross
  Serial.println( "Pedestrian time is up, flashing green man");// tell pc what is happening
  for (int i=1; i<6; i++){//run the next code 5 times to flash the green man (GO signal)
  digitalWrite(pedGo,LOW);//Switch GO light off
  delay(200);//Pause
  digitalWrite(pedGo,HIGH);//Switch GO light n
  delay(200);//Pause
}
  digitalWrite(pedGo, LOW);//Switch GO light off
  digitalWrite(pedStop, HIGH);// Switch WAIT light on
  Serial.println( "Pedestrian must stop");// tell pc what is happening
  delay(maindelay);// wait for pedestrians to clear crossing
  crossRequest = 0;// clear the pedestrian crossing request
}
/*
*Version History
 * 2.1.2
 *  - Added an interrupt button to pin 2 (Interrupt 0) as a pedestrian crossing request
 *  - Added a WAIT signal on pin 16 (pedWait)
 *  - Added a STOP signal on pin 14 (pedStop)
 *  - Added a GO signal on pin 15 (pedGo)
 *  - Added an interrupt to sense a pedestrian requesting to cross.
 *  - Added a function to allow a pedestrian to cross
 * 2.1.1 
 *  - took redundant for() loop out of void loop()
 *  - Opened the serial port and added debugging information feed from each function.
 * 2.1
 *  - changed variable type from INT to BYTE where the value will always be
 in the range 0 - 255 made sketch slightly smaller
 *2.0 Two traffic lights on opposite phases
 *  - Each light can now be called by it's own address "signal[signalID][colour]"
 *  - rewrite loop to reflect new addresses
 *  - deleted duplicated functions
 *
 * 1.2 Two traffic lights on opposite phases 
 *  -moved licence to bottom of sketch 
 *  -added version history
 *  -moved code to change lights out of the loop and into their own functions
 *
 * 1.1 Single Traffic Light
 *
 *Do what you like with this code as long as you set
 *it free and allow others to do the same. i.e.
 -------------------------------------------------
 *This work is licensed under the Creative Commons 
 *Attribution-ShareAlike 3.0 Unported License. 
 *To view a copy of this license, visit
 *http://creativecommons.org/licenses/by-sa/3.0/ 
 *or send a letter to Creative Commons, 444 Castro Street, 
 *Suite 900, Mountain View, California, 94041, USA.
 ----------------------------------------
 */

I don't know why yet but occasionally a crossing request causes the whole thing to hang. Problem is it's intermittent so I'm having trouble tracking it down. Any Ideas?

I'm still working on it.

Bookworm.

Found on another topic elsewhere.

cut
...if you call Serial.println in you interrupt handler. This may or may not work but often this is a call for doom.
paste

I commented out the Serial.println and recompiled and it runs fine.

Good to know, serial prints put in to aid debugging can be a bug.

Don't know why though. anyone point me at a topic that explains it?

Thanks

Bookworm

Bookworm:
It works!!

It turned out easier to copy some of the traffic light sketch into the array sketch. So that's what I did.

It now appears to do exactly the same thing as before, turning north to green, then to red, then east to green and then red.

/*

*A set of Traffic Lights.
*I am in the UK so it will be a UK set of traffic lights.
*Should be easy to customise to any configuration in the world!
*Come with me, it should be fun.
*I intend to  comment every line to start with
*so it should be easy to follow.

*/

const int maindelay = 1000;  //the tempo of the lights are based around
//this delay. smaller = faster, larger=slower. The rhythm should  stay the same.
const int red = 0; //first column in array signal is red
const int amber = 1;//second column in array signal is amber
const int green = 2;//third column in array signal is green
const int totalcolours = 3; //there are red, amber and green
const int north = 0; //first row in array signal is north
const int east = 1; // second row in array signal is east
const int totalsignals = 2; //at the moment there are two sets of signals
const int signal[totalsignals][totalcolours] ={   
  {
    13,12,11    }
  ,
  { 
    8, 9,10    } 
}; // traffic lights array.
//columns are red, amber, green
//rows are individual signals.

void setup() {

for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    for (int j = 0; j < totalcolours; j++) { //cycle through the colours
      pinMode(signal[i][j],OUTPUT); //set the pins as outputs
    }
  }
  for (int i = 0; i < totalsignals; i++) { //cycle through the signals
    digitalWrite(signal[i][red],HIGH); //light all the red lights
  }

}

void loop() {
  for (int signalID = 0; signalID < totalsignals; signalID++) { //cycle through the signals
    settogreen(signalID); //turn the signal called signalID to green
    delay(maindelay*2); //wait for traffic to flow
    settored(signalID);  //turn the lights back to red
    delay(maindelay);    //wait for traffic to clear
  }

}

void settogreen(int i){ //function to set a signal to green
  digitalWrite(signal[i][amber],HIGH); //light the amber light
  delay(maindelay);//pause
  digitalWrite(signal[i][green],HIGH);//light the green light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light
  digitalWrite(signal[i][red],LOW);//extingish the red light
}

void settored(int i){//function to set a signal to red
  digitalWrite(signal[i][amber],HIGH);//light the amber light
  digitalWrite(signal[i][green],LOW);//extinguish the green light
  delay(maindelay);//pause
  digitalWrite(signal[i][red],HIGH);//light the red light
  digitalWrite(signal[i][amber],LOW);//extinguish the amber light

}

/*
*Version History
*2.0 Two traffic lights on opposite phases
*  - Each light can now be called by it's own address "signal[signalID][colour]"
*  - rewrite loop to reflect new addresses
*  - deleted duplicated functions
*

  • 1.2 Two traffic lights on opposite phases
    *  -moved licence to bottom of sketch
    *  -added version history
    *  -moved code to change lights out of the loop and into their own functions
  • 1.1 Single Traffic Light

*Do what you like with this code as long as you set
*it free and allow others to do the same. i.e.

*This work is licensed under the Creative Commons
*Attribution-ShareAlike 3.0 Unported License.
*To view a copy of this license, visit
*CC BY-SA 3.0 Deed | Attribution-ShareAlike 3.0 Unported | Creative Commons
*or send a letter to Creative Commons, 444 Castro Street,
*Suite 900, Mountain View, California, 94041, USA.

*/




It's also smaller (1932 bytes) than the original version of the sketch (2102 bytes). 

Adding a new set of lights is as easy as 

- adding 1 to totalsignals 
- adding the pin numbers as an extra row 
- declaring a new signal, e.g. south and giving it the value 2


Then the sketch cycles all three sets of signals. You can add as many sets of lights as you like (until you run out of output pins).

I added a new signal "south" to pins 5 (Red), 6(amber) and 7(green).

here are the extra variable declarations and the new line in the array



const int south = 2; //south is the third row in the array.
const int totalsignals = 3; //now there are 3 sets of signals
const int signal[totalsignals][totalcolours] ={   
  { 13,12,11    },//the output pins for north
  {  8, 9,10    },//the output pins for east
  {  5, 6, 7    } //the new output pins for south
}; // traffic lights array.
//columns are red, amber, green
//rows are individual signals.




I don't know why but after adding the third signal the sketch is even smaller(1924 bytes).


Not sure what to try next. maybe a button for pedestrians to request to cross plus the associated red and green man signal.

Bear with, or have a go. Let me know how you get on.

Bookworm.
  1. I would like to use an adaption this for a 3-way intersection i'm working on for my dissertation. So is the extra variable declarations and the new line in the array all I need for it to work fine?
  2. Does signalID in the code call for a specific value or should just be left as signalID
  3. Is it possible to create different sequences for rush hour?

Thanks,
Kay.

Kerduino:
2. Does signalID in the code call for a specific value or should just be left as signalID

signalID is passed to the settored/green functions to set the value of the first subscript of the signal array. This means that when signalID is 0 the first traffic light will be controlled(in the example this is north). So the code:

  for (int signalID = 0; signalID < totalsignals; signalID++) { //cycle through the signals
    settogreen(signalID); //turn the signal called signalID to green
    delay(maindelay*2); //wait for traffic to flow
    settored(signalID);  //turn the lights back to red
    delay(maindelay);    //wait for traffic to clear
  }

does just what the comment says. It will first set the north traffic light to amber, then green, then amber, then red. Next it will repeat this process with the east traffic light, then the south traffic light, then repeats.

You should read https://www.arduino.cc/en/Reference/For

Kerduino:
3. Is it possible to create different sequences for rush hour?

Of course, have at it! You can set a different delay between light changes or whatever you like.