Пожалуйста, исправьте мой код задержки без использования delay();

Это моя функция loop ():

if(Serial.read() == 't') {
  tarestate = true;
}

while(tarestate == true) {
  timeNowTare = mills();
  if(mills() - timeNowTare >= 3000) {
    Serial.println("Tare");
  }
  tareState = false;
}

Где tareStare-логическое значение, timeNowTare-длинное.

Мне нужно распечатать на серийном:

Тара

через три секунды после того, как я введу "т" в серийный номер.

Со всем, что я пробовал на сегодняшний день, программа либо останавливается, либо останавливается сразу после ввода “t”.

РЕДАКТИРОВАТЬ: Спасибо всем, кто ответил ответами. Решение состояло в том, чтобы просто переместить объявление timeNowTare = true; до оператора Serial.read() if. Я также изменил цикл while на оператор if, потому что это, казалось, ускоряло выполнение моего кода.

final code

, 👍2

Обсуждение

единственное место, где вы инициализируете "timeNowTare", - это непосредственно перед его использованием ... таким образом, это никогда не будет > 3000 ... возможно, timeNowTare = mills(); внутри первого if, @Jaromanda X

Пожалуйста, используйте поле ответа, чтобы сделать ответ. Комментарии предназначены для уточнения вопроса. Спасибо! :), @Nick Gammon

нелегко на мобильном устройстве - плюс давал OP шанс в момент "ага" и исправлял код самостоятельно: p, @Jaromanda X


2 ответа


1

Переместите timeNowTare = millis(); сначала внутрь, если:

if (Serial.read() == 't') {
  tareState = true;
  timeNowTare = millis();
}

и tareState = ложь внутри секунды, если:

while (tareState) {
  if (millis() - timeNowTare >= 3000) {
    Serial.println(F("Tare"));
    tareState = false;
  }
}
,

1

Самое простое решение-просто использовать delay():

if (Serial.read() == 't') {
    delay(3000);
    Serial.println(F("Tare"));
}

Что? Вы сказали “без задержек ()"? Хорошо, тогда просто напишите свою собственную реализацию delay() и встроите ее вместо фактического вызова delay():

if (Serial.read() == 't') {
    uint32_t timeNowTare = millis();
    while (millis() - timeNowTare < 3000) continue;  // wait
    Serial.println(F("Tare"));
}

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

Однако делать это совершенно глупо. Зачем вам писать свою собственную версию delay (), когда ядро Arduino предоставляет вам хорошо протестированную версию? Почему вы хотите избежать стандартной задержки() в первую очередь?

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

Реальное решение состоит в том, чтобы мыслить в терминах конечного автомата. Либо программа работает в “режиме тары”, либо нет. Возможными переходами состояний являются:

  • после считывания буквы " т " на последовательном порту вы входите в режим тары и записываете текущее время
  • если вы уже находитесь в режиме тары и с момента входа в этот режим прошло три секунды, то вы распечатываете "Тара" и выходите из режима тары.

Вот прямая реализация такой state машины:

static bool tare_mode = false;
static uint32_t tare_start_time;  // meaningful only in tare_mode
if (Serial.read() == 't') {
    tare_mode = true;
    tare_start_time = millis();
}
if (tare_mode && millis() - tare_start_time >= 3000) {
    Serial.println(F("Tare"));
    tare_mode = false;
}

Теперь вы можете добавить больше кода в loop (), и этот дополнительный код никогда не будет заблокирован вашей функцией “тара”.

,