===== Эксперимент 4. Кнопка и подтягивающий резистор ===== Познакомимся с кнопкой— важным электронным компонентом. Кнопка нужна везде, где требуется взаимодействие электроники с человеком. Для начала, рассмотрим, как устроена кнопка. Как можно догадаться, внутри корпуса кнопки находится пара металлических контактов. Когда кнопка находится в нормальном состоянии, ее контакты разомкнуты, а при нажатии— замыкаются. {{ :products:esp-iot:exp3.1.png?nolink |}} //Рисунок 1. Внешний вид тактовых кнопок и обозначение на электрических схемах// ==== Подключение кнопки ==== Как мы [[theory:logic_1_0|узнали ранее]], микроконтроллер оперирует с понятиями //логического нуля// и //логической единицы//, но как получить их с помощью кнопки? Логично подключить кнопку между выводом микроконтроллера и напряжением питания. Когда кнопка нажимается, напряжение питания подается на ножку, что является //логической единицей//. Такая схема изображена на рисунке 2. {{ :products:esp-iot:exp3.2.png?nolink |}} //Рисунок 2. Неправильная схема подключения кнопки// Почему же эта схема неправильная? Дело в том, что когда кнопка нажата, на ножку микроконтроллера, действительно, подается напряжение питания, что является уровнем логической единицы, однако, когда кнопка не нажата, то на ножку не подается ничего. Говорят, что она "висит в воздухе"— то есть никуда не подключена. Такое состояние не является состоянием логического нуля. Состояние такого вывода может самопроизвольно меняться, например из-за статического электричества, или даже радиоволны. Чтобы получить состояние логического нуля, нужно подключить ножку к //земле//. Так называют минус питания, "общий" провод, относительно которого и отсчитывается напряжение во всей схеме. Но как подключить кнопку, чтобы в одном состоянии она соединяла ножку с питанием, а в другом— с землей, ведь у нее только один контакт, который либо замкнут, либо разомкнут? В таком случае используют резистор, с помощью которого ножку микроконтроллера //подтягивают// к противоположному уровню. {{ :products:esp-iot:exp3.3.png?nolink |}} //Рисунок 3. Правильные схемы подключения кнопки// На рисунке 3 изображено два варианта правильного подключения кнопки. Вариант А: Когда кнопка не нажата, ножка микроконтроллера подключена к земле через резистор, что является состоянием логического нуля. Сопротивление подтягивающего резистора выбирают достаточно большим, чтобы уменьшить протекающий через него ток, например, 10 килоом. Когда кнопка нажата, вывод микроконтроллера подключается к плюсу питания, что является логической единицей. Хотя, в это же время, соединение с землей через резистор также сохраняется, но ток, протекающий через него, слишком мал, чтобы "соперничать" с прямым подключением к питанию, поэтому он не может помешать установлению логической единицы на ножке микроконтроллера. Вариант Б: Когда кнопка не нажата, ножка микроконтроллера подключена к питанию через резистор, что является состоянием логической единицы. А когда нажата— к земле, что является логическим нулем. Теперь мы знаем как правильно подключать кнопку, а из предыдущего эксперимента возьмем схему подключения светодиода. Объединим это в одну схему. ==== Схема эксперимента ==== {{ :products:esp-iot:exp3.4.png?direct |}} //Рисунок 4. Электрическая принципиальная схема эксперимента// На рисунке изображен токоограничительный резистор последовательно со светодиодом. При сборке схемы мы не будем устанавливать его сами так как он уже установлен на плате конструктора. Соберем эту схему: {{ :products:esp-iot:exp3.png?direct&600 |}} //Рисунок 5. Монтажная схема эксперимента// ==== Программный код эксперимента ==== Теперь напишем программный код. Пусть, когда кнопка не нажата, светодиод не горит. А при нажатии кнопки — горит. #define BUTTON_PIN 16 #define LED_PIN 0 bool button_state = LOW; void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT); } void loop() { button_state = digitalRead(BUTTON_PIN); if (button_state == HIGH) { digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); } } #define LED_PIN 0 #define BUTTON_PIN 16 Создаем псевдонимы номеров выводов микроконтроллера для подключения кнопки и светодиода. Кнопку подключаем к 16 выводу, светодиод к 0. bool button_state = LOW; В строке 4 мы объявляем переменную ''button_state'' типа ''bool''. Переменные в отличие от псевдонимов хранятся в памяти микроконтроллера и могут менять свое значение в процессе выполнения программы. Также в этой строке мы используем оператор присваивания ''='' для задания начального значения ''LOW'' переменной ''button_state''. Переменная типа ''bool'' может принимать только два значения 0 или 1. Также могут использоваться псевдонимы(константы) LOW/HIGH (низкий/высокий), и false/true (ложь/истина). Объявление переменной и присваивание ей значения можно записать в две строки. bool button_state; button_state = LOW; В функции ''setup()'' pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT); Настраиваем выводы микроконтроллера. Ножку для кнопки настраиваем как вход (''INPUT''), а для светодиода — как выход (''OUTPUT''). Теперь можно работать с этими выводами. В бесконечной функции ''loop()'' buttonState = digitalRead(BUTTON_PIN); if (buttonState == HIGH) { digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); } Тело цикла. Этот код повторяется бесконечное количество раз. button_value = digitalRead(BUTTON_PIN); Сначала мы считываем состояние вывода, к которому подключена кнопка, с помощью вызова функции ''digitalRead()'' и записываем это состояние в переменную ''button_value''. Если кнопка нажата, то (в соответствии со схемой на рисунке 4) на выводе микроконтроллера состояние логической единицы, значит в переменную ''button_value'' запишется ''1''. А если кнопка не нажата, на ножке логический ноль, в переменную запишется ''0''. Далее будем использовать псевдонимы для ''1'' — ''HIGH'' и ''0'' — ''LOW''. if (buttonState == HIGH) Здесь мы впервые сталкиваемся с //условным оператором//. Оператор if проверяет выполнение условия и исполняет код в зависимости от того выполнено условие или нет. Если условие выполняется, то выполняется код в блоке прямо под ним. Если условие ложно, то исполняется код в блоке ''else''. В нашем случае условием является ''button_value == HIGH''. Символ двойного равенства ''=='' это оператор сравнения. Он сравнивает значение выражения слева от себя со значением выражения справа от себя. Если эти значения равны, то равенство выполняется, иначе — нет. [[https://arduino.ru/Tutorial/Variables|Подробнее о переменных в Arduino]] [[https://arduino.ru/Reference/Assignment|Подробнее о операторе присваивания в Arduino]] [[https://arduino.ru/Reference/BooleanVariables|Подробнее о типе bool(boolean) в Arduino]] [[https://arduino.ru/Reference/Constants|Подробнее о константах в Arduino]] Подробнее об операторах [[https://arduino.ru/Reference/If|if]] и [[https://arduino.ru/Reference/else|If..else]] в Arduino Итак, в строке 13 с помощью оператора ''if'' мы проверяем выполнение условия равенства переменной button_value цифре 1. По сути это проверка нажата ли кнопка. Если да, если условие выполняется, то выполняется код digitalWrite(LED_PIN, HIGH); который зажигает светодиод. А если условие не верно, а значит кнопка не нажата, то выполняется код в блоке ''else'' digitalWrite(LED_PIN, LOW); который гасит светодиод. Теперь, когда мы разобрали каждую строку программы, взглянем опять на алгоритм целиком: программа постоянно, бесконечное количество раз, проверяет нажата ли кнопка. Если кнопка нажата, то на светодиод зажигается, если же кнопка не нажата то светодиод выключается. ==== Дополнительное задание ==== 1. Как изменить программу, чтобы наоборот, когда кнопка не нажата — светодиод светился, а если нажата — гас? 2. Как изменить электрическую схему, чтобы добиться такого же результата, но без изменения программы?