Все статьиHardware

Игра на запоминание последовательностей на Arduino

БА
Бексултан Айтен
CTO, Alashed
7 июня 2025 г.
9 мин чтения
Игра на запоминание последовательностей на Arduino

Создаём электронную игру Simon Says на Arduino с четырьмя светодиодами, кнопками и пьезодинамиком. Полный код, список компонентов и пошаговое объяснение алгоритма.

Что такое игра на запоминание

Электронная игра на запоминание последовательностей (известная как Simon Says) -- классика, придуманная в 1978 году. Устройство показывает случайную последовательность цветовых сигналов, а игрок должен повторить её в правильном порядке. С каждым раундом последовательность удлиняется на один элемент, и задача становится всё сложнее.

Этот проект идеален для изучения работы с несколькими кнопками одновременно, массивами, генерацией случайных чисел и таймерами на Arduino. Пьезодинамик добавляет звуковую обратную связь -- каждому цвету соответствует своя нота, что помогает запоминать последовательность не только визуально, но и на слух.

Уровень сложности: средний, подходит для 6-8 классов.

Собранная игра на запоминание с кнопками и светодиодами на макетной плате
Собранная игра на запоминание с кнопками и светодиодами на макетной плате

Необходимые компоненты

  • Arduino Uno -- 1 шт.
  • Светодиоды 5 мм (красный, зелёный, жёлтый, белый) -- 4 шт.
  • Тактовые кнопки (12 мм) -- 4 шт.
  • Резисторы 220 Ом -- 8 шт. (4 для светодиодов, 4 для кнопок)
  • Пьезодинамик (buzzer) -- 1 шт.
  • Макетная плата -- 1 шт.
  • Провода-перемычки -- 15 шт.
  • USB-кабель для подключения Arduino

Схема подключения

В этом проекте каждая кнопка и светодиод делят один и тот же пин Arduino. Это возможно благодаря тому, что в каждый момент времени пин работает либо как выход (для светодиода), либо как вход (для чтения кнопки). Такой приём экономит пины.

Распределение пинов:

КомпонентПин Arduino
Кнопка/LED 1 (красный)2
Кнопка/LED 2 (зелёный)13
Кнопка/LED 3 (жёлтый)10
Кнопка/LED 4 (белый)8
Пьезодинамик5

Каждый светодиод подключается через резистор 220 Ом к соответствующему пину. Кнопка одним контактом соединяется с тем же пином, другим -- с GND. Резистор 220 Ом на кнопке служит для защиты. Пьезодинамик подключается между пином 5 и GND.

Важно: расположите каждую кнопку рядом со «своим» светодиодом на макетной плате. Это критично для удобства игры -- игрок должен интуитивно понимать, какую кнопку нажимать для повтора конкретного цвета.

Вид устройства Simon Says на Arduino сверху
Вид устройства Simon Says на Arduino сверху

Полный код проекта

```cpp

// Игра на запоминание последовательностей (Simon Says)

// 4 светодиода, 4 кнопки, пьезодинамик

// Пины для кнопок и светодиодов (общие)

const int pins[] = {2, 13, 10, 8};

// Пин пьезодинамика

const int BUZZER_PIN = 5;

// Массив для хранения последовательности (до 100 элементов)

int sequence[100];

// Текущая длина последовательности

int curLen = 0;

// Время ожидания нажатия кнопки (мс)

const int PLAYER_WAIT_TIME = 2000;

void setup() {

Serial.begin(9600);

// Инициализация случайных чисел от шума на аналоговом пине

randomSeed(analogRead(A0));

// Пауза 3 секунды для стабилизации

delay(3000);

// Генерируем первый элемент последовательности

curLen = 0;

resetGame();

}

// Сброс игры -- начало новой последовательности

void resetGame() {

curLen = 1;

sequence[0] = random(0, 4); // случайный цвет (0-3)

}

// Включить светодиод на указанном пине

void lightOn(int pin) {

pinMode(pin, OUTPUT);

digitalWrite(pin, HIGH);

}

// Выключить светодиод

void lightOff(int pin) {

pinMode(pin, OUTPUT);

digitalWrite(pin, LOW);

}

// Звуковой сигнал заданной частоты и длительности

void beep(int freq, int duration) {

tone(BUZZER_PIN, freq, duration);

delay(duration);

noTone(BUZZER_PIN);

}

// Показать текущую последовательность игроку

void playSequence() {

// Короткий сигнал -- внимание, смотри!

beep(200, 100);

delay(500);

for (int i = 0; i < curLen; i++) {

int pin = pins[sequence[i]];

lightOn(pin);

delay(500); // светодиод горит полсекунды

lightOff(pin);

delay(250); // пауза между элементами

}

}

// Быстрое мигание всех светодиодов (эффект проигрыша)

void flashAll() {

for (int k = 0; k < 4; k++) {

// Зажигаем все

for (int i = 0; i < 4; i++) lightOn(pins[i]);

delay(150);

// Гасим все

for (int i = 0; i < 4; i++) lightOff(pins[i]);

delay(150);

}

}

// Считать нажатую кнопку (возвращает индекс 0-3 или -1)

int readButton() {

// Переключаем все пины в режим входа

for (int i = 0; i < 4; i++) {

pinMode(pins[i], INPUT_PULLUP);

}

unsigned long startTime = millis();

while (millis() - startTime < PLAYER_WAIT_TIME) {

for (int i = 0; i < 4; i++) {

if (digitalRead(pins[i]) == LOW) {

// Кнопка нажата -- подсвечиваем

delay(50); // антидребезг

if (digitalRead(pins[i]) == LOW) {

// Подтверждаем нажатие светом и звуком

lightOn(pins[i]);

beep(300 + i * 200, 200);

// Ждём отпускания

while (digitalRead(pins[i]) == LOW) {

delay(10);

}

lightOff(pins[i]);

delay(100);

return i;

}

}

}

delay(10);

}

return -1; // таймаут -- игрок не ответил

}

// Получить ответы игрока и проверить правильность

bool checkPlayerInput() {

for (int i = 0; i < curLen; i++) {

int expected = sequence[i];

int pressed = readButton();

// Вывод в Serial Monitor для отладки

Serial.print("Ожидается: ");

Serial.print(expected);

Serial.print(" | Нажато: ");

Serial.println(pressed);

if (pressed != expected) {

return false; // ошибка или таймаут

}

}

return true; // всё правильно

}

void loop() {

// Показываем последовательность

playSequence();

// Ждём ответ игрока

if (checkPlayerInput()) {

// Верно! Звук победы и переход на следующий уровень

beep(1000, 100);

delay(100);

beep(1500, 200);

delay(800);

// Добавляем новый элемент

sequence[curLen] = random(0, 4);

curLen++;

Serial.print("Уровень: ");

Serial.println(curLen);

} else {

// Ошибка! Эффект проигрыша

Serial.println("Проигрыш!");

beep(100, 500);

flashAll();

delay(1000);

// Начинаем заново

resetGame();

}

}

`

