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
@LazyFatTree, 👍1
Обсуждение2 ответа
Лучший ответ:
Следующий код не очень "чистый", но понятный. Используйте переменную для хранения дня, который вы уже напечатали, и проверьте, в каком интервале вы находитесь. Если вы измените интервал в 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
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
- Как читать и записывать EEPROM в ESP8266
- Как исправить: Invalid conversion from 'const char*' to 'char*' [-fpermissive]
- ошибка: espcomm_upload_mem failed при загрузке скетча
- Как определить размер Flash?
- Несколько клиентских серверов через Wi-Fi
- Передача функции-члена класса в качестве аргумента
- В ESP-12E NodeMCU, какой выход PIN A0?
- Esp8266 Vin контакт
объявите переменную для хранения номера сообщения 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