Adding button which resets to top of void
As currently written, your changeLights() function, which is repeatedly called over and over again by the Arduino loop() function, runs a timed sequence of lights.


Red light is on for 3000 ms
Amber is on for 3000 ms
Green is on for 3000 ms


This sequence could also be implemented using a state machine, but as it is right now, it's just a simple sequence of operations.

So now you have a new feature request (heh, this happens all the time in pro software development): 


hardware will include a momentary switch to ground
when the switch is pressed, the changeLights() sequence will skip to the next Red light
we might also want to do other kinds of sequence change, not just reset


The simplest way to code this would be to use digitalRead() to test whether the switch is pressed. You could test just after each of the delay(3000) calls. Technically this would work, but it would only sense the switch state just at the instant that digitalRead() is called. So for most of your 9-second sequence, it will ignore the switch, and only briefly test. The user will have to hold the button for 3 seconds to be sure the program senses the switch press.

There are some better ways to make this work. The delay(3000) actually makes the program do nothing else but watch the clock for the full delay interval, it doesn't do anything else during this time. So instead of delay(3000) you could use a for loop, and test whether the button has been pressed.

// Spend 3 seconds waiting; exit the function if BUTTON1 is pressed.
for(int count = 300; count &gt; 0; count--) {
    delay(10); // test the button every 10 ms
    if (digitalRead(BUTTON1) == LOW) {
        return; // skip out of the changeLights() function
    }
}


(Just saw Edgar Bonet's comment about the blink without delay Ardino example, which is another valid way to do the same thing. You could also use the millis() function and calculate the time when the next state transition should happen.)

Since this is an educational example, it's worth looking into how you would implement this as a state machine. (The traffic lights controller is often used as an introduction to state machines.) There's two types of state machines, Mealy and Moore, the difference is that one kind the outputs are determined only by the internal state, and the other kind, the outputs are a function of the internal state and the inputs.

A simple traffic light controller state machine might look like this:


state 0: initialize; next state=1
state 1: Red light on, timer=5 seconds, next state=2
state 2: Green light on, timer=3 seconds, next state=3
state 3: Amber light on, timer=1 seconds, next state=1


Use a timing countdown like in the example above, and when the countdown reaches 0, advance to the next state.

const int S0_INIT = 0; // state 0: initialize
const int S1_RED = 1; // state 1: Red light on
const int S2_GREEN = 2; // state 2: Green light on
const int S3_AMBER = 3; // state 3: Amber light on
int state = S0_INIT;
int stateTimer = 0;
// void setup() not shown; configures input and output pins by pinMode(...)
void loop()
{
    if (stateTimer &lt; 0) { stateTimer = 0; state = S0_INIT; return; }
    if (stateTimer &gt; 0) {
        stateTimer = stateTimer - 1;
        delay(10); // 10 ms interval
        return;
    }
    switch(state) {
    case S0_INIT: // state 0: initialize; next state=1
        stateTimer = 0;
        state = S1_RED;
        break;
    case S1_RED: // state 1: Red light on, timer=5 seconds, next state=2
        // digitalWrite(... etc.) Red light on
        stateTimer = 500;
        state = S2_GREEN;
        break;
    case S2_GREEN: // state 2: Green light on, timer=3 seconds, next state=3
        // digitalWrite(... etc.) Green light on
        stateTimer = 300;
        state = S3_AMBER;
        break;
    case S3_AMBER: // state 3: Amber light on, timer=1 seconds, next state=1
        // digitalWrite(... etc.) Amber light on
        stateTimer = 100;
        state = S1_RED;
        break;
    }
}


A more advanced traffic light controller (that responds to input) might look like this:


state 0: initialize; next state=1
state 1: Red light on, next state=2 (unless SWITCH1=HIGH, next state=4)
state 2: Green light on, next state=3 (unless SWITCH1=HIGH, next state=4)
state 3: Amber light on, next state=1 (unless SWITCH1=HIGH, next state=4)
state 4: Red light on, next state=5 (unless SWITCH1=LOW, next state=2)
state 5: no lights on, next state=4 (unless SWITCH1=LOW, next state=2)


An external input SWITCH1 switches this traffic controller between Red-Amber-Green sequence (states 1-2-3) and flashing-Red sequence (states 4-5). Adding constants for S4_BLINKING_RED=4 and S5_BLINKING_RED=5 and replacing the switch(state):

    switch(state) {
    case S0_INIT:
        stateTimer = 0;
        state = S1_RED;
        break;
    case S1_RED:
        // digitalWrite(... etc.) Red light on
        stateTimer = 500;
        state = S2_GREEN;
        if (digitalRead(SWITCH1) == HIGH) {
            state = S4_BLINKING_RED;
        }
        break;
    case S2_GREEN:
        // digitalWrite(... etc.) Green light on
        stateTimer = 300;
        state = S3_AMBER;
        if (digitalRead(SWITCH1) == HIGH) {
            state = S4_BLINKING_RED;
        }
        break;
    case S3_AMBER:
        // digitalWrite(... etc.) Amber light on
        stateTimer = 100;
        state = S1_RED;
        if (digitalRead(SWITCH1) == HIGH) {
            state = S4_BLINKING_RED;
        }
        break;
    case S4_BLINKING_RED:
        // digitalWrite(... etc.) Red light on
        stateTimer = 50;
        state = S5_BLINKING_RED;
        if (digitalRead(SWITCH1) == LOW) {
            state = S2_GREEN;
        }
        break;
    case S5_BLINKING_RED:
        // digitalWrite(... etc.) no lights on
        stateTimer = 50;
        state = S4_BLINKING_RED;
        if (digitalRead(SWITCH1) == LOW) {
            state = S2_GREEN;
        }
        break;
    }


(Remember to define the SWITCH1 pin, and configure pinMode(SWITCH1 ) in setup().)

Of course a real traffic light controller has more lights, say Northbound-Red, Northbound-Amber, Northbound-Green, Westbound-Red, Westbound-Amber, Westbound-Green, etc. Not to mention left turn arrows and maybe even "vehicle present" sensors. For a smart traffic light controller like that, the state is named by what traffic flow is authorized during that state:


state 1: northbound-southbound traffic green, 5 seconds, next state 2
state 2: northbound-southbound traffic amber, 2 seconds, next state 3
state 3: all lights red, 0.5 second, next state 4 (unless no vehicles waiting west-east lanes, then next state 6)
state 4: westbound-eastbound traffic green, 5 seconds, next state 5
state 5: westbound-eastbound traffic amber, 2 seconds, next state 6
state 6: all lights red, 0.5 second, next state 7 (unless no vehicles waiting N-W nor S-E left turn bays, then next state 9)
state 7: north-to-west left turn and south-to-east left turn green, 3 seconds, next state 8
state 8: north-to-west left turn and south-to-east left turn amber, 2 seconds, next state 9
state 9: all lights red, 0.5 second, next state 10 (unless no vehicles waiting W-S nor E-N left turn bays, then next state 12)
state 10: west-to-south left turn and east-to-north left turn green, 3 seconds, next state 11
state 11: west-to-south left turn and east-to-north left turn amber, 2 seconds, next state 1
state 12: all lights red, 0.5 second, next state 1 (unless no vehicles waiting north-south lanes, then next state 3)


The power of using state machines is that they all use the same basic "engine", just with more states, more outputs, more inputs. If the traffic engineer wants to adjust the timing to improve the flow of traffic, that only requires adjusting some of the data, which is much lower risk than rewriting code.  ... and of course state machines apply to more than just traffic lights, it's a very generally useful design technique.