Не работает delay
- Войдите на сайт для отправки комментариев
Пнд, 26/03/2018 - 23:16
Здравствуйте! Понадобилось сделать аппарат, перемещающий крышку каждые 24 часа и работающий автономно. Для уменьшения энергопотребления использую библиотеку LowPower, а для пробуждения по таймеру MsTimer2, для отключения реле(потребляет ток даже когда не движется) - транзистор на 6 поо По непонятным причинам, в функции feed не срабатывает задержка, а без нее серво привод просто не успевает переместится до выключения и перехода в сон.
/* Created 2017 by AlexGyver AlexGyver Home Labs Inc. */ //--------------------НАСТРОЙКИ---------------------- #define open_angle 60 // угол 1 #define close_angle 128 // угол 0 #define debug 1 // вывод информации в порт для отладки //--------------------НАСТРОЙКИ---------------------- // ---ПОДКЛЮЧЕНИЕ--- #define MOSFETpin 6 #define servoPin 5 #define OpenTime 1000 // ---ПОДКЛЮЧЕНИЕ--- #include <MsTimer2.h> //библиотека таймера #include "LowPower.h" // библиотека сна #include <Servo.h> // используем библиотеку для работы с сервоприводом Servo servo; boolean open_flag; void START(){ digitalWrite(MOSFETpin, 1); // подать питание на серво delay(1); servo.write(open_angle); delay(1000); // ждать серво open_flag = 1; digitalWrite(MOSFETpin, 0); // отключить серво if (debug) Serial.println("ready"); } void feed() { digitalWrite(MOSFETpin, 1); // подать питание на серво if (debug) Serial.println("on"); if (open_flag) { if (debug) Serial.println("close"); servo.write(close_angle); open_flag = 0; // флаг что крышка в положении 0 } else { if (debug) Serial.println("open"); servo.write(open_angle); open_flag = 1; // флаг что крышка в положении 1 } delay(OpenTime); if (debug) Serial.println("off"); digitalWrite(MOSFETpin, 0); ; sleep(); } void sleep(){ if (debug) Serial.println("power_down"); delay(1); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); } void setup() { if (debug) Serial.begin(9600); servo.attach(servoPin); // серво на 5 порту pinMode(MOSFETpin, OUTPUT); // пин транзистора в режиме выхода //MsTimer2::set(86400000, feed); MsTimer2::set(10000, feed); MsTimer2::start(); START(); sleep(); } void loop() { }
Извените, опечаточка:
для отключения серво-привода (потребляет ток даже когда не движется) - транзистор на 6 порту.
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. http://arduino.ru/Reference/AttachInterrupt
Если совсем никак в обработчике прерывания без делай обойтись не можете, замените на delayMicroseconds - этот работает.
Если совсем никак в обработчике прерывания без делай обойтись не можете, замените на delayMicroseconds - этот работает.
или написать свою функцию delay(), которая будет работать в обработчике прерывания.
Например
Если совсем никак в обработчике прерывания без делай обойтись не можете, замените на delayMicroseconds - этот работает.
Нет, delayMicroseconds тоже не работает. Всё то же самое, что и с обычным delay. Может, это не совсем то прерывание, которое есть в стандартной библиотеке.
Если совсем никак в обработчике прерывания без делай обойтись не можете, замените на delayMicroseconds - этот работает.
или написать свою функцию delay(), которая будет работать в обработчике прерывания.
Например
У меня тоже была мысль тормозить всё бональным выполнением долгой операции. Но, почему то, это тоже не работает. Как будто задержка выполняется в другом месте. Я вызвал функцию на 49 строке, а в ком порте выводится что серва включена, затем задержка и после этого сразу посылается сигнал на серву и она отключается без уже задержки. Вот уж не знаю как так.
Нет, delayMicroseconds тоже не работает.
delayMicroseconds в прерывании работает. Если у Вас что-то не работает, ищите причину в другом. (кстати, надеюсь, Вы не забыли задержки на 1000 умножить?)
Да работает, но с длительностью void delayMicroseconds(unsigned int us); 65 милисекунд максимум. Если на 1000 множить, то очень быстро кончается разрядность и задержки опять становятся короткими.
Так множить-то с умом надо! Без ума оно всегда так :(
Ну, так вызывайте несколько раз. Я же говорю, с умом надо это делать.
Можно мне не вызывать несколько раз? Я же просто проинформировал.
Вот лично Вам никак низзя! Три штрафных вызова, как минимум!
Нет, delayMicroseconds тоже не работает.
delayMicroseconds в прерывании работает. Если у Вас что-то не работает, ищите причину в другом. (кстати, надеюсь, Вы не забыли задержки на 1000 умножить?)
Пишу по факту. У меня не работает простой код, который активируется библиотекой MsTimer2. Какие ещё могут быть причины? Там же вывод текста в ком порт до и после задержки, который в реальности выводятся одновременно. На 1000 не забыл умножить и даже 10 нулей ставил - результат тот же.
А как вы понимаете одновременность? 16мс - это не так много, как вы думаете.
Относительно того, что я ввожу - это одновременно. Между сообщениями явно в сотни раз меньше 2 секунд. И при чём тут 16мс?
Пишу по факту. У меня не работает простой код,даже 10 нулей ставил - результат тот же.
Вы пишете не по факту, а по своей интерпретации того. что видите, которая (интерпретация) очевидно ошибочная.
У меня не работает простой код
Так покажите его, чем языком-то болтать.
даже 10 нулей ставил
Вот и я о том же. Вам тут уже полфорума пытались объяснить, что так нельзя, а Вы всё ставите.
Не работает не delayMicroseconds, а Ваш "простой код".
Относительно того, что я ввожу - это одновременно. Между сообщениями явно в сотни раз меньше 2 секунд. И при чём тут 16мс?
Всё смешалось - люди, кони...
Ваш MSTimer запускает приаттаченную функцию из ISR? Если да, то никакой delay() там работать не будет. Работать будет delayMicroseconds(), а он позволяет задержать ход времени не более, чем 16.x мс.
К тому же, если вы ознакомились с библиотекой Servo.h, то знаете, что она сама подвешивается на прерывание таймера. А прерывания не работают, покуда вы находитесь в обработчике другого прерывания. И я буду удивлен, если ваша серва без дополнительных извращений вдруг поедет по команде, поданной изнутри ISR.
Просто управляйте сервой вручную - и тогда вам не будут нужны ни дилеи, ни пр. ни др.
Так код всё это время в шапке висел. Продублирую:
С этой же библиотекой и с таким же принципом пробуждения уже писал другую прошивку и она без проблем работала.
Ну и что вы хотите от форума - чтобы вам функцию переписали или IDE пофиксили?
Нет, просто я не понимаю что не так. Если даже не возможно сделать задержку в прирывании, то как можно вызвать функцию из лупа, прервав сон?
Просто управляйте сервой вручную - и тогда вам не будут нужны ни дилеи, ни пр. ни др.
Как это так вручную?
Вот если вас разбудить утром. Что вы будете делать. Разумеется ходить и не спать. Разбудили Ардуину, вот пусть в loop ардуина и пашет. А если вы умудритесь на работе кемарнуть, то ваш напарник вас разбудет. Потому что когда один спит.Другой пашет в двое, да и "жаба" у напарника тоже есть.
Да пусть пашет где угодно, только вот спит она очень крепко и MsTimer её не всегда будит. А уж как перенести всё в loop вообще не представляю.
Читал? http://arduino.ru/forum/programmirovanie/kak-realizovat-periodicheskii-wakeup-iz-sleep-mode
Вот вместо Serial.println("sleep"); и ставь свой код. А потом delay().
Нет, просто я не понимаю что не так. Если даже не возможно сделать задержку в прирывании, то как можно вызвать функцию из лупа, прервав сон?
Просто управляйте сервой вручную - и тогда вам не будут нужны ни дилеи, ни пр. ни др.
Как это так вручную?
Напишите маленький скетч, где будет такое действие, например: for (i=0; i < 5; i++) { digitalWrite(5, HIGH); delayMicroseconds(900); digitalWrite(5, LOW); delayMicroseconds(16000); }
На пин 5 повесьте серву. Запустите скетч. Дергается серва? Теперь меняйте 900 на что-то из диапазона 544...2400.
Принцип понятен? Цикл необязателен, но иногда серва с первого раза не может довернуться до нужной позиции. Так что по месту подбирайте сколько раз ее пнуть так, чтобы с гарантией доехала.
Так код всё это время в шапке висел. Продублирую:
Неправда. В шапке висел с делэями, а не микросендсами.
А вот теперь смотрим на Ваш код и видим, что не такой он просто, как Вам кажется.
Вам тут полфорума раз пять говорили, что delayMicroseconds НЕ БЫВАЕТ больше чем на 16383 мкс. А Вы что делаете? Фигачите её на миллион! Вы вообще читаете, что Вам пишут?
Испрвляйте строку 11 на 10000, а строку 44 на такую
for (int i=0; i<100; delayMicroseconds(OpenTime), i++);
Ура! Заработало! Всем большое спасибо!
Испрвляйте строку 11 на 10000, а строку 44 на такую
for (int i=0; i<100; delayMicroseconds(OpenTime), i++);
Вот так сделать не получилось. Конфликтовала библиотека серво и библиотерка прирываний по таймеру и работало всё не адекватно. Сделал "ручное" управление сервой и убрал её библиотеку.
Вот так сделать не получилось. Конфликтовала библиотека ....
Это уже другой разговор. Не получилось не потому, что делей не работал. Если впредь нужен делей в прерывании, Вы теперь знаете как делать.
Но справедливости ради подчеркну, что совать всю эту бороду в ISR - недостойно джентельмена. Всё должно висеть в лупе или в сетапе с бесконечным циклом унутре.
недостойно джентельмена
https://youtu.be/v1-lr5plK_A?t=3176
— Сэр не слышит.
— А может быть, он вовсе не сэр?
— Отдай лодку, болван! О! Услышал…