как заменить delay, на millis?
- Войдите на сайт для отправки комментариев
Пт, 24/12/2021 - 17:45
Здрасте.
Как заменить delay, на millis?
void door() {
for (int fadeValue = 0;fadeValue <= 255; fadeValue += 5) {
analogWrite(PWM, fadeValue);
delay(30);
}
for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 5) {
analogWrite(PWM, fadeValue);
delay(30);
}
}
Здесь без толку, цикл for сам по себе неплохо блокирует, пока он не отработает, больше ничего выполняться не будет
Мне нужно чтоб ШИМ плавно стартовал, потом плавно замедлялся. И при этом выполнялись другие процесы без серьезных задержек.
Может что-то толковое подскажите.
В самой процедуре door() просто увеличивать fadeValue до 255, а по достижении уменьшать до нуля и наоборот. Безо всяких циклов. По одному шагу. А процедуру door() вызывать из лупа раз в 30 миллисекунд. Используя миллис )))
В самой процедуре просто увеличивать fadeValue до 255, а по достижении уменьшать до нуля и наоборот. Безо всяких циклов. По одному шагу. А процедуру door() вызывать из лупа раз в 30 миллисекунд. Используя миллис )))
Извените, я не сильно пока разбераюсь. Не смогли бы Вы, подробно описать написание, правильной процедуры.
Пожалуйста!
вот так это делают! Добрый я в Сочельник католический, и особенно перед Шаббатом! ;))
const uint32_t StepDuration = 30; //millisec const float ValueStep = 5; // какой-то шаг void setup() { // smth } void loop() { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); //у меня значения флоат - так осталось от кода, из которого я это всё вытянул. static float targetValue = 0; static float slaveValue = 0; if (nm - lastStepTime > StepDuration) { lastStepTime = nm; if (slaveValue < targetValue) { if ((slaveValue += ValueStep) > targetValue) slaveValue = targetValue; } if (slaveValue > targetValue) { if ((slaveValue -= ValueStep) < targetValue) slaveValue = targetValue; } } //ну а тут что-то делаем, что меняет целевое и подчиненное значения }Подробно пояснять не стану, пора пить начинать! в Москве уже 17-06 и Шаббат начался, а я ысчо трезвый и на кнопки жамкаю! Фу, какой ужос!
вот так это делают! Добрый я в Сочельник католический, и особенно перед Шаббатом! ;))
const uint32_t StepDuration = 30; //millisec const float ValueStep = 5; // какой-то шаг void setup() { // smth } void loop() { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); //у меня значения флоат - так осталось от кода, из которого я это всё вытянул. static float targetValue = 0; static float slaveValue = 0; if (nm - lastStepTime > StepDuration) { lastStepTime = nm; if (slaveValue < targetValue) { if ((slaveValue += ValueStep) > targetValue) slaveValue = targetValue; } if (slaveValue > targetValue) { if ((slaveValue -= ValueStep) < targetValue) slaveValue = targetValue; } } //ну а тут что-то делаем, что меняет целевое и подчиненное значения }Сбасибо, добрый человек!
С наступающим.
вот так это делают! Добрый я в Сочельник католический, и особенно перед Шаббатом! ;))
А у меня 25-го годовщина свадьбы.. С суженой-ряженой
В самой процедуре просто увеличивать fadeValue до 255, а по достижении уменьшать до нуля и наоборот. Безо всяких циклов. По одному шагу. А процедуру door() вызывать из лупа раз в 30 миллисекунд. Используя миллис )))
Извените, я не сильно пока разбераюсь. Не смогли бы Вы, подробно описать написание, правильной процедуры.
Пожалуйста!
Легко. Объявляешь в процедуре door() две статические переменные
Далее, если toUp == true, увеличиваешь fadeValue на 5, при достижении 255 присваиваешь toUp = false. Если toUp == false, то уменьшаешь fadeValue на 5, при достижении 0 присваиваешь toUp = true. В конце процедуры выполняешь analogWrite(PWM, fadeValue);
Т.е. за один раз процедура door() либо увеличивает, либо уменьшает значение шим на пять единиц.
А как вызывать door() из loop() раз в 30 миллисекунд - кури пример блинка без делея - http://arduino.ru/tutorials/BlinkWithoutDelay
ЗЫ: граф уже дал готовый пример, у него тот же принцип, только без выноса в отдельную процедуру ))
вот так это делают! Добрый я в Сочельник католический, и особенно перед Шаббатом! ;))
А у меня 25-го годовщина свадьбы.. С суженой-ряженой
Маладой!!! У нас светская 28 октября было 32 года, а 32 года венчания будет 7 февраля, вот скоро уже.
вот так это делают! Добрый я в Сочельник католический, и особенно перед Шаббатом! ;))
const uint32_t StepDuration = 30; //millisec const float ValueStep = 5; // какой-то шаг void setup() { // smth } void loop() { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); //у меня значения флоат - так осталось от кода, из которого я это всё вытянул. static float targetValue = 0; static float slaveValue = 0; if (nm - lastStepTime > StepDuration) { lastStepTime = nm; if (slaveValue < targetValue) { if ((slaveValue += ValueStep) > targetValue) slaveValue = targetValue; } if (slaveValue > targetValue) { if ((slaveValue -= ValueStep) < targetValue) slaveValue = targetValue; } } //ну а тут что-то делаем, что меняет целевое и подчиненное значения }Кстати, граф, может я туплю, но разве условия в строках 18 и 21 когда-нибудь выполнятся? Ведь изначально slaveValue == targetValue
Кстати, граф, может я туплю, но разве условия в строках 18 и 21 когда-нибудь выполнятся? Ведь изначально slaveValue == targetValue
Это кусок кода. В реальности слейв следит за мастером медленно, а мастер выставляется энкодером. Это кусок какого-то старого заказа.
Не получается слепить все это. Помогите.
#include <Bounce2.h> #include <EEPROM.h> #define led 13 //Индикатор работы #define btn 2 //Кнопка открытия / закрытия #define RelayOpen 10 //Реле открытия #define RelayClose 11 //Реле закрытия #define PWM 3 #define OpenTimer 10000 //Время открытия или закрытия Bounce bouncer_btn = Bounce(btn,5); int eeprom_address = 0; const uint32_t StepDuration = 30; //millisec const float ValueStep = 5; // какой-то шаг void setup() { pinMode(led, OUTPUT); pinMode(RelayOpen, OUTPUT); pinMode(RelayClose, OUTPUT); pinMode(PWM, OUTPUT); digitalWrite(RelayOpen,LOW); digitalWrite(RelayClose,LOW); } void loop() { if ( bouncer_btn.update() ) { if ( bouncer_btn.read() == HIGH) { int eeprom_val; eeprom_val = EEPROM.read(eeprom_address); if(eeprom_val == 0) // Закрыто { digitalWrite(RelayOpen,HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis()-timer < OpenTimer) { door(); //включаем ШИМ if(millis()-led_timer >= 1000) { digitalWrite(led,!digitalRead(led)); led_timer = millis(); } if ( bouncer_btn.update() ) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led,LOW); } } } digitalWrite(RelayOpen ,LOW); digitalWrite(led,LOW); } if(eeprom_val == 1) // Открыто { digitalWrite(RelayClose,HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis()-timer < OpenTimer) { door(); //включаем ШИМ if(millis()-led_timer >= 1000) { digitalWrite(led,!digitalRead(led)); led_timer = millis(); } if ( bouncer_btn.update() ) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led,LOW); } } } digitalWrite(RelayClose ,LOW); digitalWrite(led,LOW); } } } } void door() { //=============================================================== // for (int fadeValue = 0;fadeValue <= 255; fadeValue += 5) { // analogWrite(PWM, fadeValue); // delay(30); // } // for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 5) { // // analogWrite(PWM, fadeValue); // delay(30); // // } //=============================================================== static uint32_t lastStepTime = millis(); uint32_t nm = millis(); //у меня значения флоат - так осталось от кода, из которого я это всё вытянул. static float targetValue = 0; static float slaveValue = 0; if (nm - lastStepTime > StepDuration) { lastStepTime = nm; if (slaveValue < targetValue) { if ((slaveValue += ValueStep) > targetValue) slaveValue = targetValue; } if (slaveValue > targetValue) { if ((slaveValue -= ValueStep) < targetValue) slaveValue = targetValue; } } }Это кусок кода. В реальности слейв следит за мастером медленно, а мастер выставляется энкодером. Это кусок какого-то старого заказа.
Да это понятно, просто в отрыве от основного кода этот кусок работать не станет. А значит ждем ТС снова ))
Не получается слепить все это. Помогите.
void door() { static int fadeValue = 0; static bool toUp = true; if (toUp) { fadeValue += ValueStep; if (fadeValue >= 255) { toUp = false; fadeValue = 255; // защита от дурака } } else { fadeValue -= ValueStep; if (fadeValue <= 0) { toUp = true; fadeValue = 0; // защита от дурака } } analogWrite(PWM, fadeValue); }loop() { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } }Маладой!!! У нас светская 28 октября было 32 года, а 32 года венчания будет 7 февраля, вот скоро уже.
А я ещё моложе тогда.
Неделю назад, отмечал дату-месяц как женат.
Решился вот под сраку лет.
Хотел 19го в свой(и твой кстати) ДР, жена сказала ну его нафиг.
Давай 18го.
А можно как то сделать чтоб, процедура выполнилась только один раз.
Тоесть: нажал кнопку, включился слабый ШИМ, вырос до максимума, максимальный убывает до минимума, выключился.
#include <Bounce2.h> #include <EEPROM.h> #define led 13 //Индикатор работы #define btn 2 //Кнопка открытия / закрытия #define RelayOpen 10 //Реле открытия #define RelayClose 11 //Реле закрытия #define PWM 3 //ШИМ управления драйвером #define OpenTimer 10000 //Время открытия или закрытия Bounce bouncer_btn = Bounce(btn, 5); int eeprom_address = 0; const uint32_t StepDuration = 80; //Скорость ШИМа const float ValueStep = 10; //Шаг ШИМа static int fadeValue = 0; static bool toUp = true; void setup() { pinMode(led, OUTPUT); pinMode(RelayOpen, OUTPUT); pinMode(RelayClose, OUTPUT); pinMode(PWM, OUTPUT); digitalWrite(RelayOpen, LOW); digitalWrite(RelayClose, LOW); } void loop(){ if ( bouncer_btn.update() ) { if ( bouncer_btn.read() == HIGH) { int eeprom_val; eeprom_val = EEPROM.read(eeprom_address); //======================= Закрыто ================== if (eeprom_val == 0){ digitalWrite(RelayOpen, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer){ if (millis() - led_timer >= 1000){ digitalWrite(led, !digitalRead(led)); led_timer = millis(); } if ( bouncer_btn.update()){ if ( bouncer_btn.read() == HIGH){ break; digitalWrite(led, LOW); } } //===================== включаем ШИМ ============== static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } } digitalWrite(RelayOpen , LOW); digitalWrite(led, LOW); } //======================== Открыто ================== if (eeprom_val == 1){ digitalWrite(RelayClose, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer){ if (millis() - led_timer >= 1000){ digitalWrite(led, !digitalRead(led)); led_timer = millis(); } if ( bouncer_btn.update()){ if ( bouncer_btn.read() == HIGH){ break; digitalWrite(led, LOW); } } } digitalWrite(RelayClose , LOW); digitalWrite(led, LOW); } } } } void door(){ if (toUp){ fadeValue += ValueStep; if (fadeValue >= 255){ toUp = false; fadeValue = 255; // защита от дурака} } } } else{ fadeValue -= ValueStep; if (fadeValue <= 0){ toUp = true; fadeValue = 0; // защита от дурака} } } } analogWrite(PWM, fadeValue); }Во-первых, переменные в строках 16 и 17 почему там? Это локальные переменные, используются только в процедуре door(), там им и место. Я же привел код, зачем их оттуда выкидывать?
Во-вторых, можно и один раз. Нужно завести глобальную переменную-флаг. По нажатию кнопки поднимать флаг (присваивать true), а в процедуре door() при достижении fadeValue нуля опускать флаг (присваивать false). И процедуру door() вызывать только если флаг поднят.
И в-третьих, зачем так бездумно копировать? Строка 15 - зачем там float? Граф же ясно написал, что так было нужно в его программе, в твоей это не нужно. Там int более чем достаточно.
Во-первых, переменные в строках 16 и 17 почему там? Это локальные переменные, используются только в процедуре door(), там им и место. Я же привел код, зачем их оттуда выкидывать?
Во-вторых, можно и один раз. Нужно завести глобальную переменную-флаг. По нажатию кнопки поднимать флаг (присваивать true), а в процедуре door() при достижении fadeValue нуля опускать флаг (присваивать false). И процедуру door() вызывать только если флаг поднят.
И в-третьих, зачем так бездумно копировать? Строка 15 - зачем там float? Граф же ясно написал, что так было нужно в его программе, в твоей это не нужно. Там int более чем достаточно.
Понял. Сейчас перепишу.
Спасибо.
Шим начал включатся но, не с нуля. Например остановила его процедура на 50% мочности, то при следующем вызове, начнет с этиг же 50%. А мне надо чтоб был сброс этого шима.
Что я не так написал?
#include <Bounce2.h> #include <EEPROM.h> #define led 13 //Индикатор работы #define btn 2 //Кнопка открытия / закрытия #define RelayOpen 10 //Реле открытия #define RelayClose 11 //Реле закрытия #define PWM 3 //ШИМ управления драйвером #define OpenTimer 10000 //Время открытия или закрытия Bounce bouncer_btn = Bounce(btn, 5); int eeprom_address = 0; const uint32_t StepDuration = 80; //Скорость ШИМа int ValueStep = 10; //Шаг ШИМа bool flag = 0; void setup() { pinMode(led, OUTPUT); pinMode(RelayOpen, OUTPUT); pinMode(RelayClose, OUTPUT); pinMode(PWM, OUTPUT); digitalWrite(RelayOpen, LOW); digitalWrite(RelayClose, LOW); } void loop() { if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { int eeprom_val; eeprom_val = EEPROM.read(eeprom_address); //======================= Закрыто ================== if (eeprom_val == 0) { digitalWrite(RelayOpen, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer) { if (millis() - led_timer >= 1000) { digitalWrite(led, !digitalRead(led)); led_timer = millis(); flag = true;//Разрешаем задействовать ШИМ } if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led, LOW); flag = false;// Выключаем ШИМ по принуждению } } //===================== включаем ШИМ ============== if (flag == true) { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } } } digitalWrite(RelayOpen , LOW); digitalWrite(led, LOW); } //======================== Открыто ================== if (eeprom_val == 1) { digitalWrite(RelayClose, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer) { if (millis() - led_timer >= 1000) { digitalWrite(led, !digitalRead(led)); led_timer = millis(); flag = true;// //Разрешаем задействовать ШИМ } if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led, LOW); flag = false;// Выключаем ШИМ по принуждению } } //===================== включаем ШИМ ============== if (flag == true) { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } } } digitalWrite(RelayClose , LOW); digitalWrite(led, LOW); } } } } void door() { static int fadeValue = 0; static bool toUp = true; if (toUp) { fadeValue += ValueStep; if (fadeValue >= 255) { toUp = false; fadeValue = 255; // защита от дурака} } } } else { fadeValue -= ValueStep; if (fadeValue <= 0) { toUp = true; fadeValue = 0; // защита от дурака} } flag = false; } } analogWrite(PWM, fadeValue); }Получилось.
#include <Bounce2.h> #include <EEPROM.h> #define led 13 //Индикатор работы #define btn 2 //Кнопка открытия / закрытия #define RelayOpen 10 //Реле открытия #define RelayClose 11 //Реле закрытия #define PWM 3 //ШИМ управления драйвером #define OpenTimer 10000 //Время открытия или закрытия Bounce bouncer_btn = Bounce(btn, 5); int eeprom_address = 0; const uint32_t StepDuration = 80; //Скорость ШИМа int ValueStep = 10; //Шаг ШИМа bool flag = 0; static bool toUp = true; void setup() { pinMode(led, OUTPUT); pinMode(RelayOpen, OUTPUT); pinMode(RelayClose, OUTPUT); pinMode(PWM, OUTPUT); digitalWrite(RelayOpen, LOW); digitalWrite(RelayClose, LOW); } void loop() { if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { int eeprom_val; eeprom_val = EEPROM.read(eeprom_address); //======================= Закрыто ================== if (eeprom_val == 0) { digitalWrite(RelayOpen, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer) { if (millis() - led_timer >= 1000) { digitalWrite(led, !digitalRead(led)); led_timer = millis(); flag = true;//Разрешаем задействовать ШИМ } if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led, LOW); flag = false;// Выключаем ШИМ по принуждению } } //===================== включаем ШИМ ============== if (flag == true) { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } } } digitalWrite(RelayOpen , LOW); digitalWrite(led, LOW); toUp = true; } //======================== Открыто ================== if (eeprom_val == 1) { digitalWrite(RelayClose, HIGH); EEPROM.update(eeprom_address, !eeprom_val); unsigned long timer = millis(); unsigned long led_timer = millis(); while (millis() - timer < OpenTimer) { if (millis() - led_timer >= 1000) { digitalWrite(led, !digitalRead(led)); led_timer = millis(); flag = true;// //Разрешаем задействовать ШИМ } if ( bouncer_btn.update()) { if ( bouncer_btn.read() == HIGH) { break; digitalWrite(led, LOW); flag = false;// Выключаем ШИМ по принуждению } } //===================== включаем ШИМ ============== if (flag == true) { static uint32_t lastStepTime = millis(); uint32_t nm = millis(); if (nm - lastStepTime > StepDuration) { lastStepTime = nm; door(); } } } digitalWrite(RelayClose , LOW); digitalWrite(led, LOW); toUp = true; } } } } void door() { static int fadeValue = 0; if (toUp) { fadeValue += ValueStep; if (fadeValue >= 255) { toUp = false; fadeValue = 255; // защита от дурака} } } } else { fadeValue -= ValueStep; if (fadeValue <= 0) { toUp = false; fadeValue = 0; // защита от дурака} } flag = false; } } analogWrite(PWM, fadeValue); }Кстати, граф, может я туплю, но разве условия в строках 18 и 21 когда-нибудь выполнятся? Ведь изначально slaveValue == targetValue
Это кусок кода. В реальности слейв следит за мастером медленно, а мастер выставляется энкодером. Это кусок какого-то старого заказа.
Я с тобой! Шабат никто не отменял. Только вот приехали в наше Шилово. Теперь до января 10-го. Пойду налью.
P.S. Не знаю как правильно писать шалом алехен. Полюбасу мир вашему форуму!
Шим не отключается по принуждению 47 и 81 строчка кода!
А с какой радости он отключаться должен? Там кроме flag = false; нужно еще и нулевой уровень шим выставить. Иначе он просто остается на том уровне, на котором его настигло принуждение ))
А с какой радости он отключаться должен? Там кроме flag = false; нужно еще и нулевой уровень шим выставить. Иначе он просто остается на том уровне, на котором его настигло принуждение ))
А так уже выключается, но только когда шим перевалит 50% мочности.
Если до 50% то выключается не полностью!
Значит смотри логику программы, где-то ты перемудрил ))
Для начала посмотри на строки 45 и 79. Уверен, что после break что-то будет выполняться?
Вообще было бы неплохо нарисовать блок-схему и человеческим языком расписать алгоритм работы. А уже потом по алгоритму писать код. Боюсь, что сейчас проще будет с нуля все переписать ))
А где у него там прерывания?
Прерывания будет занято энкодером, которое в качестве меню будет в будующем использоватся.
Мне бы помоч концевики прикрутить к коду, и я не буду вам морочить голову!
Это не алгоритм. Это примерное описание. По нему код не напишешь. Вот возьми хотя бы PWM - в коде он отрабатывает 3 секунды и отключается сам. А оказывается, что работать он должен, пока в концевик не упрется. Думай, голова, думай. Чем лучше все продумаешь, тем легче тебе будет код писать ))
что значит "движемся в право" ?
3 секунды PWM - это я на тот случай, если концевик не сработал.
В дальнейшем это значение можно будет менять из под менюшки.
что значит "движемся в право" ?
Это типа привод отпирает дверь на право. Тоесть открываем дверь.
Программу нужно переписывать заново. В текущем виде развивать ее будет крайне сложно. В loop() должна быть только проверка кнопки, определение направления движения и запуск door(), если нужно. А все управление PWM должно быть уже в door(). Т.е. при каждом проходе проверять состояние нужного концевика и в случае чего давать стоп. Проверку концевиков можно вынести в отдельную процедуру. Там же проверять состояние датчика тока и датчиков препятствий, если таковые появятся.
ЗЫ: и нужно еще предусмотреть аварийный стоп, т.е. иметь возможность кнопкой (этой или другой) остановить дверь, если нужно, а концевики/датчики не сработали.
Шим не отключается по принуждению 47 и 81 строчка кода!
Он выключается, но тут же включается обратно. Например в 47 выключили, а в 41 включили... А поскольку все это внутри цикла - то он так мотыляется то вкл то выкл...
Код очень избыточный и неэффективный, в нем просто куча лишних строк и повторов
Это не алгоритм, это - так - перечень хотелок.
В алгоритме нужно интегрировать замечание а) в каждый из пунктов 1-5. Типа: "если у нас нажаты такие-то кнопки и при этом PWM равно тому-то, то сделать то-то, а если нажаты те же самые кнопки, но PWM равно тому-то, то сделать другое". В общем, эти 5 пунктов превратятся в несколько десятков.
Ну и еще нужно четко различать события "состояние кнопки в настоящий момент - включено" и "кнопка перешла из состояние выключено в состояние включено" и аналогично для выключения.
Ну и еще по поводу "в конце замедляется" - нужно ввести точный критерий, когда начинается этот самый конец.
Это не алгоритм, это - так - перечень хотелок.
В алгоритме нужно интегрировать замечание а) в каждый из пунктов 1-5. Типа: "если у нас нажаты такие-то кнопки и при этом PWM равно тому-то, то сделать то-то, а если нажаты те же самые кнопки, но PWM равно тому-то, то сделать другое". В общем, эти 5 пунктов превратятся в несколько десятков.
Ну и еще нужно четко различать события "состояние кнопки в настоящий момент - включено" и "кнопка перешла из состояние выключено в состояние включено" и аналогично для выключения.
Ну и еще по поводу "в конце замедляется" - нужно ввести точный критерий, когда начинается этот самый конец.
Я все понял. Буду переписывать правильно.