Блок с датойБлок с временемБлок с возрастом сайта
Mr.ALB

    Анатолий Беляев (aka Mr.ALB). Персональный сайт

    Да пребудут с вами Силы СВЕТА!

     

    Ардуино (Arduino). #2

    Управляем кодом программы через внешнюю кнопку

    В прошлом примере #1, на предыдущей странице, предложил совместить в скетче два варианта управления светодиодом. Получается, что добавив внешнюю кнопку, по её нажатию, мы будем управлять кодом скетча (программы). Ниже рассмотрим этот пример.


    Схема 1

    Начнём с того, что добавим в схему ещё кнопку SB2, сигнал с который мы будем подавать на pin4. Для этой кнопки так же добавим стягивающий резистор R3 на 10...18 кОм. Схема представлена на рисунке ниже.

    Схема 1 для скетча #2
    Pic 1. Схема 1 для скетча #2


    Схема 2

    Как и в предыдущем уроке #1 воспользуемся инверсной логикой управления и под неё изменим схему. Как видим ниже, схема упростилась на два резистора: R1, R3.

    Схема 2 для скетча #2
    Pic 2. Схема 2 для скетча #2


    Реализация

    Реализуем схему 1. Кнопка SB2 одним контактом подключена к +5V, а второй контакт к стягивающему резистору R3. От их соединения идёт подключение к контакту pin4. Второй свободный вывод резистора R3 подключен к контакту GND. Светодиод VD1(HL1) подключаем через ограничивающий резистор 330...1000 Ом.

    Реализация скетча #2
    Pic 3. Реализация скетча #2

    Скетч 1

    Всё, подключения сделаны, переходим к программе.

    Добавим в скетч переменную switchPin, которая будет определять pin для управления режимами работы светодиода.

    Добавим переменные currentSwitch и lastSwitch для хранения состояния этой переключающей кнопки. Добавим переменную flag, через неё мы будем переключать код программы.

    В настроечную функцию setup() добавим инициализацию новой кнопки, определив её как вход (INPUT). В рабочей функции loop() мы совместим коды разных режимов работы светодиода.

    В начале работы функции loop() мы опрашиваем кнопку выбора режима, и если она была нажата, то выбираем тот код программы, который будет задавать определённый режим работы кнопки SB1, управляющей работой светодиода.

    Так как у нас всего два режима работы светодиода, то достаточно использовать конструкцию if-else.

    Вот полный скетч, его можно скопировать и вставить в свой Arduino IDE:

    /*************************************************************
     * 2018-03-11 Mr.ALB Тренировка в программировании Ардуино
     *************************************************************/
    // Переменные с пинами подключенных устройств
    int buttonPin = 2;// Подключаем кнопку SB1 на 2-й pin
    int switchPin = 4;// Подключаем кнопку SB2 на 4-й pin
    // Подключаем светодиод на 5-й pin, можно на любой с PWM
    int ledPin = 5;
    
    // Переменные для хранения состояния кнопки и светодиода
    boolean lastButton = LOW;
    boolean currentButton = LOW;
    boolean lastSwitch = false;
    boolean currentSwitch = false;
    boolean flag = false;// Изначально установлен 1-й режим
    int ledLevel = 0;
    
    // Настройка изменения яркости
    int deltaLevel = 10; // Шаг изменения яркости
    int sign = 1;        // Знак шага
    int step_delay = 120;// Здержка в шаге изменения яркости светодиода
    
    // Настройка сигнализатора окончания изменения яркости
    // Число морганий светодиода на pin13 (LED_BUILTIN)
    int max_blink = 3;
    // Задержка состояния светодиода, немного уменьшил
    int blink_delay = 250;
    
    /*************************************************************
     * Настроечная функция, выполняется один раз вначале
     *************************************************************/
    void setup()
    {
     pinMode(buttonPin, INPUT);
     pinMode(switchPin, INPUT);// Pin устанавливаем как вход
     pinMode(ledPin, OUTPUT);
     pinMode(LED_BUILTIN, OUTPUT);
    // Потушим светодиод на pin13 (LED_BUILTIN)
     digitalWrite(LED_BUILTIN, LOW);
    }
    
    /*************************************************************
     * При нажатии на кнопку SB1:
     * Режим 1: Светодиод медленно увеличивает яркость
     *          При повторном нажатии на кнопку,
     *          светодиод медленно гаснет.
     * Режим 2: Светодиод медленно увеличивает яркость до максимума,
     *          а затем уменьшает яркость до полного потухания.
     * При нажатии на кнопку SB2 
     * происходит смена режимов действия кнопки SB1
     *
     *************************************************************/
    void loop()
    {
     // Опрос кнопки SB2
     currentSwitch = fn_debounce(lastSwitch,switchPin);
     // Переключаем режимы работы программы
     if(lastSwitch == LOW && currentSwitch == HIGH)
     {
      if(flag == false) flag = true;
      else flag = false;
      // Сигнализируем о смене режима программы
      fn_blink(1, blink_delay);
     }
     // Опрос кнопки SB1
     currentButton = fn_debounce(lastButton,buttonPin);
     // Управляем работой светодиода по указанному режиму
     if(lastButton == LOW && currentButton == HIGH)
     {
      if(flag)
      {
        if(ledLevel == 0) sign = 1;
        if(ledLevel == 255) sign = -1;
        // Изменяем яркость светодиода
        fn_stepBrightness(step_delay,deltaLevel,sign);
      }
      else
      {
        fn_stepBrightness(step_delay,deltaLevel,1);// Зажигается
        fn_stepBrightness(step_delay,deltaLevel,-1);// Тухнет
      }
      // Сигнализируем об окончании изменения
      fn_blink(max_blink, blink_delay);
     }
     lastButton = currentButton;// Переписываем состояние кнопки SB1
     lastSwitch = currentSwitch;// Переписываем состояние кнопки SB2
    }
    
    /*************************************************************
     * Функция для подавления дребезга
     * Модифицирована, добавлен опрос конкретного pin-а
    *************************************************************/
    boolean fn_debounce(boolean last,int btnPin)
    {
     // Читаем состояние кнопки
     boolean current = digitalRead(btnPin);
     if(last != current)
     {
      delay(5);
      current = digitalRead(btnPin);
     }
     return current;
    }
    
    /*************************************************************
     * Функция сигнализации окончания цикла
     * изменения яркости светодиода
    *************************************************************/
    void fn_blink(int blink_max, int blink_delay)
    {
     for(int i = 0; i < blink_max; i++)
     {
      digitalWrite(LED_BUILTIN, HIGH);
      delay(blink_delay);
      digitalWrite(LED_BUILTIN, LOW);
      delay(blink_delay);
     }
    }
    
    /*************************************************************
     * Функция изменения яркости светодиода
    *************************************************************/
    void fn_stepBrightness(int step_delay, int deltaLevel, int sign)
    {
     for(int i = 0; i < (int(256 / deltaLevel) + 1); i++)
     {
      ledLevel = ledLevel + deltaLevel * sign;
      // Ограничиваем диапазон значений
      ledLevel = constrain(ledLevel, 0, 255);
      delay(blink_delay);
      analogWrite(ledPin, ledLevel);
      delay(step_delay);
     }
    }
    

    Как вы видели, в скетче немного модифицировал функцию устранения дребезга debounse в fn_debounce, добавил ещё один аргумент для указания какой pin опрашивать, так как у нас уже две кнопки, а в дальнейшем их может быть много.

    Можно представленный скетч модернизировать: режимы работы кнопки выделить в отдельные функции, или в одну функцию с аргументом выбора режима. Тогда вызывая её в loop(), и определяя номер режима, можно создать очень много режимов работы светодиода или какого другого исполнительного механизма. Конечно, в таком случае портебуется использовать не конструкцию if-else, а, к примеру, switch, и тип переменной flag определить как int.


    Скетч 2

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

    /**********************************************************************
       2018-03-11 Mr.ALB Тренировка в программировании Ардуино
                  Скетч 2.1
       2022-05-17 Mr.ALB Использование инверсной логики
                  Скетч 2.2
       ПОДКЛЮЧЕНИЕ:
        R2    - pin5
        HL1 A - R2
        HL1 k - GND
        SB1   - pin2 и GND
        SB1   - pin4 и GND
    
      Архив: https://disk.yandex.ru/d/Hs0uEvqfGNxcwQ
    
      2022-05-17 Скетч использует 1886 байт
    **********************************************************************/
    #define BT1_PIN   2   // Подключаем кнопку SB1 на 2-й pin
    #define BT2_PIN   4   // Подключаем кнопку SB2 на 4-й pin
    #define LED_PIN   5   // Подключаем светодиод на 11-й pin,
    ;                     // можно на любой с PWM
    #define MAX_BLINK 3   // Число морганий светодиода LED_BUILTIN
    
    // Переменные для хранения состояния кнопки и светодиода
    // Не активное состояние = HIGH
    // Активное состояние    = LOW
    bool lastButton     = HIGH;
    bool currentButton  = HIGH;
    bool lastSwitch     = HIGH;
    bool currentSwitch  = HIGH;
    byte mode = 1;          // Изначально установлен 1-й режим
    int ledLevel = 0;
    
    // Настройка изменения яркости
    byte deltaLevel = 10;   // Шаг изменения яркости
    bool sign = true;       // Знак шага
    // Здержка в шаге изменения яркости светодиода
    unsigned int step_delay = 120;
    
    // Настройка сигнализатора окончания изменения яркости
    // Задержка состояния светодиода на pin13
    unsigned int blink_delay = 250;
    
    /**********************************************************************
       Настроечная функция, выполняется один раз вначале
    **********************************************************************/
    void setup()
    {
      pinMode(BT1_PIN, INPUT_PULLUP);  // Pin устанавливаем как вход_
      pinMode(BT2_PIN, INPUT_PULLUP);  // с подтяжкой к +5V
      pinMode(LED_PIN, OUTPUT);
      pinMode(LED_BUILTIN, OUTPUT);
      // Потушим светодиод на pin13 (LED_BUILTIN)
      digitalWrite(LED_BUILTIN, LOW);
    }
    
    /**********************************************************************
       При нажатии на кнопку SB1:
       Режим 1: Светодиод медленно увеличивает яркость
                При повторном нажатии на кнопку, светодиод медленно гаснет.
       Режим 2: Светодиод медленно увеличивает яркость до максимума,
                а затем уменьшает яркость до полного потухания.
       При нажатии на кнопку SB2 происходит смена
       режимов действия кнопки SB1
    
    **********************************************************************/
    void loop()
    {
      // Опрос кнопки SB2
      currentSwitch = fnDebounce(lastSwitch, BT2_PIN);
      // Переключаем режимы работы программы
      if (lastSwitch == HIGH && currentSwitch == LOW)
      {
        if (mode == 1) mode = 2;
        else mode = 1;
        fnBlink(1, blink_delay);// Сигнализируем о смене режима программы
      }
    
      // Опрос кнопки SB1
      currentButton = fnDebounce(lastButton, BT1_PIN);
    
      // Управляем работой светодиода по указанному режиму
      if (lastButton == HIGH && currentButton == LOW)
      {
        fnBlink(1, blink_delay);   // Сигнал нажатия кнопки
        if (mode == 1)
        {
          if (ledLevel == 0)   sign = true;
          if (ledLevel == 255) sign = false;
          // Изменяем яркость светодиода
          fnStepBrightness(step_delay, deltaLevel, sign);
        }
        else
        {
          fnStepBrightness(step_delay, deltaLevel, true);  // Зажигается
          fnStepBrightness(step_delay, deltaLevel, false); // Тухнет
        }
        
        // Сигнализируем об окончании изменения
        fnBlink(MAX_BLINK, blink_delay);
      }
      lastButton = currentButton;// Переписываем состояние кнопки SB1
      lastSwitch = currentSwitch;// Переписываем состояние кнопки SB2
    }
    
    /**********************************************************************
       Функция для подавления дребезга
       Модифицирована, добавлен опрос конкретного pin-а
    **********************************************************************/
    boolean fnDebounce(boolean last, byte btnPin)
    {
      boolean current = digitalRead(btnPin);  // Читаем состояние кнопки
      if (last != current)
      {
        delay(10);
        current = digitalRead(btnPin);
      }
      return current;
    }
    
    /**********************************************************************
      Функция сигнализации окончания цикла изменения яркости светодиода
        blink_max    - сколько мигнуть
        blink_delay  - задержка в мс
    **********************************************************************/
    void fnBlink(int blink_max, int blink_delay)
    {
      for (byte i = 0; i < blink_max; i++)
      {
        digitalWrite(LED_BUILTIN, HIGH);
        delay(blink_delay);
        digitalWrite(LED_BUILTIN, LOW);
        delay(blink_delay);
      }
    }
    
    /***********************************************************
      Функция изменения яркости светодиода
        step_delay  - Задержка в мс на шаг
        deltaLevel  - На сколько изменить за шаг
        sign        - Знак уменьшение/увеличение:
                        если = true  умножаем на 1
                        если = false умножаем на -1
     ***********************************************************/
    void fnStepBrightness
    (
      unsigned int step_delay,
      byte deltaLevel,
      bool sign
    )
    {
      for (byte i = 0; i < (byte(256 / deltaLevel) + 1); i++)
      {
        ledLevel = ledLevel + deltaLevel * ((sign == true) ? 1 : -1);
        // Ограничиваем диапазон значений
        ledLevel = constrain(ledLevel, 0, 255);
        analogWrite(LED_PIN, ledLevel);
        delay(step_delay);
      }
    }
    

    Для уменьшения кода и более изящной конструкции в скетче применяем функцию ограничения диапазона для переменной ledLevel.

      // Ограничиваем диапазон значений
      ledLevel = constrain(ledLevel, 0, 255);
    

    На первых двух страницах раздела показываю как можно использовать кнопки и объясняю два типа логики: 1 - Прямая, где управляющий сигнал высокого уровня (HIGH) и 2 - Инверсная, где управляющий сигнал низкого уровня (LOW). Какой логикой пользоваться ваш выбор, замечу, что промышленные контроллеры чаще всего используют инверсную логику. Сам я использую разную, но инверсная, как мы видели, требует меньше ресурсов (в нашем случае меньше резисторов).


    Приложение

    Программы для повторения:


    .
    ©Mr.ALB
    Предыдущая страница Страница 3 Далее