Switch case (millis())

Я хочу создать скетч, который отсчитывает дни с момента запуска "проекта" и отправляет сообщение osc каждые два дня (или более) в течение 3 недель. Итак:

день нулевой: сообщение osc -> 0
день второй.: сообщение osc -> 1
день четвертый: сообщение osc -> 2

и так далее.

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

Я согласился с предложением @jsotola и опробовал подход BlinkWithoutDelay. По-видимому, это работает, потому что я получаю серийные отпечатки вокруг правильного millis() они печатаются в 4-кратном или 3-кратном количестве сообщений.

ОТРЕДАКТИРОВАННЫЙ КОД:

int daytwo = 25920; // для целей тестирования другие числа, то фактический millis()
int dayfour = 44400;
    
void loop() {  
  unsigned long currentMillis = millis();   // хранить текущее время

  if (currentMillis == daytwo) {
    Serial.println("daytwo");
  }
    
  if (currentMillis == dayfour) {
    Serial.println("dayfour");
  }
}

Последовательный выход:

    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.889 -> daytwo
    11:04:39.926 -> daytwo
    11:04:58.366 -> dayfour
    11:04:58.366 -> dayfour
    11:04:58.366 -> dayfour
    11:04:58.366 -> dayfour

, 👍1

Обсуждение

объявите переменную для хранения номера сообщения osc ... увеличивайте его каждые 48 часов и передавайте сообщение... см. Пример скетча blinkWithoutDelay для метода повторения действия неблокирующим способом, @jsotola

А сравнение - это == не =. В чем заключается ваш вопрос?, @romkey

Кроме того, не сравнивайте время с равенством, которое никогда не будет работать надежно. (Что делать, если тест не будет выполнен в этот самый момент?), @PMF

Если это “по-видимому работает”, то в чем именно заключается ваш вопрос? То, как вы сейчас тестируете соответствующее время (с сравнением, основанным на равенстве), действительно ненадежно. Почему вы не используете ту же логику, что и скетч “мигание без задержки” (т.Е. Используете “равно или больше”), чтобы случайно не пропустить событие?, @StarCat

@StarCat если я использую == тогда я думал, что он создаст одно сообщение (мне нужно только 1 сообщение в 2 дня, как описано в цели проекта перед вопросом о том, как этого достичь. (сначала я получил пример millis(), затем пример statemachine и знаю, что попробовал blinkwithoutdelay, как советовали мне комментарии.)) Компаратор >= дает мне переполнение Serial.print (или osc-сообщений) в этом случае. Есть какие-нибудь предложения?, @LazyFatTree

Вы должны помнить: миллисекунда длится целую миллисекунду. Для Arduino это целая вечность., @Majenko

Вы можете рассчитать день, используя int day = millis() / 86400000UL. Затем используйте это внутри оператора switch-case., @Gerben

@LazyFatTree нет, вы не использовали подход blinkWithoutDelay ... пожалуйста, внимательно изучите скетч blinkWithoutDelay, прочитайте и поймите, что говорится в комментариях ... одна вещь, которую вы должны понимать, заключается в том, что утверждение "if" истинно только "один раз за каждый интервал", а не несколько раз, как ваш код... просто увеличьте счетчик внутри блока если... используйте значение счетчика для печати дня, @jsotola


2 ответа


Лучший ответ:

1

Следующий код не очень "чистый", но понятный. Используйте переменную для хранения дня, который вы уже напечатали, и проверьте, в каком интервале вы находитесь. Если вы измените интервал в 2 дня, распечатайте сообщение и установите переменную actDay на номер дня, который вы уже напечатали, чтобы избежать повторной печати.

int daytwo = 25920; 
int dayfour = 44400;

int actDay = -1;

void loop() 
{  
  unsigned long currentMillis = millis();
  if (currentMillis < daytwo) 
  {
    if ( actDay != 0 ) 
    {
      actDay = 0;
      Serial.println("dayzero");
    }
  }
  else if (currentMillis < dayfour ) 
  {
    if ( actDay != 2 ) 
    {
      actDay = 2;
      Serial.println("daytwo");
    }
  }
  else 
  {
    if ( actDay != 4 ) 
    {
      actDay = 4;
      Serial.println("dayfour");
    }
  } 
}
,

Спасибо, ваш пример был наиболее понятным, поэтому я проголосую за это решение. Если другие думают, что вышеприведенный ответ лучше всего, пожалуйста, проголосуйте за это! @Peter-Paul-Kiefer еще раз спасибо!, @LazyFatTree


0
int day = 0;
unsigned long prevMillis = 0;
const unsigned long MILLIS_PER_DAY = 86400000UL;

void setup()
{
  prevMillis = millis();
}

void loop() {  
  if( millis() - prevMillis > MILLIS_PER_DAY )
  {
    // целый день прошел
    day++;
    prevMillis += MILLIS_PER_DAY;

    // делайте то, что вы хотите сделать в начале нового дня
    if( day==2 ) {
      Serial.println("daytwo");
    }
    else if (day == 4) {
      Serial.println("dayfour");
    }
  }
}

Это более общая версия. Он проверяет, есть ли 24*60*60*1000 с тех пор как день в последний раз перевернулся, прошли миллисекунды. Когда это произойдет, он увеличит текущий день и обновит prevMillis до значения millis() в начале дня.

Это также имеет то преимущество, что is будет запускать ваш "ежедневный код" только один раз.

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

,

Лично я предпочел бы такое решение, как ваше. Но, подумал я, было бы лучше объяснить принцип и по-прежнему думать, что ОП достаточно умен, чтобы расширить пример, если только он / она понял основы. Опять же, ваше решение лучше. Пожалуйста, позвольте мне указать вам на некоторые проблемы ': Вы использовали необъявленную переменную dayfour вместо 4., @Peter Paul Kiefer

Примерно через 50 дней счетчик millis() переполняется и начинается с 0. Примерно в течение 50 дней блок if не будет введен, после чего prevMillis переполнится до значения ~ 25032704. Если только "daytwo" и "dayfour", то это не ошибка (только если переменная day переполняется ;-)). Но если ОП попытается добавить больше случаев или найти более общее решение, это может стать проблемой., @Peter Paul Kiefer

В комментарии выше вы упомянули очень хорошее решение, которое вывело бы ваш уже "хороший" ответ на следующий уровень. `int day = millis() / 86400000UL.' Оператор use a switch . Он также будет легко расширяться. Только это немного усложнило бы такие изменения, как сброс дней на 0 или что-то еще. Я сожалею, что не дал такого решения. ;-), @Peter Paul Kiefer

@PeterPaulKiefer хороший улов. Сменил dayfour на 4. Спасибо., @Gerben