Pinterest Stumbleupon Whatsapp
Advertisement

The traffic light is a fun little project, that can be completed in under an hour. Learn how to build your own – using an Arduino – and how to modify the circuit for an advanced model.

Don’t worry if you’ve never used an Arduino before, we have a beginners guide Getting Started With Arduino: A Beginner's Guide Getting Started With Arduino: A Beginner's Guide Arduino is an open-source electronics prototyping platform based on flexible, easy-to use hardware and software. It's intended for artists, designers, hobbyists, and anyone interested in creating interactive objects or environments. Read More .

Note: This is the latest in a series of beginner level tutorials for Arduino, the open source electronics prototyping platform. Here’s a list of the previous articles in the series:

What You Need

Apart from the basic Arduino, you’ll need:

  • Red, yellow and green LEDs.
  • A breadboard.
  • 6 x 220 ? resistors.
  • Connecting wires.
  • 1 x pushbutton switch.
  • 1 x 10k ? resistor

Almost any Arduino will be suitable, providing it has enough pins. Make sure you read our buying guide Arduino Buying Guide: Which Board Should You Get? Arduino Buying Guide: Which Board Should You Get? There are so many different kinds of Arduino boards out there, you'd be forgiven for being confused. Which should you buy for your project? Let us help, with this Arduino buying guide! Read More if you are not sure what model you need. You probably have these parts in your starter kit What's in Your Arduino Starter Kit? [Arduino Beginners] What's in Your Arduino Starter Kit? [Arduino Beginners] Faced with a box full of electronic components, it's easy to be overwhelmed. Here's a guide to exactly what you'll find in your kit. Read More  already.

A Simple Example

Let’s start small. A basic, single traffic light is a good place to start. Here’s the circuit:

arduino_traffic_light

Connect the anode (long leg) of each LED to digital pins eight, nine, and ten (via a 220? resistor). Connect the cathodes (short leg) to Arduino ground.

I used Fritzing to draw these diagrams. Not only is it easy to use, it’s free!

The Code

Start by defining variables so that we can address the lights by name rather than a number. Start a new Arduino project, and begin with these lines:

int red = 10;
int yellow = 9;
int green = 8;

Next, let’s add the setup function, where’ll we configure the red, yellow and green LEDs to be outputs. Since you have created variables to represent the pin numbers, you can now refer to the pins by name instead.

void setup(){
    pinMode(red, OUTPUT);
    pinMode(yellow, OUTPUT);
    pinMode(green, OUTPUT);
}

That was easy. Now for the difficult part -– the actual logic of a traffic light. Create a separate function for changing the lights (you’ll see why later).

When you first begin programming, the code itself is very rudimentary – it’s figuring out the minute logic details that presents the biggest problem. The key to being a good programmer is to be able to look at any process, and break it down into its fundamental steps. Here’s the rest of the code:

void loop(){
    changeLights();
    delay(15000);
}

void changeLights(){
    // green off, yellow on for 3 seconds
    digitalWrite(green, LOW);
    digitalWrite(yellow, HIGH);
    delay(3000);

    // turn off yellow, then turn red on for 5 seconds
    digitalWrite(yellow, LOW);
    digitalWrite(red, HIGH);
    delay(5000);

    // red and yellow on for 2 seconds (red is already on though)
    digitalWrite(yellow, HIGH);
    delay(2000);

    // turn off red and yellow, then turn on green
    digitalWrite(yellow, LOW);
    digitalWrite(red, LOW);
    digitalWrite(green, HIGH);
    delay(3000);
}

Done! Now, upload and run (make sure to select the correct board and port from the Tools > Port and Tools > Board menus). You should have a working traffic light that changes every 15 seconds, like this (sped up):

single_traffic_light

A Pedestrian Crossing

Now that you know the basics, let’s improve it. Add in a pushbutton for pedestrians to change the light whenever they like:

arduino_traffic_light_with_button

Notice how the traffic light is exactly the same as the previous example. Connect the button to digital pin 12. You’ll notice that the switch has a high-impedance 10k? resistor attached to it, and you may be wondering why. This is called a pull-down resistor. It’s a difficult concept to grasp at first, but bear with me.

