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

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

Шкодим

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

Кнопка

01.Basics: DigitalReadSerial (Чтение цифрового вывода)
02.Digital: Button
02.Digital: StateChangeDetection
02.Digital: Debounce (Дребезг)

Кнопки очень часто используются в электронике. На первый взгляд, работа с ними не таит сюрпризов, но и тут есть "подводные камни".

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

Button

01.Basics: DigitalReadSerial (Чтение цифрового вывода)

Изучим пример DigitalReadSerial из File | Examples | 01.Basics.

На этот раз мы научимся считывать сигнал идущий с цифрового вывода, а также добавим в схему новое устройство - кнопку.

Для опытов нам понадобятся:

  • плата Arduino Uno (или любая ваша)
  • кнопка (я использовал тактовую кнопку без фиксатора, которая шла в наборе)
  • резистор 10кОм
  • макетная плата
  • провода или перемычки

Приблизительно собранная схема может выглядеть следующим образом:

Вкратце опишу на словах данную схему. Вставляем в центре макетной платы кнопку таким образом, чтобы между парными ножками проходил жёлоб макетной платы. Далее соединяем перемычками питание 5V и землю GND на Arduino с рельсами на макетной плате. Потом соединяем перемычкой цифровой вывод под номером 2 на Arduino с одной ножкой кнопки на макетной плате. Эту же ножку кнопки, но с другой стороны соединяем с резистором, который выполняет роль подтягивающего резистора. После чего сам резистор соединяем с землёй. Третью ножку кнопки соединяем к положительной рельсе на макетной плате. Осталось только соединить между собой боковые рельсы на макетной плате, и мы готовы изучать новый пример.

Кнопка выполняет очень важную функцию - она замыкает цепь при нажатии. Когда кнопка не нажата, то ток не проходит между ножками кнопки, и не можем поймать сигнал с цифрового вывода под номером 2. Поэтому состояние вывода определяется системой как LOW или 0. При нажатии на кнопку его две ножки соединяются, позволяя току пройти от питания к цифровому выводу 2, а система считывает проходящий сигнал как HIGH или 1.

Разберём код по кусочкам


// Второй вывод связан с кнопкой
int pushButton = 2;

void setup() {
  Serial.begin(9600);
  pinMode(pushButton, INPUT);
}

void loop() {
  int buttonState = digitalRead(pushButton);
  Serial.println(buttonState);
  delay(1); // задержка для стабильности
}

В функции setup() устанавливаем связь с портом для считывания данных на скорости 9600 бит в секунду с Arduino на ваш компьютер: Serial.begin(9600).

Вторая строчка нам уже знакома, но здесь теперь используется параметр INPUT - мы устанавливаем второй цифровой вывод на режим чтения данных, поступающих с кнопки: pinMode(pushButton, INPUT);

В цикле считываем поступающую информацию. Для начала нам понадобится новая переменная buttonState, которая будет содержать значения 0 или 1, поступающие от функции digitalRead().

Чтобы мы могли видеть поступающую информацию, нужно вывести получаемые результаты в окно Serial Monitor при помощи команды println().

Для большей стабильности при чтении данных установим минимальную задержку.

Если вы сейчас запустите программу и откроете также окно Serial Monitor (меню Tools | Serial Monitor), то на экране увидите бесконечные нули. Программа постоянно опрашивает состояние нашей конструкции и выводит результат - отсутствие тока. Если нажать на кнопку и удерживать её, то увидите, что цифры сменяются с 0 на 1. Значит в нашей цепи появился ток и информация изменилась.

02.Digital: Button

Работа с кнопкой рассматривается также в примере File | Examples | 02.Digital | Button. Схема осталась прежней. Кнопка соединяется с выводом 2, а светодиод с выводом 13. К кнопке также следует подвести питание и землю через резистор на 10K. Сам принцип работы остался без изменений. Только на этот раз мы не будем выводить информацию о состоянии кнопки на экран, а будем включать светодиод. Такой вариант более наглядный. При нажатии и отпускании кнопки встроенный светодиод должен загораться или гаснуть.

Button


const int buttonPin = 2;     // вывод для кнопки
const int ledPin =  13;      // вывод для светодиода

int buttonState = 0;         // статус кнопки - нажата или отпущена

void setup() {
  // режим вывода для светодиода
  pinMode(ledPin, OUTPUT);
  // режим ввода для кнопки
  pinMode(buttonPin, INPUT);
}

void loop() {
  // считываем состояние кнопки
  buttonState = digitalRead(buttonPin);

  // если кнопка нажата, то её состояние HIGH:
  if (buttonState == HIGH) {
    // включаем светодиод
    digitalWrite(ledPin, HIGH);
  } else {
    // иначе выключаем светодиод
    digitalWrite(ledPin, LOW);
  }
}

Допустим, мы хотим изменить поведение - если кнопка не нажата - светодиод горит, а при нажатии - светодиод не горит. Достаточно изменить одну строчку кода.


if (buttonState == LOW)

А теперь загадка! Вы загрузили первый вариант скетча на плату, и вдруг ваш компьютер сломался. Вы не можете отредактировать скетч, чтобы использовать второй вариант. Как можно выйти из положения?

