Урок 11. Светильник с кнопочным управлением


 В этом уроке мы добавляем порцию яркости светодиоду одной кнопкой и убавляем другой.

Список деталей для эксперимента

Принципиальная схема

Урок 11. Светильник с кнопочным управлением. Принципиальная схема

Схема на макетке

Урок 11. Светильник с кнопочным управлением. Схема на макетке

Обратите внимание

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

Скетч

  1.     #define PLUS_BUTTON_PIN     2
    
  2.     #define MINUS_BUTTON_PIN    3
    
  3.     #define LED_PIN             9
    
  4.  
  5.     int brightness = 100
    ;
    
  6.     boolean plusUp = true
    ;
    
  7.     boolean minusUp = true
    ;
    
  8.  
  9.     void setup(
    )
    
  10.     {
    
  11.       pinMode(LED_PIN, OUTPUT)
    ;
    
  12.       pinMode(PLUS_BUTTON_PIN, INPUT_PULLUP)
    ;
    
  13.       pinMode(MINUS_BUTTON_PIN, INPUT_PULLUP)
    ;
    
  14.     }
    
  15.  
  16.     void loop(
    )
    
  17.     {
    
  18.       analogWrite(LED_PIN, brightness)
    ;
    
  19.       // реагируем на нажатия с помощью функции, написанной нами
    
  20.       plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +
    35
    )
    ;
    
  21.       minusUp = handleClick(MINUS_BUTTON_PIN, minusUp, -
    35
    )
    ;
    
  22.     }
    
  23.     // Собственная функция с 3 параметрами: номером пина с кнопкой
    
  24.     // (buttonPin), состоянием до проверки (wasUp) и градацией
    
  25.     // яркости при клике на кнопку (delta). Функция возвращает
    
  26.     // (англ. return) обратно новое, текущее состояние кнопки
    
  27.     boolean handleClick(
    int buttonPin, boolean wasUp, int delta)
    
  28.     {
    
  29.       boolean isUp = digitalRead(buttonPin)
    ;
    
  30.       if (wasUp && !isUp) {
    
  31.         delay(
    10
    )
    ;
    
  32.         isUp = digitalRead(buttonPin)
    ;
    
  33.         // если был клик, меняем яркость в пределах от 0 до 255
    
  34.         if (
    !isUp)    
  35.           brightness = constrain(brightness + delta, 0, 255
    )
    ;
    
  36.       }
    
  37.       return isUp; // возвращаем значение обратно, в вызывающий код
    
  38.     }
    

Пояснения к коду

  • Мы можем пользоваться не только встроенными функциями, но и создавать собственные. Это обоснованно, когда нам нужно повторять одни и те же действия в разных местах кода или, например, нужно выполнять одни и те же действия над разными данными, как в данном случае: обработать сигнал с цифровых портов 2 и 3.
  • Определять собственные функции можно в любом месте кода вне кода других функций. В нашем примере, мы определили функцию после loop.
  • Чтобы определить собственную функцию, нам нужно:
  1. Объявить, какой тип данных она будет возвращать. В нашем случае это boolean. Если функция только выполняет какие-то действия и не возвращает никакого значения, используйте ключевое слово void
  2. Назначить функции имя — идентификатор. Здесь действуют те же правила, что при именовании переменных и констант. Называть функции принято в том же стиле как Переменные.
  3. В круглых скобках перечислить передаваемые в функцию параметры, указав тип каждого. Это является объявлением переменных, видимых внутри вновь создаваемой функции, и только внутри нее. Например, если в данном эксперименте мы попробуем обратиться к wasUp или isUp из loop() получим от компилятора сообщение об ошибке. Точно так же, переменные, объявленные в loop, другим функциям не видны, но их значения можно передать в качестве параметров.
  4. Между парой фигурных скобой написать код, выполняемый функцией
  5. Если функция должна вернуть какое-то значение, с помощью ключевого слова 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.
Теги: 
Источник: 

Shagir.ru