millis () не стабильно работает

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

На пины ... повешены светодиоды, которые управляются через входящий шим (с RC- приемника).

По условию, светодиоды должны загораться: второй с небольшой (1с) задержкой относительно первого. И гореть оба постоянно. Когда условие перестает быть верным (команда с пульта пропадает), оба светодиода гаснут. 

При следующем включении всё повторяется, только светодиоды меняются в очерёдности зажигания. Реализовал это с помощью переменных. 

Со сменой очередности - вроде все в порядке. Но вот задержка не всегда срабатывает: при включении команды -загораются оба диода сразу (как будто задержки нет). При повторном включении - уже по очереди. Далее если чуть -чуть подождеть  - снова буду оба включаться. Работают как надо только при быстрых переключения,  в общем.

Делал с помощью millis (), поэтому грешу на нее. Может ли это быть из-за кривых внутренних часов? Или всей платы кривой и китайской? Или millis () с платой не виноваты? 

С переменными как только уже не игрался - результат один. При выполнении условия задержки пробовал присваивать значение миллис - еще одной переменной, чтобы по ней высчитывать интервал времени, но в итоге пришел к тому же результату: светодиоды в большинстве случаев включаются одновременно, и только при быстры переключениях - с должной задержкой. 

#define tataPin 10  // Пуск, соединяется с приемником
#define switPin 11  // Переключение пуска, соед с приемником

/////////////////////////////Пины пуска \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

#define AirsoftPin1 7
#define AirsoftPin2 12

long previousMillisTata = 0;        // храним время последнего переключения (Эйрсофт)
long interval_asinc = 1000;           // интервал между включением первого и второго привода

  int gun1 = LOW;  // Переменная первого привода
  int gun2 = LOW; //Переменная второго привода
  
int tata = 0;  // Переменная первого эйрсофт (для обсчета)
int swit = 0;  // переменная переключателя (Эйрсофт/Ракеты) (для обсчета)


void setup() {
  
  pinMode (tataPin, INPUT); //Входной пин управление приводом
  pinMode (switPin, INPUT); //Входной пин переключение между 2-мя приводами

  pinMode (AirsoftPin1, OUTPUT); //Выход привод 1
  pinMode (AirsoftPin2, OUTPUT); //Выход привод 2
}
  

void loop()
{
{
      tata = pulseIn (tataPin, HIGH, 37880);  //Обсчет входящего ШИМ
    swit = pulseIn(switPin, HIGH, 37880); //Обсчет входящего ШИМ

}


  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Блок управления Эйрсофт!!!!!!!!!!!!!!!!!!!!!!!!

static int asinc = 0; // Переменная асинхронности приводов

static int por = 0; // Переменная порядка начала работы приводов



  digitalWrite(AirsoftPin1, gun1);  // Значение переменной выводим на нужный пин
  digitalWrite(AirsoftPin2, gun2); 


 // Сначавса начинает AirsoftPin1!!!!!!!!!!!!!!!!!!!


if ((tata > 1200)&& (swit<1500)  && gun1 == LOW && por==0&& asinc == 0)

    gun1 = HIGH, asinc = 1;


if(asinc == 1 && gun1 == HIGH  && gun2 == LOW  && por==0 && (millis() - previousMillisTata > interval_asinc))

   gun2 = HIGH,  previousMillisTata = millis(), por=1;


       if (tata < 1100)

  gun1 = LOW, gun2 = LOW; 

///// Теперь второй AirsoftPin1!!!!!!!!!!!!!!!!!!!


if ((tata > 1200)&& (swit<1500)  && gun2 == LOW && por==1 &&asinc == 1)

    gun2 = HIGH, asinc = 2;


if(asinc == 2 && gun2 == HIGH && gun1 == LOW && por==1 && (millis() - previousMillisTata > interval_asinc))

   gun1 = HIGH,  previousMillisTata = millis(), asinc = 0, por=0;


       if (tata < 1100)

  gun1 = LOW, gun2 = LOW; 
  



}  //Крайняя фигурная скобка

 

bwn
Offline
Зарегистрирован: 25.08.2014

В коде не разбирался, но 99.9% кривой, копайте в нем. Вставьте сериалы в контрольных точках, смотрите какие значения какая переменная принимает. Кварц конечно на МК не супер, но его отклонения могут на суточных интервалах сказываться, а не на секундных. Где то у вас интервал проскакивает свое значение, попробуйте на 5000 изменить и посмотрите.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Да нет,bwn, этот гений время начала своих танцев не фиксирует. Когда подряд, то успевает к фиксации в строках 60 и 77. А «чуть погодя» запомненное время становится очень старым. И оба диодо стабатывают одновременно.... Задержка то уже случилась. Гы!

