Светофор на Pico с выбором 4 режимов кнопкой (конечный автомат)
4 режима светофора всего одной кнопкой! Каждое нажатие меняет режим: обычный цикл (красный → жёлтый → зелёный по очереди), только красный (сигнал стоп), мигающий жёлтый (внимание/ночной режим) и выключено (обслуживание). Понятия: конечный автомат (переменная mode определяет, какое поведение выполняется), цикл режимов по модулю ((mode + 1) % 4 → 0→1→2→3→0), неблокирующий тайминг (фазы светодиодов отсчитываются через time.ticks_ms() + time.ticks_diff()).

Видео
Схема

Исходный код
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Светофор на Pico с выбором 4 режимов кнопкой (конечный автомат)
4# ─────────────────────────────────────────
5# Одна кнопка переключает 4 режима: обычный цикл (красный -> жёлтый ->
6# зелёный), только красный, мигающий жёлтый и выкл. Использует конечный
7# автомат и неблокирующий отсчёт времени через time.ticks_ms(), поэтому
8# кнопка всегда отзывчива.
9#
10# Пины:
11# GP11 -> Зелёный светодиод
12# GP12 -> Жёлтый светодиод
13# GP13 -> Красный светодиод (каждый светодиод с 220 ohm)
14# GP4 -> Кнопка (другая ножка к GND)
15
16from machine import Pin
17import time
18
19# ============ СВЕТОДИОДЫ ============
20green = Pin(11, Pin.OUT) # Зелёный
21yellow = Pin(12, Pin.OUT) # Жёлтый
22red = Pin(13, Pin.OUT) # Красный
23
24# ============ КНОПКА ============
25button = Pin(4, Pin.IN, Pin.PULL_UP) # При нажатии читается 0
26
27# ============ СОСТОЯНИЕ ============
28# Режим: 0 обычный цикл, 1 только красный, 2 мигающий жёлтый, 3 выкл
29mode = 0
30last_btn = 1 # Предыдущее значение кнопки
31blink_state = False # Состояние мигающего жёлтого
32last_tick = time.ticks_ms() # Последнее переключение мигания
33
34# ============ ОБЫЧНЫЙ ЦИКЛ ============
35normal_step = 0 # 0: красный, 1: жёлтый, 2: зелёный
36normal_last = time.ticks_ms() # Время начала шага
37NORMAL_TIMES = [3000, 1000, 3000] # Красный, жёлтый, зелёный (мс)
38LEDS = [red, yellow, green]
39
40def all_off():
41 # Погасить все светодиоды
42 red.off(); yellow.off(); green.off()
43
44# ============ ГЛАВНЫЙ ЦИКЛ ============
45while True:
46 btn = button.value()
47
48 # ---- Кнопка нажата (1 -> 0): смена режима ----
49 if last_btn == 1 and btn == 0:
50 mode = (mode + 1) % 4
51 all_off()
52 normal_step = 0
53 normal_last = time.ticks_ms()
54 time.sleep_ms(200) # Антидребезг
55 last_btn = btn
56
57 now = time.ticks_ms()
58
59 # ---- Обычный цикл светофора ----
60 if mode == 0:
61 if time.ticks_diff(now, normal_last) > NORMAL_TIMES[normal_step]:
62 normal_step = (normal_step + 1) % 3
63 normal_last = now
64 all_off()
65 LEDS[normal_step].on()
66
67 # ---- Только красный (стоп) ----
68 elif mode == 1:
69 all_off(); red.on()
70
71 # ---- Мигающий жёлтый, 0,4 с (осторожно/ночь) ----
72 elif mode == 2:
73 if time.ticks_diff(now, last_tick) > 400:
74 blink_state = not blink_state
75 yellow.value(blink_state)
76 last_tick = now
77 red.off(); green.off()
78
79 # ---- Выкл ----
80 else:
81 all_off()
82
83 time.sleep_ms(10)
84Частые вопросы
Что такое конечный автомат?
Одна переменная (mode) определяет, что программа делает прямо сейчас. Каждое нажатие кнопки меняет режим, а цикл выполняет только код текущего режима. Это стандартный способ держать сложное поведение в порядке.
Что делает (mode + 1) % 4?
Она увеличивает режим на один и, дойдя до 4, возвращает его к 0, поэтому режимы бесконечно идут по кругу 0, 1, 2, 3, 0, 1...
Почему используется ticks_ms(), а не time.sleep()?
Во время sleep() Pico не может читать кнопку, поэтому смена режима запаздывает. ticks_ms() и ticks_diff() позволяют обойтись без долгих ожиданий во всех фазах светодиодов. Однако эта версия ждёт 200 ms для антидребезга при смене режима и 10 ms в конце каждого цикла; в эти промежутки кнопка заново не читается.
Можно ли добавить новый режим?
Да, увеличь число режимов до 5 и напиши для нового отдельный блок поведения, например мигающий зелёный или поочерёдное зажигание всех огней.
