Значение продолжает увеличиваться, даже несмотря на то, что цикл завершен, почему?

c++

Я использую двойное значение delta и использую его для отключения ЖК-дисплея, если значение delta превышает пороговое значение тайм-аута. Как только это произойдет, предполагается, что значение delta будет равно 0, а затем будут запущены другие части программы. Тем не менее, дельта продолжает увеличиваться, и я не уверен, почему.

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

Есть какие-нибудь мысли относительно того, почему? Заранее благодарю.

#include <M5StickC.h>

double BUTTON_PRESS_NEXT_PRESS_TIME= .5; //Время в секундах
double MINIMUM_BUTTON_PRESS_TIME = .05; //Время в секундах
int BUTTON_PRESS_SLEEP = 3; //Время в секундах
int SCREEN_TIMEOUT = 5;
int count;

static int pressCount = 1;
static int nextPress= 1;

static bool buttonIsPressed;

void setup(void) {
  buttonIsPressed = false;
  M5.begin();
  M5.Lcd.setRotation(0);
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);

  // Исходная точка - это средний центр
  M5.Lcd.setTextDatum(MC_DATUM);
  M5.Axp.ScreenBreath(100);
  
  updateScreen();      
}

void updateScreen() {
   char tmp[12];
  
  // Исходная точка - это средний центр
  M5.Lcd.setTextDatum(MC_DATUM);
  M5.Lcd.drawString(dtostrf(pressCount,4,0,tmp), 80,60,6);
  M5.Lcd.drawString(dtostrf(nextPress,3,0,tmp), 80,100,6);
}

static void evaluatePress(double d) {
   // Оценить прессу 
  if (d >= BUTTON_PRESS_NEXT_PRESS_TIME) {
    nextPress++;
    pressCount = 1;
        
    if (nextPress == 19) {
      nextPress= 1;
    }
  }
  else if (d >= MINIMUM_BUTTON_PRESS_TIME && d < BUTTON_PRESS_NEXT_PRESS_TIME) {
    pressCount++;
  }
    
  updateScreen();
}

void sleepLoop() {
  bool bIsPressed = false;
  Serial.println("Sleep 1");
  while(1) {
    Serial.println("Sleep 2");
    if (digitalRead(M5_BUTTON_HOME) == LOW && !bIsPressed) {
      bIsPressed = true;
    }

    if (digitalRead(M5_BUTTON_HOME) == HIGH && bIsPressed){
      Serial.println("BREAKY BREAKY");
      M5.Axp.ScreenBreath(100);

      break;
    }
  }
}

void awakeLoop() {  
  double delta;
  double old_time;
  double current_time;

  Serial.println("Awake 1");
  
  while(1) {
    Serial.println("Awake 2");
     // Вычислить время разности
    old_time = current_time;
    current_time =  millis();
    delta = delta + (current_time - old_time)/1000;

    if (digitalRead(M5_BUTTON_HOME) == LOW && !buttonIsPressed) {
      buttonIsPressed = true; 
      delta = 0;
    }

    if(digitalRead(M5_BUTTON_HOME) == HIGH && buttonIsPressed) {
      buttonIsPressed = false;
      evaluatePress(delta);
      delta=0;
    }
 
    if(delta > SCREEN_TIMEOUT && !buttonIsPressed) {
      Serial.println(delta);
      Serial.print("BREAK AWAKE");
      Serial.println(M5.Axp.ScreenBreath(0));
      count = 0;
      break;
    }
    else {
      count++;
    }
  }
  
  delta = 0;
}

void loop() {
  awakeLoop();
  sleepLoop();
}

, 👍1

Обсуждение

Извините, но это сумасшедший способ сделать тайм-аут экрана. Вам не нужна дельта, и вы, конечно, не хотите, чтобы она была двойной... Просто запишите current_time = millis(), когда происходит действие, и прервите, когда (millis() - current_time) > 5000., @Majenko

Спасибо @Majenko. Я удалил некоторый код, чтобы вопрос был более непосредственно связан с проблемой. Я думаю, что могу сделать то, что вы предложили, хотя и попробую. Что не так с двойником?, @Kyle

@Kyle double требует операций с плавающей запятой для каждого вычисления, которые Arduino не поддерживает в своем оборудовании. Таким образом, это должно быть сделано в программном обеспечении, которое требует больших вычислительных ресурсов. Таким образом, общее правило состоит в том, чтобы использовать тип с плавающей запятой ("float" или "double") только тогда, когда это действительно необходимо. millis() использует unsigned long, так почему бы не использовать то же самое для переменных?, @chrisl


1 ответ


1

Здесь:

void awakeLoop(){  
  double delta;
  // Остальная часть тела функции...
  delta = 0;
}

дельта определяется как переменная, локальная для функции awakeLoop() и с автоматическим сохранением. Это означает, что переменная создается всякий раз, когда программа входит в функцию, не инициализируется неявно и уничтожается при возврате функции.

Последнее утверждение delta = 0; не имеет никакого эффекта, так как оно устанавливает переменную, которая будет немедленно уничтожена. Компилятор , скорее всего, избавился от него.

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

,

Спасибо @ Эдгар Боне. Проблема, с которой я сталкиваюсь, заключается в том, что дельта *не* фактически устанавливается на 0 или уничтожается. Я знаю, что мне не следует/не нужно устанавливать дельту в 0 в конце цикла, но я добавил эту строку, потому что программа работает не так, как я ожидал. Строка, которая выводит дельту, прямо под «Пробуждением тормоза», всегда выводит значение, которое я ожидал бы, если бы цикл выполнялся непрерывно., @Kyle

@Kyle: это значение бессмысленно, так как «дельта» не была инициализирована. Соответствует ли оно вашим ожиданиям или нет — это просто шанс, и рассчитывать на него не стоит., @Edgar Bonet