bwn
Offline
Зарегистрирован: 25.08.2014

wdrakula, я в первом if-е забуксовал и даже читать дальше не стал. Serial.println наше фсе.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:

В коде не разбирался

Зря! Там песня, а не код! Получил большое удовольствие.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Зря! Там песня, а не код! Получил большое удовольствие.

А как прекрасны операторы через запятую?

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

bwn пишет:

В коде не разбирался, но 99.9% кривой, копайте в нем. Вставьте сериалы в контрольных точках, смотрите какие значения какая переменная принимает. Кварц конечно на МК не супер, но его отклонения могут на суточных интервалах сказываться, а не на секундных. Где то у вас интервал проскакивает свое значение, попробуйте на 5000 изменить и посмотрите.

Спасибо что развеяли сомнения на счет кварца. 
Прямизной кода правда похвастаться не могу, в "теме" букавльно пару месяцев, и факультета IT за плечами нет. Гуманитарий я :)  Но хочу учиться) 

Пробовал поменять интервал на 5000 - задержка начинает работать, но 5с - это много, я собирался настраивать ее в пределах до 1с. 

wdrakula пишет:
Да нет,bwn, этот гений время начала своих танцев не фиксирует. Когда подряд, то успевает к фиксации в строках 60 и 77. А «чуть погодя» запомненное время становится очень старым. И оба диодо стабатывают одновременно.... Задержка то уже случилась. Гы!
 
Вот-вот-ввот!! Это оно! Очень похоже на правду! 
Как правильно фиксировать это "время начала"? Достаточно одного раза в начале цикла? Или при каждом обращении к millis () ?  Пробовал записывать время в переенную, которая потом участвует в условии
unsigned long  previousMillisTata = millis();
 
Но программа начинает еще не правильнее работать (если это прописать один раз, и если перед каждым использованием millis, загорается только - первый диод). 
Проболвал и "разбивать" эту переменную на две (делать свою для каждой части цикла).  Но результат тот же... 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Издеваетесь?

в 55 и 72 строки добавьте    previous-bla-bla-bla=millis()

----------------

остальные свои косяки сами ищите... или Женя поможет - он добрый. ;) Клапауция еще можно попросить.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

а у меня возник вопрос - Вы вообще как это создавали? Просто есть серьезное подозрение, что Вы не очень понимаете, что в этом коде происходит?

То есть Вы что-то взяли за основу, не понимая, а потом стали приделывать костыли из говна и палок. Так?

bwn
Offline
Зарегистрирован: 25.08.2014

1. К Лешаку, находим там и читаем про миллис, пока не наступит просветление. Правда сейчас что то у меня не сконнектилось, попозже попробуйте.
2. Что стать адептом тележурнала "Хочу все знать", берем сериалпринты и расставляем в контрольных точках, какие значения у наших переменных.
3. На основании полученной информации, курим что нибудь забористое и начинаем креативить на предмет, почему моя переменная делает не так.
 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:

курим что нибудь забористое ... почему моя переменная делает не так.

Так вроде уже всё выкурено. Миллис вон уже нестабилен.

Помнится в 80ы-е юзера так задолбали апломбными заявлениями, что у нас что-то не так работает, что на дверь комнаты дежурной смены мы повесили табличку: "Да, у нас фортран не работает, и чо?"

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

bwn пишет:

курим что нибудь забористое ... почему моя переменная делает не так.

Так вроде уже всё выкурено. Миллис вон уже нестабилен.

Помнится в 80ы-е юзера так задолбали апломбными заявлениями, что у нас что-то не так работает, что на дверь комнаты дежурной смены мы повесили табличку: "Да, у нас фортран не работает, и чо?"

У нас компьютер отчет стер.
Что делали?
Ничего, он сам.
Вот такие были у нас брутальные компьютеры.)))) ИИ отдыхает.
И это уже 486 и первые пеньки. Что в 80-х было вообще не представляю, я тогда еще деревянный в виде линейки юзал.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

в 84-ом я распечатал себе свой первый экземпляр Кернигана и Ричи на АЦПУ, на СМ-4 (вроде Мера польская была).

a5021
Offline
Зарегистрирован: 07.07.2013

Вы все врети. Стока люди не живут. :)

