Traffic Light Control System

Objective:

Understand a MicroPython system that controls a set of traffic lights using buttons and timers.

Components:

  • 3 LEDs (Red, Yellow, Green)
  • 4 Buttons (Red, Yellow, Green, Blue)
  • Dictionary comprehensions provide a concise method to generate dictionaries.
  • Debouncing is crucial for accurate button press detection.

Additional Notes:

Program Flow and Structure

Program Structure:

              Initialization        		   
                    |
                    | 
                    V            
                Mode Switch
                /         \
               /           \
          Auto Mode    Manual Mode
              |              |
              |              |                 			|
              V              V
        Switch Light    Check Button

Note: The blue button toggles between the auto and manual modes.

  Mode Switch

  Traffic Light Auto

  Traffic Light  Manual

Soution1 🔗

Button Debounce with Timer and IRQ Flag

Code Overview & Initialization

from machine import Pin, Timer
import utime

color_and_pin_list = [('red', 23), ('yellow', 22), ('green', 21)]
leds = {color: Pin(pin, Pin.OUT) for color, pin in color_and_pin_list}

button_and_pin_list = [('red_b', 32), ('yellow_b', 33), ('green_b', 25), ('blue_b', 4)]
buttons = {color: Pin(pin, Pin.IN, Pin.PULL_UP) for color, pin in button_and_pin_list}

auto_mode = True
  • Libraries machine and utime are imported.
  • LEDs and buttons are defined and initialized.
  • A variable auto_mode determines the operating mode.

Timers and Automatic Mode

def change_light(t):
    if leds['red'].value():
        leds['red'].off()
        leds['green'].on()
        auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)
    elif leds['green'].value():
        leds['green'].off()
        leds['yellow'].on()
        auto_mode_timer.init(period=200, mode=Timer.ONE_SHOT, callback=change_light)
    else:
        leds['yellow'].off()
        leds['red'].on()
        auto_mode_timer.init(period=500, mode=Timer.ONE_SHOT, callback=change_light)

auto_mode_timer = Timer(0)
leds['green'].on()
auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)
  • The function change_light controls the sequence of traffic light changes.
  • The timer auto_mode_timer periodically calls this function.

Manual Mode and Button Checks

def check_buttons(t):
    if not buttons['red_b'].value():
        leds['red'].on()
        leds['yellow'].off()
        leds['green'].off()
    elif not buttons['yellow_b'].value():
        leds['red'].off()
        leds['yellow'].on()
        leds['green'].off()
    elif not buttons['green_b'].value():
        leds['red'].off()
        leds['yellow'].off()
        leds['green'].on()

button_check_timer = Timer(1)
#button_check_timer.init(period=50, mode=Timer.PERIODIC, callback=check_buttons)        
  • The function check_buttons checks if any button is pressed and adjusts the LED state accordingly.
  • The timer button_check_timer is prepared to check button presses periodically in manual mode.

Toggle Mechanism and Interrupts

def toggle_auto_mode(pin):
    global auto_mode, irq_isenable
    if irq_isenable:
        auto_mode = not auto_mode
        irq_isenable = False
        Timer(-1).init(mode=Timer.ONE_SHOT, period=200, callback=enable_irq)
        if auto_mode:
           button_check_timer.deinit()
           auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)
        else:
           auto_mode_timer.deinit()
           button_check_timer.init(period=50, mode=Timer.PERIODIC, callback=check_buttons)        
        print("自動模式:", auto_mode)

blue_button = buttons['blue_b']
blue_button.irq(trigger=Pin.IRQ_FALLING, handler=toggle_auto_mode)
  • The toggle_auto_mode function switches between automatic and manual modes.
  • An interrupt is attached to the blue button to activate this function when pressed.
  • Button debounce is achieved by using timer and irq_enable flag

Main Loop

print("自動模式:", auto_mode)
while True:
    utime.sleep_ms(50)
  • The main loop keeps the program running indefinitely.
  • A minor delay is added to prevent the loop from occupying the CPU excessively.

Solution2 🔗

Button Debounce with Time Tick Difference

Initialization & Configuration

from machine import Pin, Timer
import utime

color_and_pin_list = [('red', 23), ('yellow', 22), ('green', 21)]
leds = {color: Pin(pin, Pin.OUT) for color, pin in color_and_pin_list}

button_and_pin_list = [('red_b', 32), ('yellow_b', 33), ('green_b', 25), ('blue_b', 4)]
buttons = {color: Pin(pin, Pin.IN, Pin.PULL_UP) for color, pin in button_and_pin_list}
  • Import necessary modules.
  • LEDs and buttons are initialized with their respective pins.
  • Dictionary comprehensions are utilized for concise code representation.

Automated Light Change Logic

def change_light(t):
    if leds['red'].value():
        leds['red'].off()
        leds['green'].on()
        auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)
    elif leds['green'].value():
        leds['green'].off()
        leds['yellow'].on()
        auto_mode_timer.init(period=200, mode=Timer.ONE_SHOT, callback=change_light)
    else:
        leds['yellow'].off()
        leds['red'].on()
        auto_mode_timer.init(period=500, mode=Timer.ONE_SHOT, callback=change_light)
  • The change_light function manages the LED transitions based on their current state.
  • Different time intervals are set for each transition to simulate realistic traffic light behavior.

Manual Mode Logic

def check_buttons(t):
    if not buttons['red_b'].value():
        leds['red'].on()
        leds['yellow'].off()
        leds['green'].off()
    elif not buttons['yellow_b'].value():
        leds['red'].off()
        leds['yellow'].on()
        leds['green'].off()
    elif not buttons['green_b'].value():
        leds['red'].off()
        leds['yellow'].off()
        leds['green'].on()
  • The check_buttons function assesses which button has been pressed.
  • Depending on the button pressed, the corresponding LED is activated.

Timer Initialization and System Start

auto_mode_timer = Timer(0)
leds['green'].on()
auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)

button_check_timer = Timer(1)
  • Initialize timers for the automatic mode and button checks.
  • At startup, the green LED is turned on, and the automatic mode timer begins.

Debounce Logic and Mode Toggle

auto_mode = True
debounce_time_ms = 150
last_button_press_time = 0

def toggle_auto_mode(pin):
    global auto_mode, last_button_press_time
    current_time = utime.ticks_ms()
    press_time_diff = utime.ticks_diff(current_time, last_button_press_time)
    if  press_time_diff >= debounce_time_ms:
        last_button_press_time = current_time
        auto_mode = not auto_mode
        if auto_mode:
           button_check_timer.deinit()
           auto_mode_timer.init(period=700, mode=Timer.ONE_SHOT, callback=change_light)
        else:
           auto_mode_timer.deinit()
           button_check_timer.init(period=50, mode=Timer.PERIODIC, callback=check_buttons)        
        print("自動模式:", auto_mode)

blue_button = buttons['blue_b']
blue_button.irq(trigger=Pin.IRQ_FALLING, handler=toggle_auto_mode)
  • toggle_auto_mode function switches modes using the blue button.
  • Button Debounce with Time Tick Difference

Main Loop

print("自動模式:", auto_mode)
while True:
    utime.sleep_ms(50)
  • The main loop keeps the program running indefinitely.
  • A minor delay is added to prevent the loop from occupying the CPU excessively.