Отдельная функция задержки на основе millis()

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

Нужна отдельная фунция на основе millis(), которая бы была полным аналом фунции delay(). Я попытался сделать что то подобное, но ничего не вышло. В чем ошибка?

void time(int m)
{
  int i=0;
 unsigned long b = millis();
   long c=b+m;
  while(b<c)
   { i=0;
 }}
 
 void osnov()
 {
   int a;
   int i;
       for (a=0;a<5;a++)
  {
    {
	 PORTC=0x00;
	 time(1000);
	 }
   	 {
	 PORTC=0xFF;
	 time(1000);
	 }
	}
 }

 

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

Судя по данным с терминала, переменная b не изменяется, поэтому цикл while становится бесконечным и программа зависает. Почему не меняется b? это же значение должно изменяться кажду миллисекунду

MaksMS
Offline
Зарегистрирован: 11.03.2013




void time(int m)
{
  int i=0;
 unsigned long b = millis();
  unsigned long c=b+m;
  while(millis()<c)
   { i=0;
 }}

как-то так ,хотя не понятен смысл в такой функции

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

отлично, заработало, вот только проблема - эта функция не работает параллельно с обработчиком кнопки с пульта, хотя должен. Вот весь код:

#include <IRremote.h>
#include <IRremoteInt.h>

int RECV_PIN = 8;

#define POP              0X40BF18E7   //значение кнопки
 
IRrecv irrecv(RECV_PIN);
 
decode_results results;
 
void time(int m)
{
  int i=0;
  unsigned long b = millis(); 
  unsigned long c=b+m;
  while(millis()<c)
   { i=0;
 }}
 
 void osnov()
 {
   int a;
   int i;
       for (a=0;a<5;a++)
  {
    {
	 PORTC=0x00;
	 time(1000);
	 }
   	 {
	 PORTC=0xFF;
	 time(1000);
	 }
	}
 }
 
void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Inicializamos el receptor
  DDRC=0xFF;
  unsigned char i;
  int a;
}

void loop()
{
  if (irrecv.decode(&results)) {
    if ( results.value != 0xFFFFFFFF) {
      switch (results.value) { 
           case POP        : osnov(); break;}
    }
irrecv.resume(); // Receive the next value
  }
}

Я поэтому и делал специальную функцию заменяюшую delay, чтобы она работала параллельно с обработчиком фотоприемника

ites
Offline
Зарегистрирован: 26.12.2013

CEBKACooler пишет:

отлично, заработало, вот только проблема - эта функция не работает параллельно с обработчиком кнопки с пульта, хотя должен. Вот весь код:

Программа всегда работает так, как написал программист. Если она работает не так, как он думает, она должна работать, значит он сделал ошибку, программа же ничего не должна программисту. Правильный подход в том, что функция задержки исполнения программы, как это ни смешно звучит, не должна блокировать исполнение программы. Она должна информировать основной поток исполнения о том, закончилось ли время задержки. Программа должна выглядеть как набор состояний с описанными правилами перехода между ними.

P.S. Чувствую себя старым и седым профессором. Это не так :)

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

ites пишет:

 Она должна информировать основной поток исполнения о том, закончилось ли время задержки. Программа должна выглядеть как набор состояний с описанными правилами перехода между ними.

Это все здорово и я сам это понимаю, но как реализовать это программно? Сделал по примеру, где по идеи все должно работать правильно. Так в чем же у меня тогда ошибка? или есть другой пример? Я конечно понимаю ,что когда человек допирает сам, это в 2 раза приятнее, но можно без загадок ответить

MaksMS
Offline
Зарегистрирован: 11.03.2013


Ну тогда уж так:




void time(int m)
{
  unsigned long b = millis(); 
  unsigned long c=b+m;
  while(millis()<c)
   { 
irrecv.resume();
 }}

 

Подход конечно не стандартный ,но работать должен 

Обычно делают такие вещи по другому,почитайте тему тут "мигаем светодиодом без delay"

 

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Задача какая ? После принятия команды от IR опустить порт PORTC на 1 секунду, потом поднять его на 1 секунду и так и оставить ? А если пока идет работа с портом придет еще одна команда, что сделать ? на чать работу с портом заново или проигнорировать ?

 

 

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

MaksMS, так я по этому примеру и делал эту функцию. Только в примере она все время находится в самом цикле loop, поэтому вместо условия if стоит цикл while.

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

Задача такая: опрашивать все время порт фотоприемника на наличие сигнала пульта. Как только сигнал поступил, запускается основная программа, которая записана в функции osnov(). Сейчас в моем примере он должен просто помигать 5 раз и остаться в положение 5v на выходе порта. Потом там будет  очень большой код последовательного включения портов.

Так вот сейчас мой контроллер мигает портами, но не реагирует на сигнал с пульта, пока не закончится работа функции osnov(), хотя по идеи должен реагировать на пульт и сбрасывать эту функцию на начало. Вот как можно решить эту проблему?

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

не должна :), так как у вас блокирует выполнение команда while(millis()<c). У вас происходит зацикливание, пока не пройдет заданое вами время задержки время.

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

И как тогда быть? должно же быть какое то решение параллельной работы задержки и обработчика

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Как вариант. Общий принцип.

if (пришел сигнал) a = millis();

if (millis() - a < t1) вкл

if ( t1 < (millis() - a) < t2 + t1) выкл