bwn
Offline
Зарегистрирован: 25.08.2014

a5021 пишет:

Вы все врети. Стока люди не живут. :)

Эт план такой, пенсионный фонд обанкротить.))))

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

Слёзы счастья!)))

Спасибо wdrakula,  про 55 и 72 строки - это было круто!)  Теперь все работает идеально

Даже видео снял на радостях)

https://vimeo.com/202012131

ЕвгенийП пишет:

Так вроде уже всё выкурено. Миллис вон уже нестабилен.

Простите, только сейчас понял, на сколько провокационен заголовок!) 
Да и китайцы не виноваты, отличные платы делают!))) 

Спасибо за ресурс Лешака, буду вчитываться. Что касается остального кода, то пока одолевать людей не буду, раз он работает, возможно скоро сам буду так же смеяться над своими ошибками ;) 

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

А я получается, писал эту фразу, писал,  "previous-bla-bla-bla=millis()" , но не в действии, а где-то между ними. Поэтому, она не выполнялась или выполнялась не правильно...  

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

это потому, что какой-то "гей" научил Вас писать операторы через запятую.

Поэтому чудо, что у Вас хоть что-то работает.

оператор if используется так:

if (a>b && c<d || x==y)
   {
   operator1;
   operator2;
   operator3;
   operator4;
   }
else
  {
   operator7;
   operator8;
  }

 

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

wdrakula пишет:

это потому, что какой-то "гей" научил Вас писать операторы через запятую.

Поэтому чудо, что у Вас хоть что-то работает.

оператор if используется так:

if (a>b && c<d || x==y)
   {
   operator1;
   operator2;
   operator3;
   operator4;
   }
else
  {
   operator7;
   operator8;
  }

 

Да, спасибо! Теперь только так! 

Наверно уже надоел, но все же спрошу)

Есть еще одна часть кода того же моего "масштабного" проекта. 

 

#define ledPinRok 13 // Пин спуска

#define tataPin 10  // Спуск, соединяется с RC приемником
#define switPin 11  // Переключение функции спуска, соед с RC приемником

int ledStateRok = LOW;             // Переменная спуска
long interval_Rok = 2000;           // интервал спуска
long previousMillisRok = 0;        // храним время последнего спуска
int RS = 0; //Переменая для работы спуска
static int OneRok = 0; //Переменная для совершения цикла спуска один раз


int tata = 0;  // Переменная кнопки
int swit = 0;  // переменная переключателя функции спуска

void setup() {

  pinMode (tataPin, INPUT); //Входной пин спуск
  pinMode (switPin, INPUT); //Входной пин переключение

  pinMode (ledPinRok, OUTPUT);
  
}


void loop()
  {

    /////////////////// Блок обсчета входящего ШИМ!!!!!!!!!!!!!!!!


    {
      tata = pulseIn (tataPin, HIGH, 37880); //Обсчет входящего ШИМ
      swit = pulseIn(switPin, HIGH, 37880); //Обсчет входящего ШИМ
    }

    ////////////////////// Блок вывода значенй ШИМ на каналах на сериал монитор\\\\\\\\\\\\\\\\\\\

    Serial.print ("Channel #3: ");
    Serial.println(tata);
    Serial.print ("Channel #4: ");
    Serial.println(swit);




  //!!!!!!!!!!!!Блок переменной zRok !!!!!!!!!!!!!!!!!!

  static int zRok = 0; //Переменая для работы спуска

  if ((tata > 1200) && (swit > 1500))

  {
    zRok = 1;
  }

  if (tata < 1200)  // Если кнопка выключена
  {
    zRok  = 0; // спуск всегда выключено
  }

  //!!!!!!!!!!!!Блок переменной OneRok  !!!!!!!!!!!!!!!!!!

  if (OneRok == 1)  // Есть цикл один раз выполнялся,
  {
    ledStateRok = LOW; //то второй раз не заработает  до того как не выключится кнопка
  }

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Блок управления спуском!!!!!!!!!!!!!!!!!!!!!!!////////

  digitalWrite(ledPinRok, ledStateRok); //Присваиваем пину спуска значение перменной

  unsigned long currentMillisRok = millis(); //Объявляем переменную времени

  if ((OneRok == 0) && (zRok  == 1)) //Если кнопка нажата и цикл не выполнялся

  {
    ledStateRok = HIGH; // спуск срабатывает
    currentMillisRok  = millis();   // !!!запоминаем "время начала танцев"!!!
    RS = 1;
  }

  if ( (RS == 1) && (currentMillisRok - previousMillisRok > interval_Rok)) //Если спуск включен,
    // ИИ прошло время больше интервала
  {
    ledStateRok = LOW; //Спуск выключается
    previousMillisRok  = currentMillisRok ;  //Запоминаем время срабатывания
    OneRok = 1; //   переменная однократного исполнения цикла получает=1
    RS = 0;   // обнуляем переменную спуска


  }
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Блок обнуленя переменной "OneRok"!!!!!!!!!!!!!!!!!!!!!!!////////
  if ((OneRok) == 1 && (zRok == 0)) //Если цикл один раз выполнялся, и уровень оборотов пересек нижнюю границу
  {
    OneRok = 0; // то переменная одноразового совершения цикла обнулется (цикл можно выполнить снова)
  }

   }  //Крайняя фигурная скобка