A switch either lets the current flow, or doesn’t. This seems simple enough, but in a logic circuit, the current should be always flowing in either a high or low state (remember – 1 or 0, high or low). You might assume that a pushbutton switch that isn’t actually being pushed would be defined as being in a low state, but in fact it’s said to be ‘floating’, because no current is being drawn at all.

In this floating state, it’s possible that a false reading will occur as it fluctuates with electrical interference. In other words, a floating switch is giving neither a reliable high, nor low state reading. A pull down resistor keeps a small amount of current flowing when the switch is closed, thereby ensuring an accurate low state reading. In other logic circuits, you may find a pull-up resistor instead – this works on the same principle, but in reverse, making sure that particular logic gate defaults to high.

Now, in the loop part of the code, instead of changing the lights every 15 seconds, we’re going to read the state of the pushbutton switch instead, and only change the lights when it’s activated.

The Code

Start by adding a new variable to the start of the program:

int button = 12; // switch is on pin 12

Now, in the setup function, add a new line to declare the switch as an input. I’ve also added a single line to start the traffic lights in the green stage. Without this initial setting, they would be turned off, until the first time a changeLights() was initiated using a function.

pinMode(button, INPUT);
digitalWrite(green, HIGH);

Change the entire loop function to the following instead:

void loop() {
    if (digitalRead(button) == HIGH){
        delay(15); // software debounce
        if (digitalRead(button) == HIGH) {
            // if the switch is HIGH, ie. pushed down - change the lights!
            changeLights();
            delay(15000); // wait for 15 seconds
        }
    }
}

That should do it. You may be wondering why the button is checked twice (digitalRead(button)), separated by a small delay. This is called debouncing. Much like the pull down resistor was needed for the button, this simple check stops the code detecting minor interference as a button press. You don’t have to do this (and it would probably work just fine without it), but it’s good practice.

By waiting inside the if statement for 15 seconds, the traffic lights can’t change for at least that duration. Once 15 seconds is up, the loop restarts. Each restart of the loop, read the state of the button again, but if it isn’t pressed, the if statement never activates, the lights never change, and it simply restarts again.

Here’s how this looks (sped up):

pelican_crossing

A Junction

Let’s try a more advanced model. Instead of a pedestrian crossing, modify your circuit to have two traffic lights:

arduino_dual_traffic_light

Connect the second traffic light to digital pins 11, 12, and 13.

The Code

First, assign your new traffic light pins to variables, and configure them as outputs, just like in the first example:

// light one
int red1 = 10;
int yellow1 = 9;
int green1 = 8;

// light two
int red2 = 13;
int yellow2 = 12;
int green2 = 11;

void setup(){
    // light one
    pinMode(red1, OUTPUT);
    pinMode(yellow1, OUTPUT);
    pinMode(green1, OUTPUT);

    // light two
    pinMode(red2, OUTPUT);
    pinMode(yellow2, OUTPUT);
    pinMode(green2, OUTPUT);
}

Now, update your loop to use the code from the first example (instead of the pedestrian crossing):

void loop(){
    changeLights();
    delay(15000);
}

Once again, all the work is being carried out in the changeLights() function. Rather than going red > red & yellow > green, this code will alternate the traffic lights. When one is on green, the other will be on red. Here’s the code:

