Эксперимент 11. Светильник с кнопочным управлением
← Кнопочный переключатель | Оглавление | Кнопочные ковбои →
В этом эксперименте мы добавляем порцию яркости светодиоду одной кнопкой и убавляем другой.
Список деталей для эксперимента
- 1 плата Arduino Uno
- 1 беспаечная макетная плата
- 2 тактовых кнопки
- 1 резистор номиналом 220 Ом
- 7 проводов «папа-папа»
Принципиальная схема
Схема на макетке
Обратите внимание
- Если вы переделываете схему из схемы предыдущего эксперимента, обратите внимание, что на этот раз нам нужно подключить светодиод к порту, поддерживающему ШИМ.
Скетч
- p110_plus_minus_light.ino
#define PLUS_BUTTON_PIN 2 #define MINUS_BUTTON_PIN 3 #define LED_PIN 9 int brightness = 100; boolean plusUp = true; boolean minusUp = true; void setup() { pinMode(LED_PIN, OUTPUT); pinMode(PLUS_BUTTON_PIN, INPUT_PULLUP); pinMode(MINUS_BUTTON_PIN, INPUT_PULLUP); } void loop() { analogWrite(LED_PIN, brightness); // реагируем на нажатия с помощью функции, написанной нами plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +35); minusUp = handleClick(MINUS_BUTTON_PIN, minusUp, -35); } // Собственная функция с 3 параметрами: номером пина с кнопкой // (buttonPin), состоянием до проверки (wasUp) и градацией // яркости при клике на кнопку (delta). Функция возвращает // (англ. return) обратно новое, текущее состояние кнопки boolean handleClick(int buttonPin, boolean wasUp, int delta) { boolean isUp = digitalRead(buttonPin); if (wasUp && !isUp) { delay(10); isUp = digitalRead(buttonPin); // если был клик, меняем яркость в пределах от 0 до 255 if (!isUp) brightness = constrain(brightness + delta, 0, 255); } return isUp; // возвращаем значение обратно, в вызывающий код }
Пояснения к коду
- Мы можем пользоваться не только встроенными функциями, но и создавать собственные. Это обоснованно, когда нам нужно повторять одни и те же действия в разных местах кода или, например, нужно выполнять одни и те же действия над разными данными, как в данном случае: обработать сигнал с цифровых портов 2 и 3.
- Определять собственные функции можно в любом месте кода вне кода других функций. В нашем примере, мы определили функцию после
loop
. - Чтобы определить собственную функцию, нам нужно:
- Объявить, какой тип данных она будет возвращать. В нашем случае это
boolean
. Если функция только выполняет какие-то действия и не возвращает никакого значения, используйте ключевое словоvoid
- Назначить функции имя — идентификатор. Здесь действуют те же правила, что при именовании переменных и констант. Называть функции принято в том же стиле
какПеременные
. - В круглых скобках перечислить передаваемые в функцию параметры, указав тип каждого. Это является объявлением переменных, видимых внутри вновь создаваемой функции, и только внутри нее. Например, если в данном эксперименте мы попробуем обратиться к
wasUp
илиisUp
изloop()
получим от компилятора сообщение об ошибке. Точно так же, переменные, объявленные вloop
, другим функциям не видны, но их значения можно передать в качестве параметров. - Между парой фигурных скобой написать код, выполняемый функцией
- Если функция должна вернуть какое-то значение, с помощью ключевого слова
return
указать, какое значение возвращать. Это значение должно быть того типа, который мы объявили
- Так называемые глобальные переменные, т.е. переменные, к которым можно обратиться из любой функции, обычно объявляются в начале программы. В нашем случае — это
brightness
. - Внутри созданной нами функции
handleClick
происходит всё то же самое, что в эксперименте «Кнопочный переключатель». - Поскольку при шаге прироста яркости 35 не более чем через восемь нажатий подряд на одну из кнопок значение выражения
brightness + delta
выйдет за пределы интервала [0, 255]. С помощью функцииconstrain
мы ограничиваем допустимые значения для переменнойbrightness
указанными границами интервала. - В выражении
plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +35)
мы обращаемся к переменнойplusUp
дважды. Поскольку=
помещает значение правого операнда в левый, сначала вычисляется, что вернетhandleClick
. Поэтому когда мы передаем ейplusUp
в качестве параметра, она имеет еще старое значение, вычисленное при прошлом вызовеhandleClick
. - Внутри
handleClick
мы вычисляем новое значение яркости светодиода и записываем его в глобальную переменнуюbrightness
, которая на каждой итерацииloop
просто передается вanalogWrite
.
Вопросы для проверки себя
- Что необходимо для определения собственной функции?
- Что означает ключевое слово
void
? - Как ведет себя программа при упоминании одной переменной с разных сторон от оператора присваивания
=
?
Задания для самостоятельного решения
- Доработайте код таким образом, чтобы шаг изменения яркости настраивался в одном месте.
- Создайте еще одну функцию и переделайте код так, чтобы одна функция отвечала за отслеживание нажатий, а другая — за вычисление яркости светодиода и возвращала его в
analogWrite
.