Помогите найти ошибку
- Войдите на сайт для отправки комментариев
Давно написал функцию, и вроде проблем не помню с ней. Сейчас вернулся к проекту, и не работает как надо. Это таймер (да да, опять аквариум). Почему то во втором таймере выход pwm срывается на ноль, а потом нормализуется согласно программе. Здесь три канала по четыре "таймера". Таймер это временной интервал с постоянным уровнем pwm. Можно задать уровни в каждом "таймере", изменить время старта и окончания работы каждого. Уровень pwm между "таймерами" должен плавно изменяться с уровня предыдущего "таймера" до уровня следующего. Начало и конец дня pwm - 0. Так оно и работает, кроме второго таймера. Код можно загрузить в ардуину и все увидеть. Пока тестирую без RTC, просто переменная Utime приращивается в лупе.
Может свежим взглядом виднее, я не вижу уже ничего...
struct Timer { long start; long end; int level; bool on; }; Timer timer[4]; struct Channel { long startDay; long endDay; Timer timer[4]; }; Channel channel[3]; long Utime; long Channel_pwm(Channel &c) { int _pwm = 0; //таймер -0 if (Utime >= c.startDay && Utime < c.timer[0].start) { _pwm = (((Utime - c.startDay) * c.timer[0].level) / (c.timer[0].start - c.startDay)); }// таймер 0 else if (Utime >= c.timer[0].start && Utime < c.timer[0].end) { _pwm = c.timer[0].level; }// таймер 0 - 1 else if (Utime >= c.timer[0].end && Utime < c.timer[1].start) { _pwm = ((Utime - c.timer[0].end) * (c.timer[1].level - c.timer[0].level) / (c.timer[1].start - c.timer[0].end)) + c.timer[0].level; }// таймер 1 else if (Utime >= c.timer[1].start && Utime < c.timer[1].end) { _pwm = timer[1].level; }// таймер 1 - 2 else if (Utime >= c.timer[1].end && Utime < c.timer[2].start) { _pwm = ((Utime - c.timer[1].end) * (c.timer[2].level - c.timer[1].level) / (c.timer[2].start - c.timer[1].end)) + c.timer[1].level; }// таймер 2 else if (Utime >= c.timer[2].start && Utime < c.timer[2].end) { _pwm = c.timer[2].level; }// таймер 2 - 3 else if (Utime >= c.timer[2].end && Utime < c.timer[3].start) { _pwm = ((Utime - c.timer[2].end) * (c.timer[3].level - c.timer[2].level) / (c.timer[3].start - c.timer[2].end)) + c.timer[2].level; }// таймер 3 else if (Utime >= c.timer[3].start && Utime < c.timer[3].end) { _pwm = c.timer[3].level; }// таймер 3 + else if (Utime >= c.timer[3].end && Utime < c.endDay) { _pwm = (((c.endDay - Utime) * c.timer[3].level) / (c.endDay - c.timer[3].end)); } else _pwm = 0; return _pwm; } void setup() { Serial.begin(9600); channel[0].startDay = 10000; channel[0].endDay = 82000; channel[0].timer[0].start = 24400; channel[0].timer[0].end = 31600; channel[0].timer[1].start = 38800; channel[0].timer[1].end = 46000; channel[0].timer[2].start = 53200; channel[0].timer[2].end = 60400; channel[0].timer[3].start = 67600; channel[0].timer[3].end = 74800; channel[0].timer[0].level = 70; channel[0].timer[1].level = 140; channel[0].timer[2].level = 200; channel[0].timer[3].level = 250; channel[0].timer[0].on = true; channel[0].timer[1].on = true; channel[0].timer[2].on = true; channel[0].timer[3].on = true; channel[1].startDay = 1000; channel[1].endDay = 82000; channel[1].timer[0].start = 24400; channel[1].timer[0].end = 31600; channel[1].timer[1].start = 38800; channel[1].timer[1].end = 46000; channel[1].timer[2].start = 53200; channel[1].timer[2].end = 60400; channel[1].timer[3].start = 67600; channel[1].timer[3].end = 74800; channel[1].timer[0].level = 140; channel[1].timer[1].level = 280; channel[1].timer[2].level = 560; channel[1].timer[3].level = 1120; channel[1].timer[0].on = true; channel[1].timer[1].on = true; channel[1].timer[2].on = true; channel[1].timer[3].on = true; channel[2].startDay = 1000; channel[2].endDay = 82000; channel[2].timer[0].start = 24400; channel[2].timer[0].end = 31600; channel[2].timer[1].start = 38800; channel[2].timer[1].end = 46000; channel[2].timer[2].start = 53200; channel[2].timer[2].end = 60400; channel[2].timer[3].start = 67600; channel[2].timer[3].end = 74800; channel[2].timer[0].level = 210; channel[2].timer[1].level = 420; channel[2].timer[2].level = 840; channel[2].timer[3].level = 1680; channel[2].timer[0].on = true; channel[2].timer[1].on = true; channel[2].timer[2].on = true; channel[2].timer[3].on = true; } void loop() { Utime+=5; Serial.print(Utime); Serial.print(" pwm "); Serial.print(Channel_pwm(channel[0])); Serial.print(" "); Serial.print(Channel_pwm(channel[1])); Serial.print(" "); Serial.println(Channel_pwm(channel[2])); }
Мне кажется, что автор скетча и есть ошибка.
Очень загадочный ответ. А главное полезный. Спасибо.
Очень загадочный ответ. А главное полезный. Спасибо.
ПС: И да long лучше заменить на unsigned long https://www.arduino.cc/reference/en/language/variables/data-types/unsignedlong/
Очень загадочный ответ. А главное полезный. Спасибо.
ПС: И да long лучше заменить на unsigned long https://www.arduino.cc/reference/en/language/variables/data-types/unsignedlong/
Не могу не согласится с уважаемым qwone - очень сложно читать программу без комментариев. Для Вас все прозрачно, но нам трудно оценить полет Вашей мысли... Комментарии для Вас - это несколько минут, но они могут и для Вас открыть истину!
Надо ж было такую простую вещь так сложно написать! Есть же, блин, специалисты!
Не хочется классов, структурами можно обойтись, мне кажется. Откомментировал как смог:
Надо ж было такую простую вещь так сложно написать! Есть же, блин, специалисты!
Вы про структуры или про функцию? Мне показалось так проще всего. Хоть на словах, объясните как описать просто такую "простую вещь"
unsigned long не помог...
Да, это очень похоже на классы, я и хотел, в общем, библиотеку сделать, но пока не потянул. Только не в структурах же ошибка, а в расчете уровня шим, подозреваю. Не могу найти где. Шим то во всех таймерах одинако рассчитывается, почему глюк во втором только? Или я неправильно декларирую структуры? Или неправильно помещаю массив структур timer в структуру channel?
Скорее неправильная методика программирования. Неправильно что-то продумали и эта неясность полезла в код, породив глюки в коде.
Неправильный расчет уровня шим в интервалах между таймерами. Переписывать.
Неправильный подход. Не зачем делать расчет Шима. У объекта ШИМ должно быть три состояния. Стабильное, плавно(логарифмически) возврастать до нужного и плавно (логарифмически)убывать.
ПС: И зачем Вы все усложняете. Посмотрите мультфильм "Шкатулка с секретом" Там прообраз вашей программы. https://www.youtube.com/watch?v=2wDESvyj1qo
Вот это "пружина"
А дальше "барабан"
И в эскизном виде "шкатулка" будет такой
Вот это "пружина"
А дальше "барабан"
И в эскизном виде "шкатулка" будет такой
Крутой мультфильм, я вспомнил как он удивил меня в детстве.
"Барабан" - интересная идея, с часов я могу получать часы, минуты и секунды. Дык самое главное - логарифмическое возрастание - убывание как сделать? Собственно мой код и городился на расчете шим каждую секунду нон-стоп.
X=X+delta;//линейное прирастание
X=X*delta;//логармфмическое прирастание
где delta некая константа.
X=X+delta;//линейное прирастание
X=X*delta;//логармфмическое прирастание
где delta некая константа.
Только не логарифмическое, а экспоненциальное. (хотя можно сказать "в логарифмическом масштабе")
Я баран. Я никак не пойму как из X = X * delta; сделать pwm. pwm[i] = time * delta? Дельта это крутизна, если я правильно понял. Как расчитывать ее в каждом переходном интервале, и как то pwm должен стартовать с нужного значения, и доходить до нужного значения? В барабане заданы значения pwm, но не задано сколько времени быть в статическом режиме, следовательно нужны еще ячейки в
struct
note_t? Или я не правильно все понял? Ведь сейчас получается, что в первом канале pwm каким то образом (пока мне непонятным) переходит с 10 -> 50
-> 40 -> 100-> 10.Вот вернемся к ..мультику . Там есть ... колокольчик . И он звучит . Динь. Что заставляет звучать его? Конструкция. А висит он в шкатулке или на церви уже от звука не зависит.
Теперь про ШИМ. Пусть максимум 255. 0 нет ШИМ. Уберем плавный ШИМ переход. Не понимаю зачем он вам. Вода в аквариуме инерциона. Была к примеру ШИМ=25. Пришла команда savePID(100). И стало 100.
При плавном 25,25*1.2,25*1.2*1.2,25*1.2*12,25*1.2*1.2*1.2 и так до 100 . Разумеется на каждый цикл ON-OFF новое обновление ШИМ.
ПС: Здесь константа delta=1.2 К примеру.
ПС2: Но все же лучше регулировать не ШИМ, а температуру по времени дня. Так лучше. А шим пусть ее отрабатывает.
Этож свет а не грелка! Рыбкам будет страшно когда pwm с 0 на 255 бабахать будет. :)
Ну тогда делайте снижение/ рост на delta через каждые 100 циклов. Хотя в сети переменка в 50 Гц вроде. Как вы ШИМ организовываете??
12 канальная 16 битная i2c платка, контроль времени ds3231. Значения задаются в меню. Я потому и считал шим каждую секунду, это полный контроль, можно из меню выключить канал, внести изменения в настройки. Ваш вариант хранения отдельно часов, минут и секунд лучше моего в виде секунд, а вот расчет шим мне пока не ясен совсем.
Я должен, наверно, на словах объяснить как будет работать. В каждом канале есть
это начало светового дня. Есть четыре таймера с атрибутами
и, соответственно
канала.
Шим в startDay равен 0 и нарастает до момента start первого таймера, если он включен. С момента start до момента stop pwm стабилен и равен level, заданному в таймере. В интервале между timer[0].stop и timer[1].start pwm нарастает или уменьшается в зависимости от того меньше timer[0].level чем timer[1].level или нет. И так до Channel[].endDay. По этому то мне и нужна точная формула расчета шим, чтобы переход по всему дню был без скачков.Я уже понял где я ошибся в своей функции - формулы расчета возрастающего и убывающего шим разные, а у меня только возрастающая. Наверно есть проще путь, как то с линейными ф-иями, или по вашей, с дельтой, только как прикрутить!
В общем таймеров и каналов может больше или меньше, это я пойму когда решу крышку "в железе".
А x(n) = x(0)*delta^n - это экспонента.
Ну для начала надо написать тестовый скетч . Например такой. И конопками подавать комады
Кривовато. Но где-то так
дома проверю, на работе