Снова управление LED

Тема в разделе "Силовая электроника", создана пользователем Adm123, 15 апр 2017.

  1. Adm123

    Adm123 Нерд

    Здравствуйте, уважаемые форумчане!
    Есть проблема и прошу вашей помощи в ее решении.
    Итак. Имею Arduino pro mini 5v (Atmega328) и мосфет IRFZ44N. Мосфет управляется ШИМ с 10-го ПИНа и коммутирует 12В LED-ленту. Ну, еще экранчик, часы и кнопки, но это не суть.
    Задача - организация рассвета и заката т.е. плавного (очень плавного - в течение часа примерно) включения-выключения LED.
    Все в общем-то работает, но... При почти закрытом транзисторе (analogWrite - 5-15) - и почти выключенной LED соответственно - становятся видны "ступеньки" изменения яркости.
    Можно ли как-то сделать изменение света более плавным?
     
  2. rkit

    rkit Гуру

  3. Adm123

    Adm123 Нерд

  4. Tomasina

    Tomasina Иномирянин

    глаз воспринимает изменение яркости по логарифмическому принципу, поэтому первые 60% диапазона воспринимаются ступеньками, а последние 15% неотличимы по воспринимаемому уровню яркости.
    Выход - использовать регулировку яркости не линейному, а по логарифмическому алгоритму.
     
    Adm123 нравится это.
  5. Adm123

    Adm123 Нерд

    Да, то что восприятие не соответствует реальным процентам - заметно, но сейчас не в этом соль была. Спасибо за ссылку. Внимательно пока не вчитывался, но общий смысл ясен. Функцию писать буду.
     
  6. Adm123

    Adm123 Нерд

    Спасибо ответившим за подсказки!
    Сделал 16-битный ШИМ и логарифмическое изменение яркости. В COM выводит красиво, вечером опробую на реальной нагрузке :)
     
    Tomasina нравится это.
  7. Adm123

    Adm123 Нерд

    Побаловался с разными вариантами... Мой выбор - парабола. Наиболее "естественное для глаза" затухание-разгорание, по-моему.
    Хотя в готовом контроллере оставил возможность выбора кривой (линейная ф-я, логарифм и парабола).
     
  8. Tomasina

    Tomasina Иномирянин

    а можно кусочек кода глянуть? Для логарифма и параболы.
     
  9. Adm123

    Adm123 Нерд

    Да там, в общем-то ничего особенного. Без вывертов.
    Код (C++):
      <...>
      switch (lightingValues[16]) {
        case 0:
          maxFuncArg = pow(1.1, 6.5535); // Для логарифма
          break;
        case 1:
          maxFuncArg = sqrt(65535);      // Для параболы
          break;
      }
      minFuncArg = (lightingValues[16] == 0 ? 1 : 0);
      funcRange = maxFuncArg - minFuncArg;
      startMorning = (lightingValues[0]  * 3600l + lightingValues[1]  * 60l) * 1000l;          //Время начала рассвета в миллисекундах от начала суток
      stopMorning  = (lightingValues[2]  * 3600l + lightingValues[3]  * 60l) * 1000l;          //Время конца рассвета в миллисекундах от начала суток
      startEvening = (lightingValues[9]  * 3600l + lightingValues[10] * 60l) * 1000l;          //Время начала заката в миллисекундах от начала суток
      stopEvening  = (lightingValues[11] * 3600l + lightingValues[12] * 60l) * 1000l;          //Время конца заката в миллисекундах от начала суток
      funcFactor[0] = (stopMorning - startMorning) / funcRange;                                //Множитель для получения аргумента функции затухания при увеличении яркости во время расвета
      funcFactor[1] = (stopEvening - startEvening) / funcRange;                                //Множитель для получения аргумента функции затухания при уменьшении яркости время заката
      <...>
      <...>
      if (currentMilliSecond >= startMorning && currentMilliSecond <= stopMorning) currentFuncArg = (lightingValues[13] != 0 ? (currentMilliSecond - startMorning) / funcFactor[0] + minFuncArg : maxFuncArg);
      else if (currentMilliSecond >= startEvening && currentMilliSecond <= stopEvening) currentFuncArg = (lightingValues[15] != 0 ? maxFuncArg - (currentMilliSecond - startEvening) / funcFactor[1] + minFuncArg : maxFuncArg);
      else if (currentMilliSecond >= stopMorning && currentMilliSecond <= startEvening) currentFuncArg = maxFuncArg;
      else currentFuncArg = minFuncArg;
      switch (lightingValues[16]) {
        case 0:
          analogWrite16(Pin_LED, log(currentFuncArg) / log(1.1) * 10000);
        break;
        case 1:
          analogWrite16(Pin_LED, sq(currentFuncArg));
        break;
      }
      <...>
    В lightingValues хранятся настройки, currentMilliSecond - текущая миллисекунда (отсчитывается от начала суток, т.е. 00.00)
     
    Tomasina нравится это.
  10. rkit

    rkit Гуру

    Это глаз логарифмически видит, а выводить надо через обратную функцию - экспонента.
     
  11. Adm123

    Adm123 Нерд

    Вот экспоненту не пробовал. Но, в принципе, и логарифм работает неплохо. Тут дело вкуса, что называется. Потому я и оставил возможность выбора. Мне, как я уже писал, парабола понравилась. Полностью отвечает моим ожиданиям.