Освой Arduino играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Измеряем скорость реакции

Попробуем измерить скорость реакции человека. В определённый момент будет включаться светодиод, а пользователю нужно как можно быстрее нажать на кнопку. Момент включения светодиода и нажатия кнопки фиксируется, разница между полученными результатами вычисляется и выводится в удобном виде.

Начнём с простой незамысловатой схемы. Нам понадобится кнопка и светодиод. Резисторы и провода являются вспомогательными деталями.

Кнопка будет подключена к питанию через нагрузочный резистор (pull-up) номиналом 10 кОм. Резистор одним выводом подключается к порту 3, другим - к источнику питания.

Светодиод подключаем к порту 13 через резистор номиналом 330 Ом или близким к нему.

Reaction schema

Общий алгоритм кода:

  • Устанавливаем паузу перед включением светодиода, чтобы предотвратить нажатие кнопки игроком до начала измерения. Паузу варьируем, чтобы игрок не приспособился
  • Запоминаем время включения
  • Запускаем таймер и ждём нажатие кнопки
  • Если кнопка нажата, то вычитаем из текущего времени таймера начальное время - получаем время реакции
  • Выводим результат игроку

int waitTime; // пауза разной величины перед включением светодиода
int startTime; // начало отсчёта
int reactionTime; // время реакции
const int ledPin = 13; // светодиод
const int buttonPin = 3; // кнопка

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop()
{
  Serial.println("Когда загорится светодиод, нажмите кнопку!");
  Serial.println("Наблюдайте за светодиодом. Готовы?");
  waitTime = random(2000, 4000); // пауза в виде случайной величины от 2000 до 4000 мс
  delay(waitTime); // делаем паузу
  digitalWrite(ledPin, HIGH); // включаем светодиод
  startTime = millis(); // запоминаем начальное время

  while (digitalRead(buttonPin) == HIGH) {  } // пустой цикл, выполняется пока не нажата кнопка

  reactionTime = millis() - startTime; // вычисляем время реакции
  digitalWrite(ledPin, LOW); // выключаем светодиод

  // Выводим результат в последовательный монитор
  Serial.print("Отлично справились! Ваше время реакции: ");
  Serial.print(reactionTime);
  Serial.println(" миллисекунд");
  delay(1000); // небольшая пауза перед новым измерением реакции
}

После загрузки скетча следует открыть последовательный монитор. В нём выводится инструкция, подготавливающая игрока к началу испытаний. Затем включается светодиод. Задача игрока как можно быстрее среагировать и нажать кнопку. Результат записывается и выводится на экран. Затем всё повторяется снова. И так до бесконечности.

Serial Monitor Reaction

Цикл while блокирует исполнение кода, пока не будет нажата кнопка. Когда кнопка будет нажата, то условие цикла выполнится и скетч выполнит код, который идёт за циклом.

Индикаторы реакции

Вывод показаний в монитор порта обычно используют в прототипах для отладки. Когда вы убедились, что основная идея работает, то следует подумать о законченной реализации тренажёра. Вместо монитора порта можно использовать дополнительные светодиоды в качестве индикаторов. Если пользователь нажал кнопку быстрее определённого значения (в нашем случае 215 миллисекунд), то включим светодиод зелёного цвета, в противном случае будем включать красный светодиод. А для сигнального светодиода используйте какой-то другой цвет, например, синий.

Схему приводить не буду, просто добавьте два светодиода с резисторами. Это не должно вызвать у вас затруднений.

Изменения в коде будут небольшими. Добавим инициализацию новых светодиодов на портах 4 и 5 и в функции loop() добавим проверку на время реакции через if..else.


int waitTime; // пауза разной величины перед включением светодиода
int startTime; // начало отсчёта
int reactionTime; // время реакции
const int ledPin = 13; // светодиод для подачи сигнала
const int buttonPin = 3; // кнопка

const int quickLed = 4; // светодиод для быстрой реакции
const int slowLed  = 5; // светодиод для медленной реакции

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  
  pinMode(quickLed, OUTPUT);
  pinMode(slowLed, OUTPUT);
}

void loop()
{
  Serial.println("Когда загорится светодиод, нажмите кнопку!");
  Serial.println("Наблюдайте за светодиодом. Готовы?");
  waitTime = random(2000, 4000); // пауза в виде случайной величины от 2000 до 4000 мс
  delay(waitTime); // делаем паузу
  digitalWrite(ledPin, HIGH); // включаем светодиод
  startTime = millis(); // запоминаем начальное время

  while (digitalRead(buttonPin) == HIGH) {  } // пустой цикл, выполняется пока не нажата кнопка

  reactionTime = millis() - startTime; // вычисляем время реакции
  digitalWrite(ledPin, LOW); // выключаем  сигнальный светодиод

  // если уложились в отведённое время, то включаем один светодиод и выключаем другой
  if (reactionTime <= 215) {
    digitalWrite(quickLed, HIGH);
    digitalWrite(slowLed, LOW);
  }
  else {
    digitalWrite(quickLed, LOW);
    digitalWrite(slowLed, HIGH);
  }

  // Выводим результат в последовательный монитор
  Serial.print("Отлично справились! Ваше время реакции: ");
  Serial.print(reactionTime);
  Serial.println(" миллисекунд");
  delay(1000); // небольшая пауза перед новым измерением реакции
}

Осталось оформить тренажёр как законченное устройство. Уложите всю схему в коробку. В коробке следует сделать три отверстия под светодиоды и одно для кнопки.

Дальше всё зависит от вашей фантазии. Вы можете добавить больше светодиодов для показа различной степени реакции: отличная, хорошая, средняя, медленная. В этом случае нужно добавить больше условий в код.

Также можно добавить вторую кнопку для второго игрока. Игра станет интереснее.

Следующий этап усложнения - добавить ЖК-экран, использовать трёхцветный светодиод и звуковые эффекты. Пищалка будет отвлекать внимание, а реагировать нужно на определённый цвет светодиода.

Реклама