Привет! Этот проект стал для меня важным шагом в мир : первое устройство с полностью собственной печатной платой, спроектированной с нуля в KiCad. Ранее я экспериментировал с готовыми модулями Arduino и макетными платами, но захотелось перейти к компактному, автономному решению на «голом» микроконтроллере.
Я новичок в проектировании PCB-устройств, так что могу ошибаться в некоторых нюансах. Хотя у меня уже есть большой опыт в электротехнике, с хорошим знанием схемотехники и прочего, если заметите неточности или улучшения — не стесняйтесь, указывайте в комментариях, буду рад конструктивной критике!
Получилась миниатюрная игра на реакцию для двух игроков на базе ATmega328P. Устройство питается от одной батарейки CR2032 (3 В), работает на внутреннем RC-генераторе 8 МГц и не требует внешнего кварца или стабилизатора напряжения. Проект доступен на GitHub.
В этой статье я разберу механику игры, выбор компонентов, разработку прошивки (с кодом), прототипирование, проектирование PCB и сборку. Давайте разберёмся по шагам.

Правила игры
Игра предназначена для двух игроков. У каждого — своя кнопка и индикаторный светодиод. Центральный светодиод сигнализирует о старте раунда.
-
Подготовка: Центральный LED мигает три раза коротко — сигнал готовности.
-
Задержка: Случайная пауза от 1 до 5 секунд (генерируется с помощью
random()на основе аналогового шума). -
Старт: Загорается центральный LED — игроки должны как можно быстрее нажать свою кнопку. Первый, кто успел, получает очко; его индикатор загорается на 1 секунду.
-
Анти-чит: Если во время ожидания игрок нажимает кнопку более двух раз, он блокируется на текущий раунд (чтобы избежать "спама").
-
Продолжительность раунда: 5 секунд на реакцию после сигнала.
-
Матч: Игра идёт до 3 очков. Победа отмечается пятью быстрыми миганиями индикатора победителя.
-
Сброс: После матча счёт автоматически сбрасывается, и игра готова к новому раунду.
Механика простая — требует хорошей реакции и внимания. В версии 2.0 (в разработке) добавлены по три LED на игрока для визуализации счёта (загораются последовательно и остаются гореть до конца матча).

Выбор компонентов
Я стремился к минимализму: низкое потребление энергии, компактность и дешевизна. Питание от CR2032 (3 В) идеально подходит — ATmega328P стабильно работает на этой напруге с внутренним тактированием 8 МГц (без внешнего кварца, чтобы сэкономить место и ток).
Компоненты для версии 1.0:
-
ATmega328P — 1 шт.
-
Тактовые кнопки 6×6 мм — 2 шт.
-
Светодиоды 0805 — 3 шт.
-
Резисторы 330 Ом (для ограничения тока LED) — 3 шт.
-
Резистор 10 кОм (pull-up для кнопок или сброса) — 1 шт.
-
Конденсатор 1 мкФ (для фильтрации питания) — 1 шт.
-
Держатель батарейки CR2032 — 1 шт.
-
Миниатюрный выключатель питания — 1 шт. (опционально, для удобства).
Стоимость комплекта — около 350–450 рублей. Для версии 2.0 добавляются дополнительные LED (по 3 на игрока) и резисторы (всего 7 шт. 330 Ом).
В схеме использованы минимальные внешние компоненты: нет регуляторов напряжения, нет внешнего reset'а (используется внутренний pull-up). Кнопки подключены с debounce в коде.