Задачей было сделать так, чтобы светодиод включился один раз на определенное время (interval_Rok) и погас,  до выключения и новго включения тумблера. Примерный код (кривой) у меня уже был. Сделал по тому же принципу, через millis (), постарался учесть замечания. 

И всё вроде бы работает, вот только при превичном включении тумблера на пульте RC, диод не всегда загорается (в большинстве случаев не загорается). 

В чем может быть дело? Кажется я не учел какой-то принципиальный момент.  
По сериал-монитору значения на входе изменяются. А вот где его воткнуть еще раз, чтобы посмотреть переменные - не соображу.

Да, еще такой симптом - время включения светодиода - не всегда одинковое, не смотря на то, что интервал ничего не именяет. Пробовал объявлять интервал const, пробовал unsigned  - та же петрушка

 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

79 строка. Не  каррент, а привиус.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

представьте  вместо контроллера самого себя, только ускоренного,как Флеш ;). с секундомером. Каррент - это то, что показывает секундомер сейчас, а привиус - то, что вы записали на бумажке. Так становится нагляднее?

bwn
Offline
Зарегистрирован: 25.08.2014

kak-dela007@mail.ru пишет:

 Пробовал объявлять интервал const, пробовал unsigned  - та же петрушка

Вы их таки не пробуйте, они не черешня, а разберитесь и усвойте, какое магическое слово что значит.))))

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:
Вы их таки не пробуйте
Так, що його пробувати, сало - воно сало і є. :)

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

bwn пишет:
Вы их таки не пробуйте
Так, що його пробувати, сало - воно сало і є. :)

Не, у ТС что то все петрушка получается. Было б сало, еще куда ни шло.)))

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

wdrakula пишет:

представьте  вместо контроллера самого себя, только ускоренного,как Флеш ;). с секундомером. Каррент - это то, что показывает секундомер сейчас, а привиус - то, что вы записали на бумажке. Так становится нагляднее?

Гораздо))) А я всё представляю время как что-то связанное с бесконечной вселенной))) 
 

Но если в 79 строку ввернуть previousMillisRok вместо currentMillisRok, получается странная картина: 

Диод загорается и горит. А когда кнопку выключаешь - через интервал гаснет. Но иногда и правильно стработает пару раз, а потом опять за своё. 

Сижу, разбираюсь, но пока без сала:) 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

kak-dela007@mail.ru пишет:

Но если в 79 строку ввернуть previousMillisRok вместо currentMillisRok, получается странная картина: 

Диод загорается и горит. А когда кнопку выключаешь - через интервал гаснет. Но иногда и правильно стработает пару раз, а потом опять за своё. 

Сижу, разбираюсь, но пока без сала:) 

Вы, признак того, что цикл начался (OneRok) j обнуляете при окончании цикла, а нужно при НАЧАЛЕ.

Перенесите OneRok=0;  в первый if, рядом с 79 строкой.

Понятно? Тогда это условие сработает ровно один раз, при нажатии кнопки.

bwn
Offline
Зарегистрирован: 25.08.2014

wdrakula, добрый вы. Вот сериалпринты ТС явно пользовать не желает, предпочитает спросить, а это не гут.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:

предпочитает спросить

Никакие отладчики, сериалпринты и прочие эти ваши джитэги никогда не заменят живого человеческого общения! Долой виртуальную землю, резиновых женщин и безалкогольное пиво!

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

bwn пишет:

предпочитает спросить

Никакие отладчики, сериалпринты и прочие эти ваши джитэги никогда не заменят живого человеческого общения! Долой виртуальную землю, резиновых женщин и безалкогольное пиво!