if ( t1 + t2 < (millis() - a) < t3 + t2 + t1) вкл

if ( t1 + t2 + t3< (millis() - a) < t4 + t3 + t2 + t1) выкл

if ( t1 + t2 + t3 + t4 < (millis() - a) ) вкл

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

Если учесть, что листинг моей основной программы будет занимать 20 листов А4, это я боюсь представить, какой if будет в конце)

У меня появилосб 2 варианта:

1. Я переведу 200р тому на карточку, кто сделает нормальный компактный код, соответствующий моим требованиям

2. Куплю ардуино нано, запрограммирую на обработку кнопки и выведу один из контактов на мой основной контроллер мега 2560 ,чтобы тот сбрасывал его на начало кода.

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

А итогово то что должно получиться ? Просто не верться что 20 листов А4 будут иметь вид:

"вкл что нить - подождать 2 сек - включить еще что то - подождать 3 сек - выключить все и т.д."

При такой задате подход в корне отличается от того что вы в начале писали.

Надо как то у казывать для ваших функций время начала \ окончания работы, а по внешнему сигналу запускать таймер, с которым связаны функции.

Клапауций
Offline
Зарегистрирован: 10.02.2013

CEBKACooler пишет:

Если учесть, что листинг моей основной программы будет занимать 20 листов А4, это я боюсь представить, какой if будет в конце)

У меня появилосб 2 варианта:

1. Я переведу 200р тому на карточку, кто сделает нормальный компактный код, соответствующий моим требованиям

2. Куплю ардуино нано, запрограммирую на обработку кнопки и выведу один из контактов на мой основной контроллер мега 2560 ,чтобы тот сбрасывал его на начало кода.

3. пусть нано жмёт на ресет халабуды.

*читаю - или я дурак, или топикстартер бредит.

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

roman2712@mail.ru пишет:

А итогово то что должно получиться ? Просто не верться что 20 листов А4 будут иметь вид:

"вкл что нить - подождать 2 сек - включить еще что то - подождать 3 сек - выключить все и т.д."

Так и есть. Раньше прописывал вкл\выкл портов через delay на 5-7 минут работы в сумме, и сбрасывал все это ножкой фотоприеника, подключенной на ресет. Но так как фотоприеник вещь не стабильная, поэтому при каждом засвете или вспышки фотоаппарата МК сбрасывался.

Сейчас нужно исправить эту ошибку и прописать обработчик кнопки с пульта(это я сделал) и чтобы он параллельно работал с моей основной программой, включающая порты в определенное время. Отказался от delay, решил сделать через millis, чтобы это все работало. Но ничего не вышло

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Я так понимаю, вы это делаете для костюма со световыми эфектами, а по пульту хотите засинхронизировать несколько костюмов ? 

Скажите, а вас есть эфекты типа бегущий огонь, переход цвета или плавное затухание ? Сколько каналов управления используется (руки \ ноги \ тело \ голова) ? Как подключены каналы сейчас ? Сколько нужно програм работы костюма ? Как планируется загрузка программы костюма ? Почему используете Мегу ? 

Просто есть идея, как это сделать, тока надо понимать текущие требования к реализации.

 

CEBKACooler
Offline
Зарегистрирован: 14.01.2014

roman2712@mail.ru пишет:

Я так понимаю, вы это делаете для костюма со световыми эфектами, а по пульту хотите засинхронизировать несколько костюмов ? 

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

Есть плавное затухание и зажигание всего костюма, я использую ножку шима для этого.

Раньше было 4 ножки для управления руки \ ноги \ тело \ голова. Сейчас так как у меня мега 2560, я задействую 40 ножек, он же 5 цельных портов. Будут зажигаться определенные сегменты на теле.

Программа пишется каждая для своего контроллера путем выставления временного интервала между включением нужных портов.

Клапауций
Offline
Зарегистрирован: 10.02.2013

CEBKACooler пишет:

Совершенно верно! Я синхронизирую все костюмы через фотоприемник с помощью пульта. Сейчас это должна быть определенная кнопка на пульте.

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

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Накидал вечерком 

вместо digitalWrite(ledPin, ledState[i]) , можно вставить функцию управления портами, а в качестве  ledState[] использовать несколько бит, отражающих состояние портов.

#include <IRremote.h>
int RECV_PIN = A3;
IRrecv irrecv(RECV_PIN);
decode_results results;

const int ledPin =  13;      
long previousMillis = 0;        

long interval[13] =  {
  1000 ,1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000,1000, 1};  // временные интервалы
int ledState[13] =   {
  0    ,1   , 0  ,  1   , 0   , 1  ,  0  ,  1  ,  0   , 1  ,  0   ,1   , 0};  // действия     
int i = 0;

void setup() {
  pinMode(ledPin, OUTPUT);   
  irrecv.enableIRIn();  
}

void loop()
{
  if (irrecv.decode(&results)) {
    switch (results.value) {
    case 16736925: // код клавиши на пульте
      i = 0;
      digitalWrite(ledPin, ledState[i]);
      break;
    }
    irrecv.resume(); 
  }

  unsigned long currentMillis = millis();  
  if(currentMillis - previousMillis > interval[i]) {
    ++i;
    if (i > 12) i = 12; // кол-во действий (необходимо что не было глюка программы, при i > 12)
    digitalWrite(ledPin, ledState[i]); // здесь может быт код обработки действия. 
    previousMillis = currentMillis; 
  }  
}

 

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013