Разбор кода

Общие пины для кнопок и светодиодов. Главная особенность этой схемы -- кнопка и светодиод подключены к одному пину. Когда нужно зажечь светодиод, пин переключается в OUTPUT. Когда нужно прочитать кнопку -- в INPUT_PULLUP. Функции lightOn() и readButton() управляют этим переключением автоматически.

Массив `sequence[]`. Хранит до 100 случайных чисел от 0 до 3. Каждое число соответствует одному из четырёх цветов. При каждом успешном раунде к массиву добавляется новый элемент функцией random(0, 4).

Показ последовательности. Функция playSequence() проходит по массиву и для каждого элемента зажигает соответствующий светодиод на 500 мс с паузой 250 мс между элементами. Перед началом показа раздаётся короткий звуковой сигнал -- он сообщает игроку: «Внимание, запоминай!»

Чтение кнопок с антидребезгом. Механические кнопки при нажатии дают серию быстрых контактов (дребезг). Функция readButton() решает эту проблему двойной проверкой с задержкой 50 мс. Если после паузы кнопка всё ещё нажата -- значит, это реальное нажатие, а не шум.

Таймер ожидания. У игрока есть 2 секунды (PLAYER_WAIT_TIME) на каждое нажатие. Если время истекло, функция возвращает -1, что засчитывается как ошибка. Таймер реализован через millis() -- более надёжный способ, чем delay(), потому что позволяет проверять кнопки непрерывно.

Отладка через Serial Monitor. Код выводит ожидаемое и фактическое значение каждого нажатия в Serial Monitor. Это незаменимо при отладке -- если игра ведёт себя странно, открыв монитор порта, можно точно увидеть, что идёт не так.

Советы для занятий с учениками

Начните без кода. Перед сборкой поиграйте с учениками в устную версию Simon Says: один ученик показывает последовательность цветов (используя цветные карточки), другие повторяют. Это поможет понять логику игры до погружения в код.

Настройте сложность. Измените PLAYER_WAIT_TIME для разных возрастов: 3000 мс для младших классов, 1500 мс для продвинутых. Можно также уменьшать время показа каждого элемента с ростом уровня.

Соревнование в классе. Используйте Serial Monitor для отслеживания максимального уровня. Устройте турнир -- кто запомнит самую длинную последовательность. Рекорд можно сохранять в EEPROM Arduino, чтобы он не сбрасывался при выключении.

Расширение проекта. Предложите ученикам добавить LCD-дисплей для отображения текущего уровня и рекорда. Можно реализовать режим для двух игроков с поочерёдными раундами.

Как Alashed помогает

В каталоге Alashed Hardware есть готовые наборы со светодиодами, кнопками, пьезодинамиком и Arduino Uno -- всё подобрано для немедленного начала сборки. Среда Alashed CodeStudio позволяет ученикам писать код в браузере, видеть Serial Monitor онлайн и делиться проектами друг с другом, что идеально подходит для групповой работы в классе.

Попробуйте Alashed бесплатно

Подключите школу к пилоту. Генерируйте КМЖ за 2 минуты, ведите CodeStudio уроки, заказывайте оборудование — всё в одном месте.

Попробовать бесплатноДемо