Не, я лимит вопросов предпочитаю приберегать на случай, когда действительно в тупик залезу (мой личный).

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

bwn пишет:

wdrakula, добрый вы. Вот сериалпринты ТС явно пользовать не желает, предпочитает спросить, а это не гут.

Учусь и ими пользоваться) 
И вот как раз сериал монитор показывает, что интервал уже как-бы прошел (хотя это не правда), и порой не зажигает мой свето-диод, или зажигает на меньшее время. 

Время начала танцев обозначаю..., все по схеме вроде делаю...  Странно, не пойму почему так. 

Из кода убрал лишние переменные,  теперь он сталь короче 

#define ledPinRok 13 // Пин спуска

#define tataPin 10  // Спуск, соединяется с RC приемником
#define switPin 11  // Переключение функции спуска, соед с RC приемником





 int tata = 0;  // Переменная кнопки
int swit = 0;  // переменная переключателя функции спуска

void setup() {

  pinMode (tataPin, INPUT); //Входной пин спуск
  pinMode (switPin, INPUT); //Входной пин переключение

  pinMode (ledPinRok, OUTPUT);

   Serial.begin(9600);

  
}


void loop()
  {

    /////////////////// Блок обсчета входящего ШИМ!!!!!!!!!!!!!!!!


    {
      tata = pulseIn (tataPin, HIGH, 37880); //Обсчет входящего ШИМ
      swit = pulseIn(switPin, HIGH, 37880); //Обсчет входящего ШИМ
    }

    ////////////////////// Блок вывода значенй ШИМ на каналах на сериал монитор\\\\\\\\\\\\\\\\\\\


   // Serial.print ("Channel #3: ");
   // Serial.println(tata);
  //  Serial.print ("Channel #4: ");
  //  Serial.println(swit);
  //  Serial.println("------------");

 


  //!!!!!!!!!!!!Блок переменной zRok !!!!!!!!!!!!!!!!!!
static int zRok = 0; //Переменая для работы спуска
 static int ledStateRok = LOW;             // Переменная спуска
unsigned long interval_Rok = 2000;           // интервал спуска
  unsigned long previousMillisRok = 0;        // храним время последнего спуска

  unsigned long currentMillisRok = millis(); //Объявляем переменную времени



  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Блок управления спуском!!!!!!!!!!!!!!!!!!!!!!!////////


 Serial.print ("Svet ");
  Serial.println(ledStateRok);
   
  Serial.print ("Peremenneya: ");
  Serial.println(zRok);

 
 if ((tata > 1200) && (swit > 1500)&& (zRok != 2)) 
 {
  zRok = 1;
 }

if (( zRok  == 2) && (tata < 1200)) //Если цикл один раз выполнялся, и кнопка выключена
  {
  zRok = 0; // то переменная одноразового совершения цикла обнулется (цикл можно выполнить снова)
  }

  
  if  (zRok  == 1)//Переменная =1

  {
    ledStateRok = HIGH; // спуск срабатывает
     previousMillisRok  = millis();   // !!!запоминаем "время начала танцев"!!! ??? - поменял на превиус...
     
  } 
else
{
  ledStateRok = LOW;
}

  if ((ledStateRok == HIGH)&& (currentMillisRok - previousMillisRok > interval_Rok)) //Если спуск включен,
    // ИИ прошло время больше интервала
  {
    ledStateRok = LOW;
     previousMillisRok  = currentMillisRok ;  //Запоминаем время срабатывания
     zRok = 2;
    
  }

 
digitalWrite(ledPinRok, ledStateRok); //Присваиваем пину спуска значение перменной





   }  //Крайняя фигурная скобка

 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вы, все таки доведете меня до греха!

В первой версии кода, не надо ничего делать КРОМЕ ТОГО, что в 79 строке СТАРОГО, мля, кода, написать :

previousMillisRok  = millis(); OneRok=1;

Всё. На этом мы прекратим изучение Ваших бессмерных творений. Оставьте их потомкам. Я - устал.

kak-dela007@mail.ru
Offline
Зарегистрирован: 28.12.2016

wdrakula пишет:

Вы, все таки доведете меня до греха!

В первой версии кода, не надо ничего делать КРОМЕ ТОГО, что в 79 строке СТАРОГО, мля, кода, написать :

previousMillisRok  = millis(); OneRok=1;

Всё. На этом мы прекратим изучение Ваших бессмерных творений. Оставьте их потомкам. Я - устал.

Хорошо, Вы уже и так очень помогли!)