Top.Mail.Ru

Подключение кнопки к Arduino. Цифровой пин в режиме входа.

Доброго времени суток! В самом разгаре курс по программированию Arduino и, как и было запланировано в предыдущей части, сегодня будем разбираться с работой порта Ардуино в режиме входа. Для тестирования используем простенькую кнопку, в скетче же будем определять, нажата она или нет. Принцип работы, схема подключения, примеры программ – ко всему этому незамедлительно и переходим 👍

Теоретическая часть.

Arduino. Порты ввода-вывода в режиме входа.

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

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

Состояние входа Напряжение
Логический 0 от -0.5 В до 1.5 В (0.3 * Vcc)
Логическая 1 от 3.0 В (0.6 * Vcc) до 5.5 В (Vcc + 0.5 В)

То есть имеем две области:

  • Первая - этот интервал соответствует логическому 0
  • Вторая - при этих значениях напряжений со входа гарантированно прочитаем единицу

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

При этом приведенные значения могут варьироваться с изменением температуры, графики можно найти в даташите на контроллер.

В данном уроке я использую плату Arduino Uno, микроконтроллер которой работает с уровнями в 5 В. Именно поэтому данная величина повсеместно и фигурирует. Соответственно, в случае платы с уровнями в 3.3 В, ситуация будет уже другая, верхнее значение будет составлять именно 3.3 В, а не 5, также изменятся и диапазоны. Эти данные можно найти в документации, либо пишите в комментарии, либо на форум, я всегда по возможности стараюсь оперативно ответить.

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

Внешний вид стандартных кнопок

В первом варианте исполнения все максимально просто - при нажатии происходит замыкание двух контактов, пока кнопка в покое - контакты разомкнуты. Второй вариант ничуть не сложнее, суть точно такая же, просто контакты соединены между собой внутри. То есть по умолчанию 1 и 4, а также 2 и 3 соединены между собой, при нажатии кнопки все ровно также, контакт 1 замыкается с контактом 2 (аналогично 3 и 4), по итогу при нажатой кнопке замкнуты будут все. Смотрим на наглядной схеме:

Контакты кнопок.

Все это по существу - одно и то же. Перейдем к конкретике, то есть к непосредственному подключению кнопки к Arduino Uno, вариантов может быть несколько:

Варианты подключения

В первом случае при нажатии кнопки происходит замыкание цифрового пина Ардуино на землю (GND). А это значит, что на входе микроконтроллера будет 0 В - низкий уровень. Напротив, во втором случае ситуация диаметрально противоположная: кнопка замыкает на 5 В, а значит на цифровом пине будет высокий уровень. Казалось бы, на этом разговор об электрической схеме можно заканчивать, но в реальности существует несколько дополнительных моментов, о которых зачастую бывает не сказано, что я категорически не одобряю.

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

Решение здесь классическое и простое, а именно использовать подтяжку.

Подтягивающий резистор.

Конечно же, досконально разберем, что это означает. Итак подтяжка осуществляется при помощи дополнительного резистора (подтягивающий резистор), который подключается одним концом к линии, а другой либо к 5 В, либо к GND. Первый вариант - подтяжка вверх, второй - подтяжка вниз, смотрим на наглядном примере:

Подключение кнопки к Ардуино

Возьмем первую из приведенных схем. Пусть кнопка не нажата, тогда получим следующую картину: из-за высокого внутреннего сопротивления входа микроконтроллера ток (I_R) между точками 1-2 очень мал. Из чего следует, что и напряжение на резисторе U_R также мало, поскольку:

U_R = I_R \cdot R_1

А из этого, в свою очередь, вытекает то, что добавленный подтягивающий резистор (R_1 ) гарантирует нам, что на входе будет высокий уровень (5 В). Это и называется подтяжкой вверх. Мысленно нажимаем кнопку и, конечно же, обстановка меняется, на входе получаем стабильные 0 В:

