Блок с датойБлок с временемБлок с возрастом сайта
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.1

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

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

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

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

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

    Скетч #3.1

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

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

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

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

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

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

    Ниже скетч v3.1, для просмотра – нажмите на кнопку:

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

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

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

    2018-03-28

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

    2018-07-23

    Скетч #3.2

    Подошло время новогодней ёлки, соответственно потребовалась уже реальная гирлянда из светодиодов. Сделал небольшую гирлянду из 25 светодиодов. Пять секций по пять светодиодов. Можно сделать любую, какую хотите, всё упирается в напряжение, которое подаётся на светодиоды. У меня был использован блок питания Импульсный блок питания на 9 В, только выходное напряжение не 9 В, а перенастроил его на 12 В.

    Дополнительно сделал фильтр. Добавил модуль ключей на транзисторах 2N2222, которые управляют секциями гирлянды. На входы ключей идут управляющие сигналы с Ардуино через резисторы 1.2 кОм. Для их управления задействовал порты только с ШИМ, чтобы можно было плавно менять яркость всех секций. Номера контактов: D3, D5, D6, D9, D10. Кнопку выбора эффекта и кнопку сброса вывел на небольшую плату, на ней же вначале установил линейный стабилизатор на КРЕН5В, дающий 5В для питания Ардуино от импульсного блока питания. Потом для этого стабилизатора сделал отдельный модуль. Размеры его платы 27.5х20 мм.

    Окончательный скетч смотрите ниже:

    Новый скетч можно скачать тут: my_led_elka.zip


    Реализация

    Триггер Шмитта (подавитель дребезга кнопки) сделал в виде отдельного модуля, если вдруг понадобится не в новогоднее время, то можно быстро снять и использовать в каком-нибудь другом проекте улыбка. Модуль имеет размеры 25х20 мм.

    Модуль подавителя дребезга на LM358P
    Pic 5. Модуль подавителя дребезга на LM358P
    Модуль подавителя дребезга на LM358P<br>Вид со стороны соединений
    Pic 6. Модуль подавителя дребезга на LM358P
    Вид со стороны соединений

    Ниже на фото реализация устройства, остаётся лишь всё поместить в удобную коробку или какой-нибудь корпусок.

    Реализация устройства
    Pic 7. Реализация устройства

    На фото выше слева-направо видны отдельные модули:

    • Блок питания 12 В;
    • Фильтр питания;
    • Модуль подавителя дребезга кнопки;
    • Планка с кнопками;
    • Модуль стабилизатора на 5 В;
    • Arduino UNO;
    • Модуль ключей.

    В процессе проверки работы устройства.

    Промежуточный вариант. Процесс настройки
    Pic 8. Промежуточный вариант. Процесс настройки

    Осталось всю эту механизацию прикрутить на ёлку и заряжаться праздничным настроением улыбка

    2018-12-11

    Вот и дошло дело до коробка. Решил сделать его из ДВП, по-быстрому. Ниже на фото рабочий процесс изготовления.

    Процесс изотовления коробки
    Pic 9. Процесс изотовления коробки

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

    Тестирование работоспособности уже собранного устройства
    Pic 10. Тестирование работоспособности уже собранного устройства
    2018-12-23

    Было проверено на ёлке – замечательно!


    Обновление. Скетч #3.3

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

    Недавно нашёл гирлянду и блок управления. Из него, после того 2018 нового года, изъял плату Arduino UNO R3 для отладки других проектов. А в этот блок управления сейчас поставил уже Arduino Pro Mini на микроконтроллере ATMega168P. Сам скетч использует всего 3722 байт, поэтому использовать ATMega168P более разумно, чем ATMega328P.

    Так как такая ёлочная гирлянда используется всего несколько дней в году, то сделал небольшую плату-шилд, с установленной на ней панелькой под Arduino Pro Mini. Теперь можно легко вставить или вытащить плату с Ардуино, если понадобится для каких-нибудь других проектов, а на время Нового года всегда можно запрограммировать этим скетчем для управления гирляндой.

    Глянув критически на скетч, решил его немного модернизировать. Что в нём нового?

    Немного переписал функции. Поигрался временными задержками, но самое главное, это для режима effect = 0 применил не последовательный перебор эффектов, а случайный их выбор, через функцию random().

    Ещё заменил функцию delay() на свою функцию fnDelay(), которая делает задержку через функцию millis().

    В остальном скетч 2020 года подобен предыдущим.

    /***********************************************************
       2018-03-19 Mr.ALB Тренировка в программировании Ардуино
    
       Управление 5-ю светодиодными гирляндами
       7-ть эффектов работы
       Дребезг книпки SB1 устраняется аппаратно с помощью LM358P
    
       2018-12-08 9-ть  эффектов работы
       2018-12-11 11-ть эффектов работы
       2020-12-02 Arduino Pro Mini
                  + случайный выбор эффектов при effect = 0
                  + добавлена функция fnDelay() вместо delay()
    ***********************************************************/
    
    /* Задержки в мс */
    #define DELAY_1     100
    #define DELAY_2     200
    #define DELAY_3     300
    #define DELAY_5     500
    #define DELAY_10    1000
    #define MAX_EFFECT  11
    
    byte mode = 0;            //Режим работы гирлянды
    byte ledLevel = 0;
    byte deltaLevel = 10;     // Шаг изменения яркости
    
    /* Переменные для кнопки */
    #define BUTTON 2 // Подключаем кнопку SB1 на 2-й pin
    
    /* Перывание */
    volatile byte effect = 0; //Визуальный эффект через прерывание
    const byte numberInt = 0; //Номер прерывания
    
    byte repeat; // Повтор
    unsigned long time_now, time_check; // Для fnDelay()
    
    /***************************************
      Функция - Включение гирлянды (секции)
    
      Состояние flag:
      Если 0, то выключить
      Если 1, то включить
      Если 2, то включить и выключить
     **************************************/
    void fnBlinkLed(byte pin, word msec, byte flag = 2)
    {
      if (flag == 1 || flag == 2)
      {
        digitalWrite(pin, HIGH);//Включение
        fnDelay(msec);
      }
      if (flag == 0 || flag == 2)
      {
        digitalWrite(pin, LOW);//Выключение
        fnDelay(msec);
      }
    }
    
    /***********************
      Настройка программы
     ***********************/
    void setup()
    {
      /* Цифровые выводы под номерами 3,5,6,9,10 на выход */
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 || i != 7 || i != 8)
          pinMode(i, OUTPUT);
      }
    
      pinMode(BUTTON, INPUT);       // SB1 - Выбор эффектов
      pinMode(LED_BUILTIN, OUTPUT); // Светодиод на pin13 сигнализация
      digitalWrite(LED_BUILTIN, LOW);// Потушим светодиод на pin13
    
      /* Прикрепим прерывание int0 (pin2) к функции fn_ISR */
      attachInterrupt(numberInt, fn_ISR, RISING);
    
      /* Установка начала псевдослучайной последовательности */
      randomSeed(analogRead(0));
      // Проверка работоспособности всех светодиодов
      fnEffect11();
    }
    
    /*******************************************
       Переключение пяти гирлянд. 9 эффектов
       effect = 0 - все эффекты последовательно
                1 - первый эффект
                2 - второй эффект
                ...
    ********************************************/
    void loop()
    {
      if (effect == 1) fnEffect1();
      if (effect == 2) fnEffect2();
      if (effect == 3) fnEffect3();
      if (effect == 4) fnEffect4();
      if (effect == 5) fnEffect5();
      if (effect == 6) fnEffect6();
      if (effect == 7) fnEffect7();
      if (effect == 8) fnEffect8();
      if (effect == 9) fnEffect9();
      if (effect == 10) fnEffect10();
      if (effect == 11) fnEffect11();
      if (effect == 0)
      {
        /* Включаем случайным выбором эффект */
        switch (random(1, 12))
        {
          case 1: fnEffect1(); break;
          case 2: fnEffect2(); break;
          case 3: fnEffect3(); break;
          case 4: fnEffect4(); break;
          case 5: fnEffect5(); break;
          case 6: fnEffect6(); break;
          case 7: fnEffect7(); break;
          case 8: fnEffect8(); break;
          case 9: fnEffect9(); break;
          case 10: fnEffect10(); break;
          case 11: fnEffect11();
        }
      }
    
      /* Выключаем все гирлянды */
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, 1, 0);   //Выключаем
      }
      fnDelay(DELAY_1);
    
      //Сигнализируем об окончании цикла
      fnBlinkLed(LED_BUILTIN, DELAY_1);
    }
    
    /***********************
       Функции
     ***********************/
    
    /******************************************
      Функция - задержка на время delaytime
        delaytime в мс
     *****************************************/
    void fnDelay(int delaytime)
    {
      time_check = millis();
      do
      {
        time_now = millis();
      }
      while (time_now - time_check < delaytime);
    }
    /* Функция - Обработка прерывания */
    void fn_ISR()
    {
      /* При нажатии на кнопку SB1, происходит выбор эффекта */
      ++effect; //Переходим на другой эффект
      if (effect > MAX_EFFECT) effect = 0; // Установим все эффекты сразу
    }
    
    /* Функция - Изменение яркости светодиода */
    void fn_stepBrightness(byte ledPin, word step_delay, byte deltaLevel, int sign)
    {
      if (sign == 1)ledLevel = 0;
      else ledLevel = 255;
    
      for (byte i = 0; i < 25; i++)
      {
        analogWrite(ledPin, ledLevel);
        ledLevel = ledLevel + deltaLevel * sign;
        if (ledLevel < deltaLevel)ledLevel = 0;
        fnDelay(step_delay);
      }
    }
    
    /*******************************
      Первый эффект.
        Поочерёдно включаем и выключаем гирлянды
    */
    void fnEffect1()
    {
      for (int i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, DELAY_3);
      }
    }
    
    /***************************************
      Второй эффект.
        Последовательно включаем все гирлянды
    ****************************************/
    void fnEffect2()
    {
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, DELAY_5, 1);
      }
      /* ...потом в обратном порядке их выключаем */
      for (byte i = 10; i > 2; i--)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, DELAY_3, 0);
      }
    }
    
    /*******************************
      Третий эффект.
        Все включить,  задержка 0,5 с
        Все выключить, задержка 0,5 с
    ********************************/
    void fnEffect3()
    {
      repeat = 5; //Повтор 5 раз
      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 < 11; i++)
          {
            if (i != 4 && i != 7 && i != 8)
              fnBlinkLed(i, 1, mode);//Задержка 1 мс
          }
          
          fnDelay(DELAY_5);//Задержка 0,5 с
        }
      }
    }
    
    /*************************************************
      Четвертый эффект.
        Быстрая последовательная пробежка по гирляндам
    **************************************************/
    void fnEffect4()
    {
      if (effect == 4 || effect == 0)
      {
        repeat = 5;                //Повтор 5 раз
        for (byte k = 0; k < repeat; k++)
        {
          // В прямом порядке...
          for (byte i = 3; i < 11; i++)
          {
            if (i == 3)
              fnBlinkLed(i, DELAY_2, 0);
            if (i == 5 || i == 6 || i == 9)
              fnBlinkLed(i, DELAY_2);
            if (i == 10)
              fnBlinkLed(i, DELAY_2, 1);
          }
          // ...в обратном порядке
          for (byte i = 10; i > 2; i--)
          {
            if (i == 10)
              fnBlinkLed(i, DELAY_2, 0);
            if (i == 5 || i == 6 || i == 9)
              fnBlinkLed(i, DELAY_2);
            if (i == 3)
              fnBlinkLed(i, DELAY_2, 1);
          }
        }
      }
    }
    
    /************************************
      Пятый эффект.
        Включаем с крайних к центральной
     ************************************/
    void fnEffect5()
    {
      // Включаем с крайних до центральной
      fnBlinkLed(3, 1, 1);
      fnBlinkLed(10, 1, 1);    //Задержка 1 мс
      fnDelay(DELAY_3);        //Задержка 500 мс
      fnBlinkLed(5, 1, 1);
      fnBlinkLed(9, 1, 1);
      fnDelay(DELAY_3);
      fnBlinkLed(6, 1, 1);
      fnDelay(DELAY_10);
    
      // Выключаем центральную
      fnBlinkLed(6, 1, 0);     //Задержка 1 мс
      fnDelay(DELAY_2);        //Задержка 500 мс
      fnBlinkLed(5, 1, 0);
      fnBlinkLed(9, 1, 0);
      fnDelay(DELAY_2);
      fnBlinkLed(3, 1, 0);
      fnBlinkLed(10, 1, 0);
      fnDelay(DELAY_2);
    }
    
    /*******************************
      Шестой эффект.
        Включаем ШИМ на 3,5,6,9,10
     *******************************/
    void fnEffect6()
    {
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
        {
          fn_stepBrightness(i, DELAY_1, deltaLevel, 1);  // Зажигается
          fn_stepBrightness(i, DELAY_1, deltaLevel, -1); // Тухнет
        }
      }
      fnDelay(DELAY_2);
    }
    
    /*******************************
      Седьмой эффект.
        Быстрое моргание - мерцание
     *******************************/
    void fnEffect7()
    {
      repeat = 108; //Повтор 108 раз
      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 < 11; i++)
          {
            if (i != 4 && i != 7 && i != 8)
              fnBlinkLed(i, 1, mode);//Задержка 1 мс
          }
          fnDelay(21);
        }
      }
    }
    
    /*****************************************
      Восьмой эффект.
        включение 3-6-10 далее 5-9 → повтор
     *****************************************/
    void fnEffect8()
    {
      repeat = 16;              //Повтор 16 раз
      for (byte k = 0; k < repeat; k++)
      {
        fnBlinkLed(5, 1, 0);   //Режим выключения
        fnBlinkLed(9, 1, 0);
        fnBlinkLed(3, 1, 1);   //Режим включения
        fnBlinkLed(6, 1, 1);
        fnBlinkLed(10, 1, 1);
        fnDelay(DELAY_5);
        fnBlinkLed(5, 1, 1);   //Режим включения
        fnBlinkLed(9, 1, 1);
        fnBlinkLed(3, 1, 0);   //Режим выключения
        fnBlinkLed(6, 1, 0);
        fnBlinkLed(10, 1, 0);
        fnDelay(DELAY_2);
      }
    }
    
    /***********************
      Девятый эффект.
      включение x-5-6-9-10
          далее 3-x-6-9-10
          далее 3-5-x-9-10
          далее 3-5-6-x-10
          далее 3-5-6-9-x
     ***********************/
    void fnEffect9()
    {
      repeat = 5;   //Повтор 5 раз
      for (byte k = 0; k < repeat; k++)
      {
        for (byte i = 5; i < 11; i++)
        { // Включаем 5-6-9-10
          if (i != 7 && i != 8)
            fnBlinkLed(i, 1, 1);       //Задержка 1 мс
          if (i == 3)
            fnBlinkLed(3, DELAY_3, 0); // Гасим
        }
    
        fnBlinkLed(3, 1, 1);        // Включаем
        fnBlinkLed(5, DELAY_5, 0);  // Гасим
    
        fnBlinkLed(5, 1, 1);        // Включаем
        fnBlinkLed(6, DELAY_3, 0);  // Гасим
    
        fnBlinkLed(6, 1, 1);        // Включаем
        fnBlinkLed(9, DELAY_3, 0);  // Гасим
    
        fnBlinkLed(9, 1, 1);        // Включаем
        fnBlinkLed(10, DELAY_3, 0); // Гасим
      }
    }
    
    /***************************************
      Десятый эффект.
        Быстрое разное моргание - мерцание
     **************************************/
    void fnEffect10()
    {
      repeat = 108; //Повтор 108 раз
      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 < 11; i++)
          {
            if (i == 3)
              fnBlinkLed(i, 1, mode);//Задержка 1 мс
            if (i == 5)
              fnBlinkLed(i, 2, mode);//Задержка 2 мс
            if (i == 6)
              fnBlinkLed(i, 3, mode);//Задержка 3 мс
            if (i == 9)
              fnBlinkLed(i, 4, mode);//Задержка 4 мс
            if (i == 10)
              fnBlinkLed(i, 5, mode);//Задержка 5 мс
          }
          fnDelay(21);
        }
      }
    }
    
    /***********************
      Одиннадцатый эффект.
        Просто включены
     ***********************/
    void fnEffect11()
    {
      mode = 1;          //Режим включения
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, 1, mode);//Задержка 1 мс
      }
      fnDelay(10000);// Задержка 10 c
      mode = 0;         //Режим выключения
      for (byte i = 3; i < 11; i++)
      {
        if (i != 4 && i != 7 && i != 8)
          fnBlinkLed(i, 1, mode);//Задержка 1 мс
      }
    }
    

    Приложение

    Используемые библиотеки и программы:


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