Espruino:Примеры/Использование кнопки BTN1 на Espruino для включения светодиода

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Использование кнопки BTN1 на Espruino для включения светодиода[1]

Плата Espruino, помимо прочего, оснащена кнопкой BTN1. И в этом руководстве мы расскажем, как использовать её для включения светодиода, а также о нескольких подводных камнях, с которыми можно столкнуться при использовании этой кнопки.

Подсоединение

Мы воспользуемся встроенными светодиодами и кнопкой Espruino, так что ничего подключать не нужно.

Код

Давайте начнём с самого простого – с включения светодиода LED1:

LED1.write(1);

Далее давайте создадим функцию, которая будет менять состояние светодиода LED1 с «вкл» на «выкл» и наоборот:

var next_state = 1;
function swap() {
  LED1.write(next_state);
  next_state = !next_state;
}

Теперь мы можем просто написать swap() и светодиод включится, если был выключен, и выключится, если был включен. Следующий шаг – организовать «слежку» за кнопкой, чтобы узнать, нажали на неё или нет. Для этого мы воспользуемся функцией setWatch(). Но она будет срабатывать дважды – когда пользователь будет нажимать на кнопку и когда будет её отпускать. Но нам нужно, чтобы состояние светодиода менялось только при нажатии на кнопку, поэтому нам нужна ещё одна функция:

function swap_on_down() {
  if (digitalRead(BTN1) == 1) swap();
}

Это очень простая функция – она лишь проверяет, нажата кнопка BTN1 или нет. Поэтому она не будет вызывать функцию swap(), когда пользователь/пользовательница уберёт свой палец от кнопки. Как раз то, что нам нужно! Теперь мы можем воспользоваться setWatch(), чтобы с её помощью вызывать swap_on_down():

setWatch(swap_on_down, BTN1, true);

Последним аргументом в функции выше стоит true – благодаря этому setWatch() будет вызывать swap_on_down() при каждом нажатии на кнопку, а не только в первый раз. Попробуйте ввести эту функцию – в результате красный светодиод будет включаться и выключаться каждый раз, когда вы будете нажимать на кнопку.

Кроме того, мы можем поиграться с разными цветами. Идея в том, чтобы при первом нажатии на кнопку загорался красный светодиод, при втором – зелёный, при третьем – синий, а при четвёртом – снова красный и так далее. Мы также добавим код, благодаря которому все светодиоды выключатся, если пользователь перестанет нажимать на кнопку в течение 5 секунд.

// Здесь будет храниться индикатор светодиода:
var next_LED = 1;
// ID таймаута (см. ниже): 
var timeout_ID = 0;
function swap() {
  // Удаляем таймаут для выключения светодиодов,
  // когда пользователь нажимает на кнопку:
  clearTimeout(timeout_ID);
  // Определяем, какой светодиод включить/выключить:
  switch(next_LED) {
    case 1:
      LED1.write(1);
      LED3.write(0);
      break;
    case 2:
      LED2.write(1);
      LED1.write(0);
      break;
    case 3:
      LED3.write(1);
      LED2.write(0);
      break;
  }
  // Определяем, какой светодиод нужно включить следующим:
  next_LED = Math.wrap(next_LED, 3) + 1;
  // Обнуляем таймаут для выключения всех светодиодов,
  // чтобы его можно было использовать 
  // при следующем вызове этой функции: 
  timeout_ID = setTimeout(function () { LED1.write(0); LED2.write(0); LED3.write(0); }, 5000);
}

Как видите, всё работает как и задумывалось, но иногда возвращает ошибку ERROR: Unknown Timeout (когда все светодиоды выключены). Это отличный повод поизучать наш код и немного его улучшить. Давайте начнём с ошибки.

Исправить её можно, написав var timeout_ID = undefined вместо var timeout_ID = 0. Кроме того, мы можем сделать так, чтобы таймаут удалялся, только если его значением будет undefined:

  if (timeout_ID !== undefined) {
    clearTimeout(timeout_ID);
  }

Для сравнения с undefined важно использовать именно !==, а не !=. Код выше работает, потому что ID, сгенерированный при установке таймаута, может быть «0», но никогда не будет задан как undefined. В принципе, мы можем ещё сильнее упростить код и просто написать var timeout_ID;, т.к. эта переменная всё равно будет инициализирована со значением undefined. Но мы ещё не закончили. Нам надо отредактировать функцию setTimeout(), чтобы после истечения таймаута, его значение было задано на undefined. В результате это...

  timeout_ID = setTimeout(function () { LED1.write(0); LED2.write(0); LED3.write(0); }, 5000);
``

...станет этим:

timeout_ID = setTimeout(function () { LED1.write(0); LED2.write(0); LED3.write(0); timeout_ID = undefined; }, 5000); ``

Наконец, в языке Espruino есть функция, позволяющая задать прерывание только на возрастающем сигнале. Это как раз то, что нам нужно, и даже избавит нас от необходимости использовать функцию swap_on_down(). Мы можем просто написать следующее:

setWatch(swap, BTN1, {repeat:true, edge:"rising"});

То есть нам теперь не нужно вызывать функцию swap_on_down() – мы просто напрямую вызовем функцию swap(). Весь код полностью в итоге выглядит вот так:

// Здесь будет храниться индикатор светодиода:
var next_LED = 1;
// ID таймаута (см. ниже):
var timeout_ID;
function swap() {
  // Удаляем таймаут для выключения светодиодов,
  // когда пользователь нажимает на кнопку:
  if (timeout_ID !== undefined) {
    clearTimeout(timeout_ID);
  }
  // Определяем, какой светодиод включить/выключить:
  switch(next_LED) {
    case 1:
      LED1.write(1);
      LED3.write(0);
      break;
    case 2:
      LED2.write(1);
      LED1.write(0);
      break;
    case 3:
      LED3.write(1);
      LED2.write(0);
      break;
  }
  // Определяем, какой светодиод нужно включить следующим:
  next_LED = Math.wrap(next_LED, 3) + 1;
  // Обнуляем таймаут для выключения всех светодиодов,
  // чтобы его можно было использовать
  // при следующем вызове этой функции:
  timeout_ID = setTimeout(function () { LED1.write(0); LED2.write(0); LED3.write(0); timeout_ID = undefined; }, 5000);
}

См.также

Внешние ссылки