Подтягивающий резистор

В этом и заключается весь смысл идеи: при наличии подтягивающего резистора на цифровом входе возможны два четких варианта:

  • высокий уровень - кнопка не нажата
  • низкий уровень - кнопка нажата

Аналогичные процессы протекают и при подтяжке вниз, только в данном случае резистор подключается к GND, а нажатая кнопка замыкает на 5V. И в данном случае:

Подтягивающий резистор, подтяжка вниз
  • высокий уровень - кнопка нажата
  • низкий уровень - кнопка не нажата

Таким образом, подтягивающий резистор в данной схеме просто необходим. Номинал (значение сопротивления) не обязательно должен иметь какую-то конкретную величину. Вдаваться в нюансы, когда ставить сопротивление больше, а когда меньше, мы в этой статье не будем, возьмем «традиционное» для такого случая значение в 10 КОм:

R_1 = 10 \medspace КОм

Кроме того, Arduino Uno, а точнее микроконтроллер AVR, на базе которого и построена плата, имеет встроенные подтягивающие резисторы, которые можно легко и непринужденно задействовать (об этом в практической части), что даст возможность сэкономить и место на плате, и затраты на покупку резисторов. Но я лично почти всегда предпочитаю использовать внешние.

Токоограничивающий резистор.

При подключении кнопки есть и еще один нюанс, хотя, казалось бы, операция максимально примитивна. Рассмотрим потенциальную ситуацию…

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

Короткое замыкание

Как видите, в точке 2 потенциал равен 5 В, а в точке 1: 0 В. При этом сопротивление проводов между этими точками мало, а это автоматически означает, что по цепи потечет ток, значение которого будет велико (из-за того, что R_{wire} мало, а оно в знаменателе дроби, закон Ома):

I = \frac{5 \medspace В}{R_{wire}}

Результат максимально прост и непригляден - порт микроконтроллера будет неотвратимо уничтожен. Поэтому для исключения этого печального явления добавляется еще один резистор (R_2 ):

Arduino кнопка, схема подключения

Сопротивление этого резистора выбирается так, чтобы значение тока не превысило максимально допустимое для порта. Допустим, хотим ограничить ток величиной в 20 мА, тогда:

R_2 = \frac{5 \medspace В}{20 \medspace мА} = 250 \medspace Ом

При возникновении описанной выше ситуации с ошибочным скетчем и нажатой кнопкой, получим, что ток в цепи не превысит допустимых пределов, что позволит сохранить контроллер в целости и сохранности. На самом деле, этот резистор ставится достаточно редко, потому что предполагается, что в программе не будет допущено такой ошибки. То есть порт будет настроен как вход (что верно), а не как выход (что ошибочно). Тем не менее это следует держать в уме и при необходимости учитывать 👌

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

Схема подключения кнопки к Arduino Uno.

Подводим итог, схема приобрела такой вид:

Подключение кнопки к Ардуино

А при использовании макетной платы коммутация может производиться так:

Схема подключения кнопки к Ардуино на макетной плате.

Практическая часть.

Функция digitalRead().

Для настройки порта на работу в режиме входа используется все та же функция, что мы использовали ранее: pinMode(). Единственное отличие, что второй аргумент будет отличаться:

pinMode(3, INPUT);

Напомню, что для порта в режиме выхода было так:

pinMode(3, OUTPUT);

И здесь же можно активировать встроенный в микроконтроллер подтягивающий резистор, тогда конфигурация превратится в:

pinMode(3, INPUT_PULLUP);

Что примечательно, имеется возможность задействовать только подтяжку вверх, только так и никак иначе. Первый же аргумент везде по прежнему - номер пина платы Ардуино (в данном случае D3). С этим понятно, осталось понять, как получить значение на входе в скетче. И тут понадобится функция:

digitalRead(pin)

