Прошу помочь с millis
- Войдите на сайт для отправки комментариев
Пнд, 28/05/2018 - 16:25
Здравствуйте господа.
Прошу вашей помощи. для управления сервой сделал такую програмку. при подключении питания серва выставляется в определённое положение(заданое в программе), при нажатии кнопки и её удержании серва через 2 сек. поворачивается на определённый угол и стоит там пока нажата кнопка, после отпускании кнопки серва сразу возвращается назад. С движением сервы проблем нет, а вот с паузой непонятки, бывает что сразу по нажатию срабатывает, бывает больше трёх сек пауза, с возвратом тоже ерунда какая-то, должна сразу возвращаться, а она то нормально вернётся то с задержкой( от одной до трёх сек.). Подскажите пожалуйста, где ошибка, нифига не могу понять.
#include <Servo.h> // подключаем библиотеку для работы с сервоприводом Servo servo; // объявляем переменную servo типа "servo" int button_pin = 4; // пин кнопки int buttonState; // переменная для хранения состояния кнопки unsigned long timing; void setup() { pinMode(button_pin, INPUT); // Инициализируем цифровой вход. servo.attach(5); // привязываем сервопривод к аналоговому выходу 5 servo.write(170); //ставим вал под 0 } void loop() { if (millis() - timing > 2000){ // Вместо 2000 ставим нужное значение паузы timing = millis(); buttonState = digitalRead(button_pin);// считываем значения с входа кнопки } if (buttonState == HIGH) { servo.write(90); //ставим вал на 125 } else { servo.write(170); //ставим вал на 0 } }
так у вас в коде написано совсем не то, что вы хотите. Сначала четко пропишите алгоритм. Сейчас у вас проблемы с логикой. Посмотрите внимательно на loop - в первом условии вы зачем-то сначала ждете 2 сек, а только потом читаете пин кнопки. какой в этом смысл? А во втором включаете серву сразу. как-только переменная пина кнопки стала ХАЙ. И где задержка?
Нужно сделать примерно так - в цикле читаете кнопку, если она ХАЙ - только с этого момента начинаете отсчитывать 2 сек. При этом продолжаете проверять кнопку. Если к концу 2 сек кнопка все еще нажата - поворачиваете серву...
У Вас в коде отсутствует "через 2 секунды". Вы раз в две секунды опрашиваете кнопку, поэтому логично, что поворот вала начинается сразу после того, как состояние кнопки определилось как HIGH. Я бы на Вашем месте все время бы опрашивал кнопку, в каждом проходе лупа. И тогда уже от ее состояния либо инициировал задержку с последующим поворотом вала, либо возвращал вал в исходное.
вот сначала сделал опрос кнопки, если она хай то ждём 2 сек. поворачиваем серву. (хотя я так и не понял как этот millis работает, поэтому действую больше наугад:)), в таком варианте она поворачивается без пауз.
Пока не поймете миллис (что там понимать-то?) - толку не будет.
В данном коде ваша ошибка в том, что вы в начале периода в 2 сек не запоминаете время, поэтому задержка не срабатывает.
Внимательно изучите примеры кодов с миллис - что, в каком порядке - и главное! - для чего - делается.
а именно строки 17 и 18 у Вас написаны не правильно. Вам СНАЧАЛА надо запомнить текущее милис, а потом ничего не делать, или делать, как реализуете, в течении какого-то периода.
ок. спасибо, буду пробовать.
я понимаю что в этих строчках ошибка, но чтото не могу разобраться. буду по новой изучать:)
я понимаю что в этих строчках ошибка, но чтото не могу разобраться. буду по новой изучать:)
timing = millis();
Вы запомнили то значение милис, которое было на момент присваивания. А милис между тем дальше себе побежал, вперед. И Вам надо подождать, пока он убежит от запомненного значения на 2 сек. То есть Вам , например, надо ничего не делать, пока милис не убежит вперед на значение 2000. То есть словами это звучит :
до тех пор, пока разница миллис минус запомненное значение будет менее 2000 - ничего не делать. Вам остается эту фразу просто реализовать в коде.
freeman86,Что бы не жевать одно и тоже, то вы не организовали флаг и дальше if(флаг==событию &&<время истекло>)#23
Получается еще нужно где-то написать функцию, которая будет входить в состояние TONE2500_STATE? Иначе условие не выполнится..
Разумеется . я в setup это сделал.
Просто у меня это не начальное состояние, и программа вероятно будет разростаться, поэтому я каждое состояние писал в виде функции, и swith-case эти функции будет крутить, а функция типа select_state подставлять в swith-case нужные номера состояний :)
Вообще, не очень понимаю с точки зрения логики, почему обязательно должно быть уже какое-то состояние, чтобы таймер работатл правильно ) точнее, не так. swith-case может иметь 30-50-100 case`s. И как быть, если надо из любого кейса переходить в любой другой...?
я эту тему уже здесь на форуме жевал
А где почитать ваши объяснения? ) Я хочу сам понять :)
попробуй от сюда #254
swith-case может иметь 30-50-100 case`s. И как быть, если надо из любого кейса переходить в любой другой...?
никак. Не бывает таких систем, которым надо переходить "из любого кейса в любой". Количество переходов всегда ограничено и должно происходить по строго заданным условиям, а не в произвольном порядке.
Вообще, ситстема, у которой слишком много состояний - плохо спроектирована. У хорошего конечного автомата на одном уровне обычно не более десятка состояний. Более сложные системы обычно состоят из нескольких автоматов - обычно последовательных, параллельных или вложенных один в другой.
swith-case может иметь 30-50-100 case`s. И как быть, если надо из любого кейса переходить в любой другой...?
никак. Не бывает таких систем, которым надо переходить "из любого кейса в любой".
Вообще-то именно "из любого в любое".
Переход должен осуществляться согласно матрице переходов. Какие из клеток этой матрицы будут задекйствованы, а какие останутся пустыми - дело разработчика. Так что теоретически именно из любого в любое.
Количество переходов всегда ограничено и должно происходить по строго заданным условиям, а не в произвольном порядке.
Естественно, ограничено. Если у нас N состояний, то в матрице переходов N*N клеток (включая диагональ).
2ТС: Другое дело, что "обязательно должно быть уже какое-то состояние" - это как бы по определению. Коль скоро мы вводим конечный автомат, то он обязательно находится в каком-то состоянии. Это как переключатель - он просто физически не может не находиться в одном из положений. Разве что его разломать.
вот так заработало, только всё равно непонятно почему работает когда эта строка "timing = millis();" именно в этом месте, почему если её поставить перед "else" то не работает?
В таком варианте состояния бегают по кругу, пока А =true, но засада с таймерами.
В таком варианте таймеры работают как надо, но все застывает на последнем состоянии. Как сделать так, чтобы они бегали по кругу, пока А = true?
Когда я попытался вместо if(A) сделать while(A), прога перестала работать. Почему так?
Разобрался только что. Чтобы состояния бегали по кругу, надо в последнем состоянии сделать переход на начальное. Но не будет ли конфликта в при определенном стечении обстоятельств? Ведь если например if(!A) {state = one) и при условии if(A) в конец всех состояний будет переход к состоянию one, то непонятно в какой момент такая программа может рухнуть? Или тут все нормально?
все равно неверно. У вас таймер запускается не в момент нажатия кнопки, а черти когда.
Неужели так сложно разобраться один раз, как работает миллис???
Всего два действия
1. при нажатии кнопки запустили тацмер
2. Если таймер истек и кнопка нажата - поворачиваем серву
И где у вас первый шаг? - как не было, так и нет.
freeman86, Что здесь сложного.
Пух, по учебнику (да и по здравому смыслу), состояния перебираюца через switch
Они и перебираются с помощью switch. Это просто кусок кода, и эта функция отправляет в switch номера состояний.
Они и перебираются с помощью switch. Это просто кусок кода, и эта функция отправляет в switch номера состояний.
ну это очень неоптимальная функция. Думаю, квон так написал для примера и чтоб новичков не баловать :)
все равно неверно. У вас таймер запускается не в момент нажатия кнопки, а черти когда.
Неужели так сложно разобраться один раз, как работает миллис???
Всего два действия
1. при нажатии кнопки запустили тацмер
2. Если таймер истек и кнопка нажата - поворачиваем серву
И где у вас первый шаг? - как не было, так и нет.
я не знаю как запустить таймер
сделал так, не знаю правильно или нет, но вроде работает.
P.S. не, так неправильно работает.
мда, походу программирование это не моё.
мда, походу программирование это не моё.
Не стоит отчаиваться! Сейчас много прекрасных коррекционных школ для детей и взрослых с задержкой в развитии.
================
Тебе написали ДВА пункта. Можно ли увидеть, что ты верно прочитал написанное и перевел на язык С?
1. при нажатии кнопки запустили тацмер
if (КНОПКА_НАЖАТА) timing = millis();
2. Если таймер истек и кнопка нажата - поворачиваем серву
if ( (millis() - timing > ВРЕМЯ_ОЖИДАНИЯ) && КНОПКА_НАЖАТА) ПОВЕРНУТЬ_СЕРВУ();
----------------
Не вникал в проблему, когда тебе нужно обратно серву вернуть, но вот прямо так и пиши, как думаешь.
Самоуничижения для вызова жалости - это низко. Нужно себя уважать, кому же еще можно доверить столь ответственное дело???
мда, походу программирование это не моё.
Не стоит отчаиваться! Сейчас много прекрасных коррекционных школ для детей и взрослых с задержкой в развитии.
================
Тебе написали ДВА пункта. Можно ли увидеть, что ты верно прочитал написанное и перевел на язык С?
1. при нажатии кнопки запустили тацмер
if (КНОПКА_НАЖАТА) timing = millis();
2. Если таймер истек и кнопка нажата - поворачиваем серву
if ( (millis() - timing > ВРЕМЯ_ОЖИДАНИЯ) && КНОПКА_НАЖАТА) ПОВЕРНУТЬ_СЕРВУ();
----------------
Не вникал в проблему, когда тебе нужно обратно серву вернуть, но вот прямо так и пиши, как думаешь.
Самоуничижения для вызова жалости - это низко. Нужно себя уважать, кому же еще можно доверить столь ответственное дело???
да я уже весь гугл перечитал за неделю ( по вечерам) везде один и тотже пример описывают, причём слово в слово, но подробностей ни где нет. Я не знал что таймер запускается именно так: timing = millis(); , в примерах эта строка всегда идёт в конце.
if ( (millis() - timing > ВРЕМЯ_ОЖИДАНИЯ) && КНОПКА_НАЖАТА) ПОВЕРНУТЬ_СЕРВУ();
так я тоже пробовал, только немного иначе
if ((кнопка нажата) && (millis() - timing>2000)) {
повернуть серву
}
как понимал так и делал (я не программист, пару недель назад решил попробовать).
по поводу самоунижения для вызова жалости, да даже мысли не было, просто если это действительно настолько элементарно, а я не могу понять, ну значит это не моё, дальше походу ещё сложнее будет.
ну всётаки благодаря вам и всем кто подсказывал я теперь примерно понимаю как она работает.
Спасибо всем.
да я уже весь гугл перечитал за неделю ( по вечерам) везде один и тотже пример описывают, причём слово в слово, но подробностей ни где нет. Я не знал что таймер запускается именно так: timing = millis(); , в примерах эта строка всегда идёт в конце.
да ладно, почему установка времени в конце?
Неужели ничего подобного не попадалось?
да я уже весь гугл перечитал за неделю ( по вечерам) везде один и тотже пример описывают, причём слово в слово, но подробностей ни где нет. Я не знал что таймер запускается именно так: timing = millis(); , в примерах эта строка всегда идёт в конце.
да ладно, почему установка времени в конце?
Неужели ничего подобного не попадалось?
нет, не видел, может проглядел.
везде примерно это:
unsigned
long
timing;
// Переменная для хранения точки отсчета
void
setup() {
Serial.begin(9600);
}
void
loop() {
/*
В этом месте начинается выполнение аналога delay()
Вычисляем разницу между текущим моментом и ранее сохраненной точкой отсчета.
Если разница больше нужного значения, то выполняем код.
Если нет - ничего не делаем
*/
if
(millis() - timing > 10000){
// Вместо 10000 подставьте нужное вам значение паузы
timing = millis();
Serial.println (
"10 seconds"
);
}
}
всё равно не работает
всё равно не работает
похоже, программирование и правда не ваше :(
Я уже буквальный пример вам дал, как делать - а вы зачем-то половину кода из него выкинули. Думаете, лишнее? - а без него не сработает.
Если не в силах разобраться сами - то хоть повторяйте внимательно.
да вроде всё сделал так как вы написали.
В результате исследования английских ученых они выяснили, что в исследовании английские ученые были лишними.
qwone, сегодня переделал подглядывая в ваш пример, который выше. Спасибо, все работает. Единственно чего я не понимаю, для чего нужно past = mill в функции void stand?
freeman86, а подумать!! В ардуино в большинстве случаев перехода по состоянию надо еще и фиксировать время перехода. Вот я это и совместил.
мне не очень понятен порядок работы. mill = millis() написано ниже. Компилятор это сам расставляет, или скетч как пример, но он не рабочий?
Скетч рабочий. Загрузите и проверьте последовательно отработает все события и остановится.
Может вы до конца не понимаете как программировать с помощью цифрового автомата.
разумеется я до конца не понимаю, иначе бы я не задавал глупых вопросов в этой теме :)
Можете объяснить, как эта функция может работать, если присваивание времени переменной происходит после условия? она работает: 250 мс пищит, 250мс молчит. Ну то есть работает как задумано...я не понимаю.
Вот как вы варите яйца. Ждете когда закипит вода. Как закипела вода вы кладете яйца в кипяток и засекаете время (фиксируете время ). Потом ждете немного и смотрите на время теперешнее . Разница времени и есть время когда яйца находятся в кипятке. Работаете в таком режиме некоторое время когда разница не станет 10 минут. Все яйца надо извлекать. Так и здесь . millis() это часы. переменная past это блокнот куда вы пишете время укладки яиц. Флаг это яйца на столе или в кипятке.
Итак простой алгоритм Когда кладете яйца в кипяток вы взводите флаг-"яйца в кипятке" и засекаете время past=millis().
А теперь регулярно если "яйца в кипятке" И разница больше 10 минут, то флаг "яйца на столе" и извлечь яйца. Можно закладывать новую партию яиц в кипяток.
ПС: Функция бредовая.
сам алгоритм я понимаю. Он очень простой. Но я не понимаю как это выразить в С++. Вы говорите что функция бредовая. Я согласен. Но она рабоатет, причем работает как задумано. Либо тут ошибка накладывается на ошибку, либо непонятно почему она работает?
сам алгоритм я понимаю. Он очень простой. Но я не понимаю как это выразить в С++.
Можно воспользоваться простым приемом:
1. Записать алгоритм по-русски.
2. Перевести с русского на Си++.
человеческий язык сильно отличается от языка программирования )
человеческий язык сильно отличается от языка программирования )
человеческий язык сильно отличается от языка программирования )
В данном случае это несущественно.
Я так понимаю, Вы не можете написать алгоритм по-русски?
Могу конечно :)
Ну так напишите. За чем дело стало?
человеческий язык сильно отличается от языка программирования )
Уху, а русский от аглицкого, а уж китайский.(((( Но ведь обсчаются как то?
На мой взгляд, разница между СИ и русским на порядки ниже, чем между русским и аглицким. ИМХО.
вот такой код получился, может и не правильный, но работает идеально.
всем спасибо.