void changeLights(){
    // turn both yellows on
    digitalWrite(green1, LOW);
    digitalWrite(yellow1, HIGH);
    digitalWrite(yellow2, HIGH);
    delay(5000);

    // turn both yellows off, and opposite green and red
    digitalWrite(yellow1, LOW);
    digitalWrite(red1, HIGH);
    digitalWrite(yellow2, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(green2, HIGH);
    delay(5000);

    // both yellows on again
    digitalWrite(yellow1, HIGH);
    digitalWrite(yellow2, HIGH);
    digitalWrite(green2, LOW);
    delay(3000);

    // turn both yellows off, and opposite green and red
    digitalWrite(green1, HIGH);
    digitalWrite(yellow1, LOW);
    digitalWrite(red1, LOW);
    digitalWrite(yellow2, LOW);
    digitalWrite(red2, HIGH);
    delay(5000);

}

Here’s what that looks like (sped up):

dual_traffic_light

That’s it for this time, so I hope you learnt lots and had fun writing from scratch. You got your hands dirty with a few LEDs and resistors, as well as adding a switch with a pull down resistor – hopefully you understood why we need one. Play around with the code, adjust it, and most importantly have fun. If you make any additions or changes, why not let us know about it in the comments?

Image Credit: androsvector via Shutterstock.com

Leave a Reply

Your email address will not be published. Required fields are marked *

  1. BharathiKumar
    May 4, 2017 at 2:27 pm

    Ya nice,I will do many times,super but i will lean more ideas in this little....tell me more instruction to do in this projects....

  2. Markus
    April 27, 2017 at 10:04 am

    I did everything like the instructions said and inserted the code but nothing happens could it be that something is broken on my bord

    • Willie
      May 22, 2017 at 11:59 am

      did you fix it? I have this exact problem right now :/

  3. Heithem
    April 25, 2017 at 2:22 pm

    what if we add a pedestrian button to push to cross
    how will the code be

  4. Giovanni Edrose
    March 27, 2017 at 2:16 pm

    can we program our arduino with our smartphones?How?

  5. Danny DelBalzo
    March 17, 2017 at 7:16 pm

    I'm following your basic code and continue to get this error message:

    'changeLights' was not declared in this scope

    Do you have any suggestions?

    • Kyriakos
      March 20, 2017 at 12:20 pm

      same problem here.

      • Joe Coburn
        March 20, 2017 at 5:46 pm

        All fixed, sorry! :)

  6. mohamed
    February 15, 2017 at 1:44 am

    what if you have a four-way intersection with four crossing? how do you modify that

  7. T o connor
    February 5, 2017 at 10:00 pm

    For the first example ,[ the single traffic light set]
    the ""delay(15000);"" part of the
    void loop(){
    changeLights();
    delay(15000);
    is adding 15secs to the turn on time of the green LED.
    If this line is removed the green led will run on for the 3 sec as written in the code.

  8. bilal
    February 3, 2017 at 5:04 pm

    there is problem while runnig the code
    traffic for signal 1 is working but for signal 2 its not working plz guide

    • Joe Coburn
      March 20, 2017 at 5:47 pm

      I've updated a typo, thanks for stopping by.

      • Francis Heron
        June 3, 2017 at 5:20 pm

        can you please advise where the corrected code appears or what it is as I cant find it

  9. troy
    February 1, 2017 at 2:21 am

    What is the correct code for the pedestrian crossing traffic light.

    • Joe Coburn
      March 20, 2017 at 5:47 pm

      All fixed now, checkout the updated code!

  10. melvin B
    January 26, 2017 at 8:57 am

    The Arduino gives a message while compiling: 'changelights' was not declared. This refers to the line directly after the "void loop(){"
    Should it be declared in de void setup() or before that?

    • Nahuel
      February 16, 2017 at 3:10 am

      Just move the declaration of changeLights() before loop()

      void changeLights() {
      ...
      }

      void setup() {
      ...
      }

      void loop() {
      ...
      }

  11. Aakash Choudhry
    January 11, 2017 at 7:45 pm

    Did this code work for anyone??

    • Brian Graham
      January 29, 2017 at 12:59 pm

      // light one
      int red1 = 10;
      int yellow1 = 9;
      int green1 = 8;

      // light two
      int red2 = 13;
      int yellow2 = 12;
      int green2 = 11;

      void setup(){
      Serial.println("Welcome");
      // light one
      pinMode(red1, OUTPUT);
      pinMode(yellow1, OUTPUT);
      pinMode(green1, OUTPUT);

      // light two
      pinMode(red2, OUTPUT);
      pinMode(yellow2, OUTPUT);
      pinMode(green2, OUTPUT);
      }

      void loop(){
      changeLights();
      delay(15000);
      }

      void changeLights(){
      // turn both yellows on
      Serial.println("Hello world");
      digitalWrite(green1, LOW);
      digitalWrite(yellow1, HIGH);
      digitalWrite(yellow2, HIGH);
      delay(5000);

      // turn both yellows off, and opposite green and red
      digitalWrite(yellow1, LOW);
      digitalWrite(red1, HIGH);
      digitalWrite(yellow2, LOW);
      digitalWrite(red2, LOW);
      digitalWrite(green2, HIGH);
      delay(5000);

      // both yellows on again
      digitalWrite(yellow1, HIGH);
      digitalWrite(yellow2, HIGH);
      digitalWrite(green2, LOW);
      delay(3000);

      // turn both yellows off, and opposite green and red
      digitalWrite(green1, HIGH);
      digitalWrite(yellow1, LOW);
      digitalWrite(red1, LOW);
      digitalWrite(yellow2, LOW);
      digitalWrite(red2, HIGH);
      delay(5000);

      }

      • Steven Jurick
        February 10, 2017 at 1:45 pm

        Why do you turn both yellows on?

    • ledpup
      February 3, 2017 at 5:03 am

      The first changeLights function is missing an open curly brace {

      void changeLights()
      // green off, yellow on for 3 seconds
      digitalWrite(green, LOW);
      etc.

      Should be:

      void changeLights() *{*
      // green off, yellow on for 3 seconds
      digitalWrite(green, LOW);
      etc.

  12. saleem
    January 10, 2017 at 1:45 am

    Easy to understand arduino function

    • Steven Jurick
      February 10, 2017 at 1:44 pm

      Realistically, in a 4-way intersection, both Red Lights are lit for about 1/2 sec before the Red turns to Green.

      How would you implement the additional 500ms for the Red light that's about to turn green? Since using delay is linear (code executes down line by line), I can't get it to work without the yellow also pausing for 500ms along with the Red before both turning off.

      Ex:
      North-South light is RED
      East-West light is GREEN
      EW Green turns YELLOW
      EW Yellow turns RED
      NS RED should stay on for .5 sec, then turn Green

      Perhaps using millis() or even a state machine is required for this? If you can do it with delay please let me know.

      Below is my code for a 4-way intersection without the needed .5 red delay:

      // Environment
      int ledRedNS = 11;
      int ledYelNS = 10;
      int ledGrnNS = 9;
      int ledRedEW = 8;
      int ledYelEW = 7;
      int ledGrnEW = 6;
      int rgDelay = (6000); //Red and Green on duration
      int yDelay = (4000); //Yellow on duration

      void setup() {
      // Initialize digital pins as an output
      pinMode(ledRedNS, OUTPUT);
      pinMode(ledYelNS, OUTPUT);
      pinMode(ledGrnNS, OUTPUT);
      pinMode(ledRedEW, OUTPUT);
      pinMode(ledYelEW, OUTPUT);
      pinMode(ledGrnEW, OUTPUT);

      // Set initial light state (RED NS ON; GRN EW ON for rgDelay)
      digitalWrite(ledRedNS, HIGH);
      digitalWrite(ledGrnEW, HIGH);
      delay(rgDelay);
      }

      void loop() {
      //YEL EW ON; GRN EW OFF for yDelay
      digitalWrite(ledYelEW, HIGH);
      digitalWrite(ledGrnEW, LOW);
      delay(yDelay);

      //RED EW ON; RED NS OFF; GRN NS ON for rgDelay
      digitalWrite(ledRedEW, HIGH);
      digitalWrite(ledRedNS, LOW); //Needs to pause 500ms before turning LOW
      digitalWrite(ledGrnNS, HIGH);
      digitalWrite(ledYelEW, LOW);
      delay(rgDelay);

      //YEL NS ON; GRN NS OFF for yDelay
      digitalWrite(ledYelNS, HIGH);
      digitalWrite(ledGrnNS, LOW);
      delay(yDelay);

      //RED NS ON; RED EW OFF; GRN EW OFF; YEL NS OFF for rgDelay
      digitalWrite(ledRedNS, HIGH);
      digitalWrite(ledRedEW, LOW); //Needs to pause 500ms before turning LOW
      digitalWrite(ledGrnEW, HIGH);
      digitalWrite(ledYelNS, LOW);
      delay(rgDelay);
      }

      • Joe Coburn
        February 10, 2017 at 2:22 pm

        Yep, state machine is required - check out our guide below!

        http://www.makeuseof.com/tag/arduino-delay-function-shouldnt-use/

        • Steven Jurick
          February 11, 2017 at 1:51 am

          OK, so I've rebuilt my sketch using millis(); instead of delay. I setup a large if statement in loop() and I can alternate RED/GRN LEDs at a given interval, but I'm really lost on how to introduce the YEL on each side, which will obviously cancel it's respective GRN, then when the YEL turns to RED, leaving the other RED on for 500ms, then turn it GRN and start the whole cycle over again.

          I guess there needs to be a way to check how long each individual LED has been on? Is that correct thinking?