Один аргумент функции - номер пина, значение на входе которого нас интересует. Возвращаемое же значение может иметь два разных значения: LOW означает, что на входе низкий уровень, HIGH - высокий. Все очень логично и понятно 👍 Переходим к парочке примеров для закрепления разобранного.

Базовый пример скетча.

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

Подключение кнопки и светодиода к Arduino

И код скетча:

// Светодиод подключен к D2
int ledPin = 2;

// Кнопка - к D3
int buttonPin = 3;

void setup() 
{
  // D2 работает в качестве выхода
  pinMode(ledPin, OUTPUT);

  // D3 - в качестве входа
  pinMode(buttonPin, INPUT);
}

void loop() 
{
  // Текущее состояние кнопки
  int currentButtonState = digitalRead(buttonPin);

  if (currentButtonState == LOW)
  {
    // Кнопка нажата, зажигаем светодиод
    digitalWrite(ledPin, HIGH);
  }
  else
  {
    // Кнопка не нажата, гасим светодиод
    digitalWrite(ledPin, LOW);
  }
}

Здесь все максимально подробно и развернуто, на деле же можно значительно уменьшить размер скетча следующим образом:

// Светодиод подключен к D2
int ledPin = 2;

// Кнопка - к D3
int buttonPin = 3;

void setup() 
{
  // D2 работает в качестве выхода
  pinMode(ledPin, OUTPUT);

  // D3 - в качестве входа
  pinMode(buttonPin, INPUT);
}

void loop() 
{
  // Текущее состояние кнопки
  int currentButtonState = digitalRead(buttonPin);
  digitalWrite(ledPin, !currentButtonState);
}

Если currentButtonState равно HIGH, то соответственно !currentButtonState = LOW, таким образом можно считанное из digitalRead() значение инвертировать и сразу без лишних манипуляций передать в digitalWrite(). Компилируем и запускаем - все работает по плану: кнопка не нажата - светодиод не горит, кнопка нажата - горит.

Расширенный пример. Подключение кнопки и светодиода к Arduino.

Давайте разберем еще один пример, чуть усложненный, но тоже простой. Пусть при нажатой кнопке светодиод мигает с периодом, равным 1 секунде, а при ненажатой - 250 мс. Для этого добавим переменную currentPeriod, которая будет соответствовать нужному значению полупериода:

// Светодиод подключен к D2
int ledPin = 2;

// Кнопка - к D3
int buttonPin = 3;

// Полупериод, если кнопка нажата
int halfPeriodPressed = 500;

// Полупериод, если кнопка не нажата
int halfPeriodNotPressed = 125;

// Актуальный период
int currentPeriod = halfPeriodNotPressed;

void setup() {
  // D2 работает в качестве выхода
  pinMode(ledPin, OUTPUT);

  // D3 - в качестве входа
  pinMode(buttonPin, INPUT);
}

void loop() {
  // Текущее состояние кнопки
  int currentButtonState = digitalRead(buttonPin);

  if (currentButtonState == LOW)
  {
    // Кнопка нажата
    currentPeriod = halfPeriodPressed;
  }
  else
  {
    // Кнопка не нажата
    currentPeriod = halfPeriodNotPressed;
  }

  // Зажигаем светодиод
  digitalWrite(ledPin, HIGH);
  delay(currentPeriod);

  // Гасим светодиод
  digitalWrite(ledPin, LOW);
  delay(currentPeriod);
}

Пример, конечно, придуман исключительно в целях задействовать все пройденное в предыдущих уроках в одном скетче. На практике применимо не особо, все на примитивных задержках с delay(), тем не менее со своей демонстрационной задачей пример справляется отлично.

Снова прошиваем микроконтроллер и наблюдаем, что все работает в точности так, как и было запланировано! Поэтому мы имеем полное право завершить сегодняшний урок, до встречи в следующих частях, в ближайшей из которых займемся явлением, связанным с дребезгом контактов 🤝

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x