Диалог с ИИ.
Спойлер
Ты програмист ардуино. Напиши программу и прокомментируй каждую строку. Алгоритм : загорается лампочка через случайный период от 1 до 5 секунд, после загорания лампочки надо нажать одну из трёх кнопок и лампочка соответствующее кнопке должна загореться. Нажатие любой кнопки сбрасывает программну в начальное состояние. Нажатие кнопки раньше загорания первой лампочки приводит к морганию лампочки соответствующей кнопки.
1:59 PM
Конечно! Ниже приведена программа на языке Arduino C++ для описанного тобой алгоритма. Я подробно прокомментирую каждую строку, чтобы было понятно, как всё работает.
Предположим, у нас:
- 1 лампочка-индикатор ожидания (например, светодиод на пине
LED_WAIT) — она загорается случайно через 1–5 секунд.
- 3 кнопки:
BTN1, BTN2, BTN3.
- 3 лампочки, соответствующие кнопкам:
LED1, LED2, LED3.
- Если нажать кнопку до загорания
LED_WAIT — соответствующий LED мигает один раз (например, 200 мс).
- Если нажать кнопку после загорания
LED_WAIT — соответствующий LED загорается и держится, а все сбрасывается через короткую паузу.
- Любое нажатие кнопки сбрасывает состояние в начало (ожидание нового случайного интервала).
Исходный код с комментариями:
// Пины для светодиодов
#define LED_WAIT 13 // “ожидающая” лампочка (обычно встроенный LED на пине 13)
#define LED1 10 // лампочка для кнопки 1
#define LED2 11 // лампочка для кнопки 2
#define LED3 12 // лампочка для кнопки 3
// Пины для кнопок (подключены к GND, используют внутренний подтяжку к VCC)
#define BTN1 2 // кнопка 1
#define BTN2 3 // кнопка 2
#define BTN3 4 // кнопка 3
// Переменные состояния
unsigned long startTime; // время старта текущего цикла (мс)
unsigned long waitTime; // случайный интервал ожидания (1–5 сек → 1000–5000 мс)
bool waitingForLight = true; // флаг: true — ждём, когда загорится LED_WAIT
bool lightIsOn = false; // флаг: true — LED_WAIT уже горит, ждём реакции
bool buttonPressed = false; // чтобы избежать многократной обработки одного нажатия
// Функция инициализации (выполняется один раз при включении или сбросе)
void setup() {
// Инициализация пинов светодиодов как выходов
pinMode(LED_WAIT, OUTPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
// Инициализация пинов кнопок как входов с подтяжкой к VCC (внутренний резистор)
pinMode(BTN1, INPUT_PULLUP);
pinMode(BTN2, INPUT_PULLUP);
pinMode(BTN3, INPUT_PULLUP);
// Запуск генератора случайных чисел (используем шум с аналогового пина для инициализации)
randomSeed(analogRead(A0)); // A0 не подключён — берём шум как источник энтропии
// Сброс всех светодиодов в выключенное состояние
digitalWrite(LED_WAIT, LOW);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
// Начинаем первую сессию: засекаем время старта
resetGame(); // функция ниже реализует сброс в начальное состояние
}
// Главный цикл (выполняется бесконечно)
void loop() {
// Читаем состояние кнопок
bool btn1Pressed = digitalRead(BTN1) == LOW; // кнопки активны при LOW (из-за INPUT_PULLUP)
bool btn2Pressed = digitalRead(BTN2) == LOW;
bool btn3Pressed = digitalRead(BTN3) == LOW;
// Текущее время в миллисекундах
unsigned long currentTime = millis();
// === Этап 1: Ожидаем случайного интервала, пока не загорится LED_WAIT ===
if (waitingForLight) {
// Проверяем, прошло ли уже нужное время?
if (currentTime - startTime >= waitTime) {
// Время вышло — зажигаем “ожидающую” лампочку
digitalWrite(LED_WAIT, HIGH);
lightIsOn = true; // теперь ждём реакции игрока
waitingForLight = false; // больше не в режиме ожидания старта
}
// Если нажали кнопку ДО загорания — моргаем соответствующим LED
if ((btn1Pressed || btn2Pressed || btn3Pressed) && !buttonPressed) {
buttonPressed = true; // флаг — нажатие зафиксировано (антидребезг)
// Выключаем ожидание, чтобы не реагировать повторно
waitingForLight = false;
// Моргаем нужным светодиодом
if (btn1Pressed) blinkLED(LED1);
if (btn2Pressed) blinkLED(LED2);
if (btn3Pressed) blinkLED(LED3);
// Сразу сбрасываем игру (т.к. нажатие — досрочное)
delay(500); // пауза, чтобы игрок увидел моргание
resetGame();
}
}
// === Этап 2: LED_WAIT горит — ждём нажатия кнопки ===
else if (lightIsOn) {
// Если нажали любую кнопку — загорается соответствующий LED и сброс
if ((btn1Pressed || btn2Pressed || btn3Pressed) && !buttonPressed) {
buttonPressed = true;
// Гасим индикатор ожидания
digitalWrite(LED_WAIT, LOW);
// Включаем нужный LED (и оставляем его включённым на 1 сек, затем гасим)
if (btn1Pressed) digitalWrite(LED1, HIGH);
if (btn2Pressed) digitalWrite(LED2, HIGH);
if (btn3Pressed) digitalWrite(LED3, HIGH);
// Даём игроку увидеть результат
delay(1000); // держим LED включённым 1 секунду
// Гасим все LED и сбрасываем игру
resetGame();
}
}
// === Антидребезг: когда кнопки отпущены — сбрасываем флаг buttonPressed ===
if (!btn1Pressed && !btn2Pressed && !btn3Pressed) {
buttonPressed = false;
}
// Небольшая задержка для снижения нагрузки (необязательна, но полезна)
delay(10);
}
// Функция: моргнуть светодиодом один раз (200 мс вкл → 200 мс выкл)
void blinkLED(int pin) {
digitalWrite(pin, HIGH);
delay(200);
digitalWrite(pin, LOW);
delay(200);
}
// Функция: сброс игры в начальное состояние
void resetGame() {
// Гасим всё
digitalWrite(LED_WAIT, LOW);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
// Генерируем новое случайное время ожидания: от 1000 до 5000 мс
waitTime = random(1000, 5001); // random(max) — НЕ включает max, поэтому 5001
// Запоминаем текущее время как старт нового раунда
startTime = millis();
// Возвращаем флаги в исходное состояние
waitingForLight = true;
lightIsOn = false;
buttonPressed = false; // на случай, если сброс вызван не через отпускание кнопок
}
Подключение в реальности:
| Элемент |
Пин Ардуино |
Особенности |
| Светодиод WAIT |
13 |
Встроенный LED на многих платах |
| LED1 |
10 |
Через резистор 220 Ом на GND |
| LED2 |
11 |
То же |
| LED3 |
12 |
То же |
| Кнопка 1 |
2 |
Один вывод → GND, второй → пин. Используется INPUT_PULLUP |
| Кнопка 2 |
3 |
То же |
| Кнопка 3 |
4 |
То же |
Кнопки должны замыкать пин на GND. Внутренняя подтяжка (INPUT_PULLUP) делает пин HIGH при отпущенной кнопке, и LOW при нажатой.
Как можно улучшить:
- Заменить
delay() на millis()-логику для полноценной неблокирующей работы (если в будущем добавишь таймеры, звук и т.п.).
- Добавить счётчик реакций, рекорды и т.д.
- Использовать библиотеку
Bounce2 для надёжной антидребёжной обработки кнопок.