Шаг 1: Разработка прошивки и программирование
Прошивка написана в Arduino IDE на C++ (используются только базовые функции, без библиотек). Это позволило быстро прототипировать логику, а затем скомпилировать в чистый HEX для "голого" AVR.
Ключевые особенности кода:
-
Рандомизация задержки:
random(1000, 5000)с сидом от аналогового пина. -
Debounce кнопок: простая задержка в 20 мс.
-
Анти-чит: счётчик ложных нажатий.
-
Энергосбережение: использование
sleep_mode()в будущем (в v1.0 не реализовано полностью). -
Fuse-биты: Low = 0xE2 (внутренний 8 МГц, без делителя).
Полный код для v1.0 (из GitHub: /src/v1/reaction_game_v1.ino):
// reaction_game_v1.ino
#define LED_CENTER 13 // Центральный LED (PB5)
#define LED_P1 12 // LED Player 1 (PB4)
#define LED_P2 11 // LED Player 2 (PB3)
#define BTN_P1 2 // Кнопка Player 1 (PD2)
#define BTN_P2 3 // Кнопка Player 2 (PD3)
int scoreP1 = 0;
int scoreP2 = 0;
int falsePressP1 = 0;
int falsePressP2 = 0;
bool blockedP1 = false;
bool blockedP2 = false;
void setup() {
pinMode(LED_CENTER, OUTPUT);
pinMode(LED_P1, OUTPUT);
pinMode(LED_P2, OUTPUT);
pinMode(BTN_P1, INPUT_PULLUP);
pinMode(BTN_P2, INPUT_PULLUP);
randomSeed(analogRead(0)); // Сид для рандома
}
void loop() {
resetRound(); // Сброс раунда
// Сигнал готовности: 3 мигания
for (int i = 0; i < 3; i++) {
digitalWrite(LED_CENTER, HIGH);
delay(200);
digitalWrite(LED_CENTER, LOW);
delay(200);
}
// Случайная задержка
delay(random(1000, 5000));
// Старт: зажигаем центр
digitalWrite(LED_CENTER, HIGH);
unsigned long startTime = millis();
while (millis() - startTime < 5000) { // 5 сек на реакцию
checkFalsePresses(); // Проверка анти-чита
if (!blockedP1 && digitalRead(BTN_P1) == LOW) {
scoreP1++;
digitalWrite(LED_P1, HIGH);
delay(1000);
digitalWrite(LED_P1, LOW);
checkWin();
break;
}
if (!blockedP2 && digitalRead(BTN_P2) == LOW) {
scoreP2++;
digitalWrite(LED_P2, HIGH);
delay(1000);
digitalWrite(LED_P2, LOW);
checkWin();
break;
}
delay(20); // Debounce
}
digitalWrite(LED_CENTER, LOW);
}
void resetRound() {
falsePressP1 = 0;
falsePressP2 = 0;
blockedP1 = false;
blockedP2 = false;
}
void checkFalsePresses() {
if (digitalRead(BTN_P1) == LOW) {
falsePressP1++;
if (falsePressP1 > 2) blockedP1 = true;
delay(20);
}
if (digitalRead(BTN_P2) == LOW) {
falsePressP2++;
if (falsePressP2 > 2) blockedP2 = true;
delay(20);
}
}
void checkWin() {
if (scoreP1 >= 3) {
for (int i = 0; i < 5; i++) {
digitalWrite(LED_P1, HIGH);
delay(100);
digitalWrite(LED_P1, LOW);
delay(100);
}
scoreP1 = 0;
scoreP2 = 0;
} else if (scoreP2 >= 3) {
for (int i = 0; i < 5; i++) {
digitalWrite(LED_P2, HIGH);
delay(100);
digitalWrite(LED_P2, LOW);
delay(100);
}
scoreP1 = 0;
scoreP2 = 0;
}
}
Процесс прошивки:
-
Скомпилировать в Arduino IDE → получить .hex.
-
Использовать программатор T48 .
-
Записать HEX и fuse-биты.

Шаг 2: Прототипирование на макетной плате
С прошитым чипом собрал схему на breadboard: ATmega в панельке, кнопки и LED по пинам, питание от CR2032 или лабораторного БП (3 В).
Тестировал:
-
Стабильность на 3 В (ток в idle ~1 мА).
-
Рандомизацию (без повторяющихся паттернов).
-
Анти-чит и debounce (чтобы избежать ложных срабатываний).
После отладки — переход к PCB.

Шаг 3: Проектирование платы в KiCad
Первый опыт полноценного дизайна в KiCad. Шаги:
-
Eeschema: Нарисовал схему (простая: MCU + LED + кнопки + пассивка).
-
Pcbnew: Разводка трасс (2 слоя, минимальные зазоры 0.25 мм). Учитывал компактность.
-
3D-viewer: Визуализация для проверки (см. рендер на GitHub: images/v1/3D Model.png).
-
Генерация Gerber-файлов.
Схема (из GitHub: images/v1/Schematic.png):
Шаг 4: Заказ плат и сборка
Gerber загрузил на PCBWay: 2 слоя, чёрная маска, HASL, 1.6 мм, 5 шт. Стоимость с доставкой ~2160 руб. (пришли через 2,5 месяца).

Пайка: Ручная, SMD .

Первый опыт — не идеально, но плата заработала почти с первого раза.

Итог и планы
Проект дал опыт полного цикла: от идеи до готового устройства. Узнал нюансы AVR, KiCad, пайки SMD. Теперь увереннее в embedded.
В v2.0: Три LED на игрока для счёта, улучшенная шелкография. Есть один нюанс, который я не исправил : неправильное расположение кнопок на PCB — футпринт оказался перевернутым.
Если статья полезна — лайкните, подпишитесь или оставьте комментарий. Вопросы по коду или схеме — в issues репозитория. Удачи в ваших проектах! 🚀

Автор: Pelectronik
