delay() в сложных временнЫх процессах.
- Войдите на сайт для отправки комментариев
Пнд, 20/07/2015 - 23:11
Написал программу, в которой используется много временнЫх интервалов, задаваемых оператором delay(). Работает медленно, но уверенно )). Очень хочу избавиться от delay, но не пойму с какой стороны подступиться.
Краткая предыстория создания. Сделал устройство для включения четырех нагрузок 220В. Два-три месяца работало хорошо, а потом стали залипать контакты реле, хотя используются энергосберегающие лампочки. Решил заменить реле на твердотельные. Но у меня их всего два, поэтому придумал схему на четыре нагрузки с одной твердотелкой.
// ***** Define pins ***** // Serial_RX 0 // Serial_TX 1 #define K1_relay 5 #define K2_relay 6 #define K3_relay 9 #define K4_relay 10 #define K5_relay 7 #define K6_relay 8 #define K7_relay 11 #define K8_relay 12 #define K9_SSR 3 // Solid State Zero Crossing Relay // #define IOPort Serial // порт ввода-вывода #define PortSpeed 9600 // скорость работы порта // ***** Define relay switching times ***** #define SSR_Switch_Time 11 // in milliseconds #define RelaySwitchON_Time 10 // in milliseconds #define RelaySwitchOFF_Time 20 // in milliseconds // struct output_power_switch { unsigned long sw_time; // для будущего использования byte relay_A; // реле А (1..4) подключающее byte relay_B; // реле В (5..8) перемыкающее boolean state; // текщее состояние канала ВКЛ-ВЫКЛ } RelayPool [] = {0, K9_SSR, K9_SSR, LOW, \ 0, K1_relay, K5_relay, LOW, \ 0, K2_relay, K6_relay, LOW, \ 0, K3_relay, K7_relay, LOW, \ 0, K4_relay, K8_relay, LOW}; const byte RelayPoolMaxN = sizeof(RelayPool)/sizeof(output_power_switch); // // Переменные исключительно для тестирования работы unsigned long interval = 1500; // интервал включения-выключения канала unsigned long previousMillis = 0; unsigned long currentMillis; // void setup() { IOPort.begin (PortSpeed); for (byte i = 0; i < RelayPoolMaxN; i++) { pinMode (RelayPool[i].relay_A, OUTPUT); digitalWrite (RelayPool[i].relay_A, LOW); pinMode (RelayPool[i].relay_B, OUTPUT); digitalWrite (RelayPool[i].relay_B, LOW); } } void loop() { currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; ChangeState (1); //можно любой номер 1..4 } } void SwitchON(byte n){ if ( !RelayPool[n].state && (boolean)n && (n < RelayPoolMaxN)){ // если канал вЫключен, его номер не 0 и не больше числа каналов, // то будем включать noInterrupts(); digitalWrite (RelayPool[n].relay_A, HIGH); delay (RelaySwitchON_Time); digitalWrite (RelayPool[0].relay_A, HIGH); delay (SSR_Switch_Time); digitalWrite (RelayPool[n].relay_B, HIGH); delay (RelaySwitchON_Time); digitalWrite (RelayPool[0].relay_A, LOW); digitalWrite (RelayPool[n].relay_A, LOW); delay (RelaySwitchOFF_Time); RelayPool[n].state = HIGH; interrupts(); return; } } void SwitchOFF(byte n){ if ( RelayPool[n].state && (boolean)n && (n < RelayPoolMaxN)){ // если канал включен, его номер не 0 и не больше числа каналов, // то будем вЫключать noInterrupts(); digitalWrite (RelayPool[n].relay_A, HIGH); delay (RelaySwitchON_Time); digitalWrite (RelayPool[0].relay_A, HIGH); delay (SSR_Switch_Time); digitalWrite (RelayPool[n].relay_B, LOW); delay (RelaySwitchOFF_Time); digitalWrite (RelayPool[0].relay_A, LOW); delay (SSR_Switch_Time); digitalWrite (RelayPool[n].relay_A, LOW); delay (RelaySwitchOFF_Time); RelayPool[n].state = LOW; interrupts(); return; } } void ChangeState(byte n){ if ((boolean)n && (n < RelayPoolMaxN)){ RelayPool[n].state ? SwitchOFF(n) : SwitchON(n); } return; }
Извините, схему забыл.
delay() в loop() это зло.
Надеюсь не надо писать почему.
Используйте millis().
Расчитывайте моменты времени когда надо выполнить то или иное действие.
И постоянно в цикле loop() постоянно проверяйте наступило условие для события или нет.
А для начала смотрите темы как мигать без delay()
Piskunov, что делает ваше устройство, по-очереди включает и отключает лампочки? Опишите на словах алгоритм.
Опишите на словах алгоритм.
dimax, приветствую!
Задача, которая решена в этой схеме - использование единственного твердотельного реле для включения/выключения четырёх нагрузок.
Описание схемы.
Реле 1..8 - обычные, с током коммутации 5А по паспорту.
Реле 9 - твердотельное, с функцией Zero Crossing.
Алгоритм работы.
Для включения, например, нагрузки №1 сначала включаем реле 1 (задержка на включение 10 мс), затем включаем реле 9 (задержка на включение один полупериод), соответственно ток включения/выключения коммутируется твердотелкой, и контакты обычных реле не подгорают. После этого реле 5 перемыкает замкнутые контакты реле 1 и 9 (задержка на включение 10 мс) и остаётся включеным.
Далее отключаем реле 1 и 9 (задержка 20мс) и готовы к включению другой нагрузки.
Выключение производим в том же порядке, но с обратным знаком ))
Описанный функционал запрограммирован в функциях SwitchON и SwitchOFF
Остальная часть программы особого значения не имеет, так как упрощена до предела - подача команд, оценка освещённости и тд удалены, дабы не загружать сообщение в теме.
Сейчас это решение стоит у меня в комнате и управляет светом, в принципе нормально, но в моменты включения/выключения подтормаживает, и может не воспринимать команды. Думаю, что из-за delay.
PS. Я понимаю, что четыре твердотелки упрощают этот вопрос принципиально ))
но у меня их нет ((
А для начала смотрите темы как мигать без delay()
Эта тема мне знакома ))
См. строки 50..52
Piskunov, честно говоря я даже не могу начать думать по теме вашего вопроса, т.к. не понимаю зачем такое чудовищное извращение. Если у вас сдохло реле через 2 месяца -значит реле было плохое. Хорошие электромагнитные реле работают по 30 лет. Если ваше реле было на китайском реле-шилде, то туда всё самое дешевое г@вно ставят. Я вот однажды себе такое брал, правда всего пару лет работает, рано выводы делать. Есть ещё хорошие реле Tyco , они обычно в оранжевых корпусах.
У меня FINDER 34.51.7.012.0010, мне по случаю достались ))
Они тихие, и на лампочки накаливания работают без проблем. А вот с энергосберегайками ерунда вышла, контакты подгорают. Наверное из-за большой емкостной нагрузки, сама мощность ерунда, 6 ламп по 12 ватт на один канал и три по 18 на другой.
Три месяца работают, а потом менять приходится - залипают и не выключают свет, пока отвёрткой не ударишь.
Пробовал поставить мощнее (44.62.9.012.0000), щёлкают громко и время нормальной работы увеличилось раза в полтора.
Зато с твердотельным по такой схеме уже четыре месяца полёт нормальный. Лишь delay() покоя не даёт ))
Эта тема мне знакома ))
См. строки 50..52
Видно что знакома, но не прочувствована. Архитектура должна быть переделана. Полный запрет на делеи во всех функциях, вызываемых из лупа. Т.е. выполнение любой функции , из тех у которых в вашей реализации делей, должно содержать проверку истек ли временной интервал. Если не истек - выходим, в другой раз вызовут иначе выполняем действие. Величину интервала и выполняемое действие определяет некоторая глобальная переменная.
Типа пример из "раннего", несколько замутненного оптимизацией. Генерит морзянкой "...---..." по кругу.
А noInterrupts(); у Вас зачем?
А noInterrupts(); у Вас зачем?
Сорри, не убрал. Это датчик движения у меня в полной версии через прерывание на площадке свет включает. А когда сосед долго ключ в замок вставить не может, у меня свет не всегда включался, пока прерывание не запретил ))
Прием с канала при запрещенном прерывании также может вызывать проблему. А может и не вызывать.
Видно что знакома, но не прочувствована.
Возможно так.
Но, понимаете, у меня не линейный процесс, и может быть ситуация, когда один свет будет включаться, на другой придёт команда выключить, а задействованы одни и те же элементы.
Как в этом случае по времени разносить, не понятно...
А с делэями пока не выполнится, к другому не приступит.
Прием с канала при запрещенном прерывании также может вызывать проблему. А может и не вызывать.
Ну, подумаешь, свет на площадке на полсекунды позже включится. Не критично ))
Возможно так.
Но, понимаете, у меня не линейный процесс, и может быть ситуация, когда один свет будет включаться, на другой придёт команда выключить, а задействованы одни и те же элементы.
Как в этом случае по времени разносить, не понятно...
Очевидно блокировать выполнение новых команд до выполнения текущей, складывать их в очереди и выполнять по мере готовности. Или просто игнорить.
Очевидно блокировать выполнение новых команд до выполнения текущей, складывать их в очереди и выполнять по мере готовности. Или просто игнорить.
Я так пробовал сделать, но примерно на сотой строке функции включения меня посетило чувство, что я двигаюсь в никуда.
Теперь, по Вашему примеру, подозреваюб что я рано сдался.
Буду пробовать ещё, хотя я надеялся получить ответ типа "есть книга такая-то, читай, неучь, там про это есть"
Почитать - не сложно, у Вас было https://ru.wikipedia.org/wiki/%D0%90%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5#.D0.98.D0.BC.D0.BF.D0.B5.D1.80.D0.B0.D1.82.D0.B8.D0.B2.D0.BD.D0.B0.D1.8F_.D0.BF.D1.80.D0.BE.D0.B3.D1.80.D0.B0.D0.BC.D0.BC.D0.B0 а должно https://ru.wikipedia.org/wiki/%D0%90%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5#.D0.92.D1.8B.D0.B4.D0.B5.D0.BB.D0.B5.D0.BD.D0.B8.D0.B5_.D1.88.D0.B0.D0.B3.D0.B0_.D0.B0.D0.B2.D1.82.D0.BE.D0.BC.D0.B0.D1.82.D0.B0_.D0.B2_.D0.BE.D1.82.D0.B4.D0.B5.D0.BB.D1.8C.D0.BD.D1.83.D1.8E_.D1.84.D1.83.D0.BD.D0.BA.D1.86.D0.B8.D1.8E
Там к стати есть enum States { before, inside, after }; - И это правильно, в моем примере тоже надо бы, и обычно я так делаю.
Краткая предыстория создания. Сделал устройство для включения четырех нагрузок 220В. Два-три месяца работало хорошо, а потом стали залипать контакты реле, хотя используются энергосберегающие лампочки.
В момент включения энергосберегаек импулс тока достигает нескольких десятков ампер (под сотню Ампер) и контакты просто привариваются. Поставьте последовательно с каждой лампой NTC Ом на 20-30.
И с лампами накаливания этот трюк полезен - в холодном состоянии сопротивление спирали в 10-15 раз меньше, чем в раскаленном. Номинал NTC поменьше в этом случае.
И с лампами накаливания этот трюк полезен - в холодном состоянии сопротивление спирали в 10-15 раз меньше, чем в раскаленном. Номинал NTC поменьше в этом случае.
А уж как он полезен для галлогенок на 220В! Там температура рабочая выше и отношенее сопротивлений соответственно больше. NTC исключает их перегорание при включении и продлевает срок службы просто катастрофически.
Поставьте последовательно с каждой лампой NTC Ом на 20-30.
Спасибо.
Я почему-то думал, что они дорогие, ан нет - вполне по карману.
Обязательно поставлю, по результатам отпишусь (месяца через три :-)
Автоматное программирование...
О как!
Я про эту тему ничего не знал, с удовольствием почитаю. Думаю до нового года точно хватит ))
Спасибо
А не проще будет Zero Detect использовать?
Эт снимет проблему? Есть у кого опыт более менее длительной эксплуатации?
Примеров реализации много. Микросхемка с детектором, и соответсвенно прерывание которое обрабатывает.
Или оптопары переключающиеся при пересечении нуля.
Поставьте последовательно с каждой лампой NTC Ом на 20-30.
Поставил. Греются как... Ну, в общем сильно греются. Убрал.
Мощность лампы какая? Я то думал ватт по 20. Поставте 2 NTC паралельно. Если NTC не будут нагреваться, то в них смысла не больше чем в простых резисторах. Думаю нагрев при работе до 50С* это нормально.
Мощность лампы какая? Я то думал ватт по 20. Поставте 2 NTC паралельно. Если NTC не будут нагреваться, то в них смысла не больше чем в простых резисторах. Думаю нагрев при работе до 50С* это нормально.
Pyotr, приветствую.
Стоит 8 шт по 18Вт, итого должно быть меньше 1 ампера.
NTC резистор один на всю группу светильников, вот такой: JNR15S200, http://www.joyin.com.tw/lan_en/product_files/15S200L.pdf
Подплавил мне подрозетник )). То есть я понимаю, они должны греться, возможно даже градусов до 100. Делаю вывод, что лампочки полнейшее г@вно.
Вообще то я писал: "Поставьте последовательно с каждой лампой NTC Ом на 20-30."
У вас получается 1А на 20 Ом = 20 В. Мощность 20в*1А=20 Вт маленький такой паяльничек)
Вообще то я писал: "Поставьте последовательно с каждой лампой NTC Ом на 20-30."
У вас получается 1А на 20 Ом = 20 В. Мощность 20в*1А=20 Вт маленький такой паяльничек)
"Неправильно ты, Дядя Фёдор, бутерброд ешь." (с) не я.
Если поставить с каждой лампочкой, то сопротивление уменьшится пропорционально количеству, и мы не получим существенное ограничение тока (20 / 8 = 2,5). Поэтому я и поставил на группу.
Мысли, собственно, такие:
Для начального момента Ваш расчёт верен, но в процессе резистор нагреется, его сопротивление упадёт. Этакая система с обратной связью. В25/50 = 3100, по графику сопротивление резистора упадёт до 0,2 от номинала при температуре 80 С, и будет меньше 0,1 при 120 С. Что даёт нам мощность 2 ватта при 1 ампере.
Мне кажется, что при такой мощности пластмассу не расплавить ))
Следовательно ток больше, причём существенно. Почему? Потому что лампочки ...
В нашем непонимании друг друга виноват Интернет)
Внутреннее сопротивление электросети думаю 0.5- 2 Ом. Напрямую не получится измерить, но косвенно можно посчитать. Пусть будет 1 Ом. Включаем сберегайку. Если момент попадёт на вершину синуса почти 300 В, ток в цепи (теоретически, на самом деле меньше из за индуктивности проводов) под 300 А (кондёр разряжен). Диоды такой кратковременный импульс выдерживают, а контакты подгорают. Будет хорошо, если ограничим импульс тока до 10-20 А. Для этого нужно включить последовательно с энергосберегайкой резистор 30-15 Ом. При этом при потребляемой мощности лампы 22 Вт ток =0.1 А. На 20 Ом резисторе падает 2 В и выделяется Р=0.1*2=0.2 Вт. Делить омы на количество ламп не надо. Да, эти цифры для холодного NTC. От такого подогрева его Т поднимется на 10-20С*, но не до 100С* и, при нагреве выделяемая мощность на нем уменьшится вследствие уменьшения его сопротивления.
Померьте ток через лампу и будете знать потребляемую мощность. И 20 Ом резистор на одну лампу или 3 Ом на 8 ламп.
Во всех советских теликах с импульсными БП стояли проволочные резисторы 4.7 Ом. На БП стояли 1-2 кондера по 100 мкф. и всё замечательно работало годами.
Возможно интернет ))
С оценкой "сопротивления сети" согласен.
Если мы ставим NTC последовательно с каждой лампой, то в начальный момент времени эквивалентная схема для NTC будет представлять параллельное включение. Всё-таки настаиваю на 2,5 омах. Что плохо, и не сильно ограничивает ток через управляющие контакты.
Поэтому считаю, что NTC надо включать в общую цепь, но обязательно предусматривать тот факт, что он будет нагреваться и ставить его надо не абы как (типа как я), а по нормальному.
На всякий случай график.
Картинка хорошая, сохранил у себя. Ещё вот про NTC http://aterlux.ru/index.php?page=article&art=ntcresistor
Пусть будет 2.5 Ом не спорю. Тут важно найти компромис между пусковым током и рассеиваемой на резисторе мощностью, что сказывается на КПД устройства.
Идеальный вариант по КПД это замыкание балластного резистора контактами дополнительного реле через 0.5-1 сек после включения.
Идеальный вариант по КПД это замыкание балластного резистора контактами дополнительного реле через 0.5-1 сек после включения.
Спасибо, статья полезная.
А если для исключения потерь использовать дополнительное реле, то NTC и не обязателен, можно поставить обычный резистор на 15..20 Ом, его за полсекунды не перегреем наверное. В результате приходим к идее, сходной с моей первоначальной. Она хороша на мой взгляд, но размыкать цепь нам придётся обычными контактами под полной нагрузкой.
Резюме: надо продолжать изучение автоматного программирования ))
PS и ещё, в такой схеме NTC будет даже вреден, так как повторное включение через несколько секунд будет при полном токе, NTC остыть не успеет, у него постянная времени большая (125 сек!).
Размыкать нагрузку в Вашем случае контактам не трудно. Им "трудно" размыкать индуктивную нагрузку. При работе выпрямителя на емкость ток течёт в короткий период на самых вершинах синусоиды, а остальное время цепь как будто разомкнута.
Писал я скетч для себя типа: мигаем светиками без делай и без миллис, работает на прерывании по совпадению таимера0. Не трогая настроек Т/С можно независимо переключать хоть все пины с шагом в 1 мсек.