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

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

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

     

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

    Управляем гирляндами

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

    В скетче, который рассмотрим на этой странице, будет использование аппаратного прерывания для считывания кнопки, а так же используем ШИМ (PWM), как в предыдущем примере, для управления яркостью некоторых гирлянд.

    Так как хочу использовать кнопку для выбора светового эффекта, то потребуется устранить дребезг контактов этой кнопки. В данном случае, раз мы её будем использовать через прерывания, то для уменьшения кода имеет смысл сделать схему аппаратного устранения дребезга. Для этих целей использовал операционный усилитель LM358P. Эта микросхема не дорогая, доступная, имеет корпус DIP8 и обладает пониженным энергопотреблением. Её удобно использовать, и в одном корпусе имеется два операционных усилителя, что удобно, если использовать две кнопки (для возможного расширения функций в будущем).

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

    Чтобы устранить множественность импульсов, которые даёт кнопка при её нажатии и отпускании, использую интегрирующий конденсатор, который установим параллельно кнопке. Сигнал с этого конденсатора подадим на инвертирующий вход ОУ (контакт 2).

    Принцип работы триггера Шмитта поясняется на картинке Pic 1. Когда нажимается кнопка SB, то напряжение на конденсаторе C быстро разряжается через контакты кнопки. При достижении на нём уровня TL, выходное напряжение на триггере переходит в высокое состояние. При отпускании кнопки, конденсатор C начинает относительно медленно заряжаться через резистор R до уровня напряжения питания. Когда напряжение на нём достигнет уровня TH, то на выходе триггера напряжение скачком перейдёт в низкое значение. Дребезг контактов кнопки в виде пачки импульсов на включении и выключении сглаживается за счёт инерции заряда конденсатора, что не даёт напряжению на входе инвертора достигнуть порога TH и тем самым переключить выход триггера в другое состояние.

    Принцип работы триггера Шмитта
    Pic 1. Принцип работы триггера Шмитта

    Для реализации схемы триггера Шмитта на ОУ потребуется:

    1. Резистор 10k...24k (подтягивающий к +5V)
    2. Резистор 12k
    3. Резистор 24k
    4. Конденсатор 0.1uF...1uF на напряжение больше 5V
    5. Микросхема LM358P

    Ниже на рисунке два типа включения LM358. На типе a) ближе к монтажной схеме, где операционный усилитель представлен DIP корпусом, а на типе b) — уже электрическая принципиальная схема.

    Подавитель дребезга кнопки
    Pic 2. Подавитель дребезга кнопки

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

    В этом примере, в качестве гирлянд, использую одиночные светодиоды, которые можно подключить к выходам 3,4,5,6,7 через резисторы 330...1000 Ом. Конечно, для подключения реальной светодиодной гирлянды потребуется сделать силовую часть схемы, на которую будут поступать сигналы с Arduino. Думаю, что к следующим новогодним праздникам и новогодней ёлке сделаю такую силовую плату и добавлю в этот проект, а пока чисто программа управления гирляндами и имитация их с помощью светодиодов.

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

    Всё монтируем на макетной панельке. Делаем надлежащие подключения к плате Arduino и переходим к самому скетчу (программе).

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

    Используем наработки предыдущих скетчей и добавляем кое-что новое. Этим новым будет использование прерываний. У Arduino есть два аппаратных прерывания int0 и int1, которые подключены к контактам pin2 и pin3 соответственно. В моём случае буду использовать прерывание int0 (контакт pin2). На этот контакт подключим выход схемы устранения дребезга.

    Что такое прерывание? Это значит, что выполнение программы аппаратно прерывается и опрашивается определённый вход, в нашем случае – pin2. Если на заданном входе ничего не происходит, то выполняется очередной шаг программы дальше.

    Само прерывание программно подключается с помощью функции attachInterrupt. Аргументы у этой функции следующие:

    • numberInt – Номер прерывания (у нас = 0);
    • fn_ISR – Имя функции обработки прерывания (любая ваша функция);
    • RISING – На что реагировать, условие при котором срабатывает функция обработки прерывания (в данном примере на фронт, то есть на изменение сигнала с низкого уровня на высокий).

      Кроме этой возможности, существуют ещё и другие, для отслеживания события на контакте прерывания:
      • LOW — прерывание будет срабатывать всякий раз, когда на выводе присутствует низкий уровень сигнала;
      • CHANGE — прерывание будет срабатывать всякий раз, когда меняется состояние вывода;
      • FALLING — прерывание сработает, когда состояние вывода изменится с высокого уровня на низкий.

    Для того, чтобы передавать значение выбранного эффекта из функции обработки прерывания fn_ISR() в функцию loop(), используем для переменной effect тип volatile byte.

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

    /**********************************************************************
     * 2018-03-19 Mr.ALB Тренировка в программировании Ардуино
     * Управление 5-ю светодиодными гирляндами (можно больше)
     * 7-мь световых эффектов (можно больше)
     * Дребезг кнопки SB1 устраняется аппаратно с помощью LM358P
    **********************************************************************/
    /* Задержки в мс */
    #define delay_1 100
    #define delay_2 200
    #define delay_3 300
    #define delay_5 500
    #define delay_10 1000
    
    byte mode = 0;       // Режим работы гирлянды
    byte ledLevel = 0;
    byte deltaLevel = 10;// Шаг изменения яркости
    byte repeat=3;       // Повтор в 3-м эффекте 3 раза
    
    /* Переменные для кнопки */
    byte switchPin = 2;// Подключаем выход LM358P (кнопка SB1) на 2-й pin
    
    /* Перывание */
    volatile byte effect = 0;// Визуальный эффект через прерывание
    byte numberInt = 0;      // Номер прерывания
    
    /**********************************************************************
     * Настроечная функция, выполняется один раз вначале
    **********************************************************************/
    void setup()
    {
    /* Конфигурируем цифровые выводы под номерами 3,4,5,6,7 на выход */
     for(byte i=3; i < 8; i++)
     {
       pinMode(i, INPUT);
     }
     pinMode(switchPin, INPUT);   // SB1 - Выбор эффектов
     pinMode(LED_BUILTIN,OUTPUT);// Используем светодиод для сигнализации
    
     /* Потушим светодиод на pin13 (LED_BUILTIN) */
     digitalWrite(LED_BUILTIN, LOW);
    
     /* Прикрепим прерывание int0 (pin2) к функции fn_ISR */
     attachInterrupt(numberInt, fn_ISR, RISING);
    }
    
    /**********************************************************************
     * Функция включения гирлянды
     *
     * Состояние flag:
     *  Если 0, то выключить
     *  Если 1, то включить
     *  Если 2, то включить и выключить
     * По умолчанию flag = 2 – включить-выключить
    **********************************************************************/
    void fn_blinkLed(byte pin, word msec, byte flag = 2)
    {
      /* Включение */
      if(flag == 1 || flag==2)
      {
        digitalWrite(pin, HIGH);
        delay(msec);
      }
    
      /* Выключение */
      if(flag == 0 || flag==2)
      {
        digitalWrite(pin, LOW);
        delay(msec);
      }
    }
    
    /**********************************************************************
     * Функция loop() выполняется постоянно
     *
     * Переключение пяти гирлянд. 7 световых эффектов
     * effect = 0 - все эффекты последовательно
     *          1 - первый эффект
     *          2 - второй эффект
     *          ...
    **********************************************************************/
    void loop()
    {
     /* Первый эффект. Поочерёдно включаем и выключаем гирлянды */
     if(effect==1 || effect==0)
     {
       for(byte i=3; i < 8; i++)
       {
         fn_blinkLed(i, delay_5);
       }
     }
    
     /* Второй эффект. Последовательно включаем все гирлянды... */
     if(effect==2 || effect==0)
     {
       for(byte i=3; i < 8; i++)
       {
         fn_blinkLed(i, delay_3, 1);
       }
       /* ...потом в обратном порядке их выключаем */
       for(byte i=7; i > 2; i--)
       {
         fn_blinkLed(i, delay_3, 0);
       }
     }
    
    /* Третий эффект. Все включить - Все выключить. С задержкой 1 с */
     if(effect==3 || effect==0)
     {
       for(byte k=0; k < repeat; k++)
       {
        for(byte j=0; j < 2; j++)
        {
         if(j==0) mode=1;// Режим включения
         else mode=0;    // Режим выключения
         for(byte i=3; i < 7; i++)
         {
           fn_blinkLed(i, 1, mode);// Задержка 1 мс
         }
         delay(delay_10);// Задержка 1 с
        }
       }
     }
    
     /* Четвертый эффект. Быстрая последовательная пробежка по гирляндам */
     if(effect==4 || effect==0)
     {
       // В прямом порядке...
       for(byte i=3; i < 8; i++)
       {
         fn_blinkLed(i, delay_1);
       }
       // ...в обратном порядке
       for(byte i=6; i > 2; i--)
       {
         fn_blinkLed(i, delay_1);
       }
     }
    
     /* Пятый эффект. Включаем с крайних к центральной */
     if(effect==5 || effect==0)
     {
       // Включаем с крайних до центральной
       byte n=7;
       for(byte i=3; i < 6; i++)
       {
         fn_blinkLed(i, 1, 1); // Задержка 1 мс
         fn_blinkLed(n--, 1, 1);
         delay(delay_5);// Задержка 500 мс
       }
    
       // Выключаем-выключаем центральную
       fn_blinkLed(5, delay_5);// Задержка 500 мс
       // Выключаем от центральной к крайним
       n=6;
       for(byte i=4; i > 2; i--)
       {
         fn_blinkLed(i, 1, 0);
         fn_blinkLed(n++, 1, 0);
         delay(delay_5);// Задержка 500 мс
       }
     }
    
     /* Шестой эффект. Включаем ШИМ на 3,5,6 */
     if(effect==6 || effect==0)
     {
       for(byte i=3; i < 7; i++)
       {
        if(i!=4)
         {
           fn_stepBrightness(i, delay_1, deltaLevel, 1);// Зажигается
           fn_stepBrightness(i, delay_1, deltaLevel, -1);// Тухнет
         }
       }
     }
    
     /* Седьмой эффект. Быстрое моргание - мерцание */
     if(effect==7 || effect==0)
     {
       byte repeat=63;// Повтор 63 раза
       for(byte k=0; k < repeat; k++)
       {
         for(byte j=0; j < 2; j++)
         {
           if(j==0) mode=1;// Режим включения
           else mode=0;    // Режим выключения
           for(byte i=3; i < 7; i++)
           {
             fn_blinkLed(i, 1, mode);// Задержка 1 мс
           }
           delay(21);// Задержка 21 мс
         }
       }
     }
    
     /* Выключаем все гирлянды */
     for(byte i=3; i < 8; i++)
     {
       fn_blinkLed(i, 1,0);
     }
     delay(delay_5);
     fn_blinkLed(LED_BUILTIN, delay_2);// Сигнализируем об окончании цикла
    
    }// Конец loop()
    
    
    /**********************************************************************
     * Функции
    **********************************************************************/
    
    /* Функция обработки прерывания */
    void fn_ISR()
    {
     /* При нажатии на кнопку SB1, происходит выбор эффекта по кругу */
      ++effect;// Переходим на следующий эффект
     if(effect > 7) effect=0;// Установим все эффекты сразу
    }
    
    /**********************************************************************
     * Функция изменения яркости гирлянды через ШИМ (PWM)
    **********************************************************************/
    void fn_stepBrightness(byte ledPin,
           word step_delay,
           byte deltaLevel,
           int sign)
    {
     for(byte i = 0; i < (int(256 / deltaLevel) + 1); i++)
     {
      ledLevel = ledLevel + deltaLevel * sign;
      ledLevel = constrain(ledLevel, 0, 255);// Ограничиваем диапазон
      analogWrite(ledPin, ledLevel);
      delay(step_delay);
     }
    }
    
    

    Этот скетч можно дополнить ещё какими-нибудь эффектами. К примеру, добавить эффект случайного перебора гирлянд. Возможно в дальнейшем этот эффект и добавлю.

    Код подробно закоментирован, надеюсь трудностей в его понимании не будет.

    P.S. Изменил типы переменных с int на byte, что позволило уменьшить код.

    2018-03-28

    Скетч можно скачать тут: sketch__3.zip

    2018-07-23
    . Mr.ALB
    Предыдущая страница Страница 4 Далее