Нужно поменять полярность цепи! Провод от резистора, который на землю, нужно воткнуть в 5V, а провод, который шёл из 5V к кнопке, перекинуть на землю. При включении ток пойдёт из питания на вывод 2 без всяких помех и будет получено значение HIGH. При нажатии кнопки получится другая цепь, и вывод 2 останется без питания.

02.Digital: StateChangeDetection

В примере File | Examples | 02.Digital | StateChangeDetection идёт подсчёт щелчков кнопки и состояние кнопки (включён или выключен). Схема осталась прежней. Кнопка соединяется с выводом 2, а светодиод с выводом 13 (можно использовать встроенный). К кнопке также следует подвести питание и подтягивающий резистор к земле на 10K.


const int  buttonPin = 2;    // кнопка на выводе 2
const int ledPin = 13;       // светодиод на выводе 13

int buttonPushCounter = 0;   // счётчик нажатия кнопки
int buttonState = 0;         // текущее состояние кнопки
int lastButtonState = 0;     // предыдущее состояние кнопки

void setup() {
  // устанавливаем режим ввода для кнопки
  pinMode(buttonPin, INPUT);
  // устанавливаем режим вывода для светодиода
  pinMode(ledPin, OUTPUT);
  // включаем последовательную передачу данных
  Serial.begin(9600);
}


void loop() {
  // считываем показания с вывода кнопки
  buttonState = digitalRead(buttonPin);

  // сравниваем состояние с предыдущим состоянием
  if (buttonState != lastButtonState) {
    // если состояние изменилось, увеличиваем счётчик
    if (buttonState == HIGH) {
      // если текущее состояние HIGH, значит кнопка включена
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // если текущее состояние LOW, значит кнопка выключена
      Serial.println("off");
    }
    // небольшая задержка для устранения эффекта дребезга
    delay(50);
  }
  // сохраняем текущее состояние как последнее состояние для следующего раза
  lastButtonState = buttonState;

  // включаем светодиод при каждом четвёртом нажатии, проверяя деление по остатку счётчика нажатий
  if (buttonPushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
}

02.Digital: Debounce (Дребезг)

У кнопок существует такой эффект, как "дребезг". При замыкании и размыкании между пластинами кнопки возникают микроискры, провоцирующие до десятка переключений за несколько миллисекунд. Явление называется дребезгом (англ. bounce). Это нужно учитывать, если необходимо фиксировать «клики». Поэтому первичным показаниям верить нельзя. По этой причине часто в скетчах делают небольшую задержку, а уже потом считывают показания. В обычном состоянии, когда мы не нажимаем кнопку или держим кнопку нажатой, эффекта дребезга не наблюдается. Иногда для этих целей в учебных примерах используют функцию delay(), но на практике следует использовать функцию millis(), как в примере File | Examples | 02.Digital | Debounce. Схема подключения остаётся без изменений.


const int buttonPin = 2;    // кнопка на выводе 2
const int ledPin = 13;      // светодиод на выводе 13

int ledState = HIGH;         // текущее состояние светодиода
int buttonState;             // текущее состояние вывода для кнопки
int lastButtonState = LOW;   // предыдущее состояние вывода для кнопки

// используем тип без знака, чтобы использовать большие числа
unsigned long lastDebounceTime = 0;  // последнее время
unsigned long debounceDelay = 50;    // задержка, увеличьте в случае необходимости

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  digitalWrite(ledPin, ledState);
}

void loop() {
  // считываем состояние кнопки
  int reading = digitalRead(buttonPin);

  // если нажали кнопку,
  // то немного ожидаем, чтобы исключить дребезг

  // если состояние изменилось (дребезг или нажатие)
  if (reading != lastButtonState) {
    // сбрасываем таймер
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // если состояние кнопки изменилось
    if (reading != buttonState) {
      buttonState = reading;

      // переключаем светодиод, если новое состояние кнопки стало HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // устанавливаем светодиод
  digitalWrite(ledPin, ledState);

  // сохраняем состояние кнопки. В следующий раз в цикле это станет значением lastButtonState:
  lastButtonState = reading;
}

02.Digital: DigitalInputPullup (Встроенный подтягивающий резистор)

У цифровых выводов уже есть резисторы на 20 кОм, которые можно использовать в качестве подтягивающих при работе с кнопками. Рассмотрим пример File | Examples | 02.Digital | DigitalInputPullup.

Схема подключения - соединим первый вывод кнопки с выводом 2 на плате, а второй вывод кнопки с выводом GND. Во время работы скетча будем считывать показания второго вывода.

Pull-up


void setup() {
  Serial.begin(9600);
  // настроим вывод 2 на режим ввода и включим встроенный подтягивающий резистор
  pinMode(2, INPUT_PULLUP);
  pinMode(13, OUTPUT); // светодиод
}

void loop() {
  // снимаем показания кнопки
  int sensorVal = digitalRead(2);
  // выводим в Serial Monitor
  Serial.println(sensorVal);

  // Помните, что при использовании подтягивающего к питанию резистора, состояние кнопки инвертировано
  // В не нажатом состоянии кнопка имеет значение HIGH, и LOW при нажатии.
  // При нажатии на кнопку включим светодиод, при отпускании - выключим
  if (sensorVal == HIGH) {
    digitalWrite(13, LOW);
  } else {
    digitalWrite(13, HIGH);
  }
}

Если запустить скетч, то увидим, что на монитор выводятся числа 1 (HIGH). При нажатии на кнопку значения поменяются на 0 (LOW).

Реклама