Урок 12. Кнопочные ковбои


В этом уроке мы создаем игрушку на реакцию: кто быстрее нажмет кнопку по сигналу.

Список деталей для эксперимента

Принципиальная схема

Схема на макетке

Скетч

  1.     #define BUZZER_PIN   12  // пин с пищалкой
    
  2.     #define PLAYER_COUNT 2   // количество игроков-ковбоев
    
  3.     // вместо перечисления всех пинов по-одному, мы объявляем пару
    
  4.     // списков: один с номерами пинов с кнопками, другой — со
    
  5.     // светодиодами. Списки также называют массивами (англ. array)
    
  6.     int buttonPins[PLAYER_COUNT] = {
    3, 13
    }
    ;
    
  7.     int ledPins[PLAYER_COUNT] = {
    9, 11
    }
    ;
    
  8.  
  9.     void setup(
    )
    
  10.     {
    
  11.       pinMode(BUZZER_PIN, OUTPUT)
    ;
    
  12.       for (
    int player = 0
    ; player < PLAYER_COUNT; ++player) {
    
  13.         // при помощи квадратных скобок получают значение в массиве
    
  14.         // под указанным в них номером. Нумерация начинается с нуля
    
  15.         pinMode(ledPins[player], OUTPUT)
    ;
    
  16.         pinMode(buttonPins[player], INPUT_PULLUP)
    ;
    
  17.       }
    
  18.     }
    
  19.  
  20.     void loop(
    )
    
  21.     {
    
  22.       // даём сигнал «пли!», выждав случайное время от 2 до 7 сек
    
  23.       delay(random(
    2000, 7000
    )
    )
    ;
    
  24.       tone(BUZZER_PIN, 3000, 250
    )
    ; // 3 килогерца, 250 миллисекунд
    
  25.  
  26.       for (
    int player = 0
    ; ; player = (player+
    1
    ) % PLAYER_COUNT) {
    
  27.         // если игрок номер «player» нажал кнопку...
    
  28.         if (
    !digitalRead(buttonPins[player]
    )
    ) {
    
  29.           // ...включаем его светодиод и сигнал победы на 1 сек
    
  30.           digitalWrite(ledPins[player], HIGH)
    ;
    
  31.           tone(BUZZER_PIN, 4000, 1000
    )
    ;
    
  32.           delay(
    1000
    )
    ;
    
  33.           digitalWrite(ledPins[player], LOW)
    ;
    
  34.           break
    ; // Есть победитель! Выходим (англ. break) из цикла
    
  35.         }
    
  36.       }
    
  37.     }
    

Пояснения к коду

  • Массив состоит из элементов одного типа, в нашем случае int.
  • Объявить массив можно следующими способами:

  1. int firstArray[
    6
    ]
    ; // 6 целых чисел с неопределёнными начальными значениями
    
  2. int pwmPins[
    ] = {
    3, 5, 6, 9, 10, 11
    }
    ; // 6 целых чисел, длина вычисляется автоматом
    
  3. boolean buttonState[
    3
    ] = {
    false, true, false
    }
    ; // можно использовать элементы любого типа
    
  • Когда мы объявляем массив с указанием количества его элементов n, это число всегда на 1 больше, чем номер последнего элемента (n-1), т.к. индекс первого элемента — 0.
  • Считать или записать значение элемента массива можно, обратившись к нему по индексу, например firstArray[2] или buttonState[counter], где counter — переменная, такая как счетчик цикла
  • В переменных типа long можно хранить значения до 2 147 483 647. unsigned int в этом случае нам будет недостаточно, потому что 65 535 миллисекунд пройдут чуть больше чем за минуту!
  • Функция random(min, max) возвращает целое псевдослучайное число в интервале [min, max]. Для драматичности каждая игра начинается с паузы случайной длины.
  • Благодаря массивам в этом уроке мы настраиваем порты, считываем кнопки и включаем светодиоды в циклах со счетчиком, который используется как индекс элемента.
  • Мы используем цикл for без условия его завершения, поэтому пока мы явно того не потребуем, цикл будет крутиться до бесконечности.
  • Мы использовали выражение player = (player+1) % PLAYER_COUNT для счётчика цикла, чтобы не только увеличивать его на единицу каждый раз, но и обнулять при достижении последнего игрока.
  • Инструкция break прекращает работу цикла и выполнение программы продолжается с инструкции после его конца.

Вопросы для проверки себя

  • Можно ли поместить в один массив элементы типа boolean и int?
  • Обязательно ли при объявлении массива заполнять его значениями?
  • Чем удобно использование массива?
  • Как обратиться к элементу массива, чтобы прочитать его значение?
  • Почему для хранения времени прошлого сигнала мы используем переменную типа long?
  • Чем отличаются инструкции continue и break?

Задания для самостоятельного решения

  • Сделайте напряженный вариант игры: пусть интервал между сигналами будет в диапазоне от 10 до 15 секунд.
  • В игре есть лазейка: кнопку можно зажать до сигнала «пли!» и таким образом сразу же выиграть. Дополните программу так, чтобы так выиграть было нельзя.
  • Добавьте в игру еще двух ковбоев!
Теги: 
Источник: 

wiki.amperka.ru