Нужна помощь в применении логики к этому коду

Вот код:

int softStart = A0;
int enable = A1;
int powerBTN = A2, powerState = HIGH, lastPowerState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 25;
unsigned long powerTimer = 0;
unsigned long powerHoldTimer = 0;
bool softStartENB = 0;

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);
  pinMode(powerBTN, INPUT_PULLUP);
}

void loop() {
  int powerReading = digitalRead(powerBTN);

  if (powerReading != lastPowerState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay && !softStartENB) {
    if (powerReading != powerState) {
      powerState = powerReading;
      if (powerState == HIGH) {
        digitalWrite(enable, !digitalRead(enable));
        Serial.print("Normal start: ");
        Serial.println(digitalRead(enable));
      }
    }
  }

  if (powerReading == LOW) {
    powerTimer = millis() - lastDebounceTime;
  } else {
    powerTimer = 0;
  }

  if (powerTimer >= 1000 && millis() - powerHoldTimer >= 2000) {
    softStartENB = 1;
    digitalWrite(enable, LOW);
    digitalWrite(softStart, HIGH);
    Serial.print("Soft start started: ");
    Serial.println(digitalRead(softStart));
    powerHoldTimer = millis();
  }

  if (softStartENB && lastPowerState == HIGH && powerReading == LOW) {
    digitalWrite(enable, HIGH);
    delay(2000);
    digitalWrite(softStart, LOW);
    Serial.print("Soft start ended: ");
    Serial.println(digitalRead(softStart));
    softStartENB = 0;
  }

  lastPowerState = powerReading;

}

Итак, логика такая:

  1. При нажатии powerBTN контакт enable переключается.
  2. Удерживая powerBTN в течение 1 секунды, условие softStartENB становится истинным.
  3. Когда softStartENB имеет значение true, если я снова нажимаю powerBTN, на выводе enable устанавливается высокий уровень, и через 2 секунды softStart на низкий уровень.

Проблема в том, что после установки для softStartENB значения 0, lastPowerState = powerReading переключает вывод enable на низкий уровень, но я хочу, чтобы enable, чтобы оставаться на высоком уровне, пока я снова не нажму powerBTN, чтобы переключить его.

  • Как применить описанную логику?

, 👍-1

Обсуждение

должно ли «включить» переключаться при нажатии «powerBTN» в течение 1 секунды?, @jsotola

@jsotola Это невозможно, потому что после удержания его в течение секунды флаг «softStartENB» становится истинным, а «включить» можно переключать только тогда, когда «softStartENB» мигает., @ElectronSurf

пункт 1. ничего не говорит о softStartENB... кроме того, softStartENB может быть ложным в начале нажатия кнопки... следует ли переключать enable при отпускании кнопки?, @jsotola

Ваша формулировка проблемы кажется очень неполной. Как только softStartENB станет true, останется ли оно true навсегда? Если нет, то какие события снова переключают его на «ложь»? Тот же вопрос для «softStart»: может ли он когда-нибудь измениться с «LOW» на «HIGH»? Что произойдет, если кнопку нажать во время 2-секундной задержки? Пожалуйста, постарайтесь дать полное описание желаемого поведения, желательно в виде [диаграммы состояний]()., @Edgar Bonet

@jsotola см. редактирование., @ElectronSurf

@EdgarBonet см. редактирование., @ElectronSurf

Устройство, которым вы управляете, имеет три состояния: ВЫКЛ, ВКЛ и IN_SOFT_START. Короткое нажатие кнопки приводит к переключению устройства между ВКЛ и ВЫКЛ. Длительное нажатие инициирует IN_SOFT_START. Второе нажатие кнопки в этом состоянии переводит устройство в состояние ВКЛ после ожидания 2 секунд. Это просто, но вам следует нарисовать это как обычную диаграмму состояний. А как насчет добавления тайм-аута, если после входа в состояние IN_SOFT_START пользователь не нажмет кнопку еще раз в течение разумного периода времени?, @6v6gt

@ 6v6gt Я могу сделать все это позже, сейчас проблема в том, что контакт включения становится низким после того, как флаг softStartENB становится ложным., @ElectronSurf


2 ответа


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

0

Я решил проблему, используя библиотеку JC_button:

#include <JC_Button.h>


const byte softStart(A0), enable(A1);
int powerStates = 0;
bool enableState;

Button powerBTN(A2);

void setup() {
  Serial.begin(115200);
  powerBTN.begin();
  pinMode(enable, OUTPUT);
  pinMode(softStart, OUTPUT);
}

void loop() {
  powerBTN.read();
  Serial.println(powerStates);

  switch (powerStates) {
    case 0:
      if (powerBTN.wasReleased())
        switchEnable();
      else if (powerBTN.pressedFor(1000))
        powerStates = 1;
      break;

    case 1:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, LOW);
        digitalWrite(softStart, HIGH);
        enableState = false;
        powerStates = 2;
      }
      break;
      
    case 2:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, HIGH);
        delay(2000);
        digitalWrite(softStart, LOW);
        enableState = true;
        powerStates = 0;
      }
      break;
  }
}

void switchEnable() {
  enableState = !enableState;
  digitalWrite(enable, enableState);
}
,

0

Я реструктурировал ваш код в конечный автомат. Существует минимальное количество «иностранных» участников. флаги и почти соотношение 1:1 между кодом и диаграммой состояний. Вы можете протестировать его симуляцию здесь: https://wokwi.com/projects/383445446722551809

int softStart = A0;
int enable = A1;
int powerBTN = A2;

enum State { OFF = 0, ON = 1, WAIT_ON = 2 , WAIT_OFF = 3, IN_SOFT_START = 4, SOFT_START_CONFIRM = 5 } ;
State state  ;
State oldState ;
bool stateChange = true ;

uint32_t inCurrentStateAtMs = 0 ;

void setState ( State newState ) {
  // принудительно переходим в новое состояние
  inCurrentStateAtMs = millis() ;
  oldState = state ;
  state = newState ;
  stateChange = true ;
}

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  pinMode(powerBTN, INPUT_PULLUP) ;
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);

  setState( State::OFF ) ;

}

void loop() {

  if ( stateChange ) {
    //отлаживать
    stateChange = false ;
    Serial.print("state changes to: ");
    Serial.println( state ) ;
  }


  switch ( state ) {

    case State::OFF : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_ON ) ;
        }
        break ;
      }

    case State::WAIT_ON : {
         
          if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs < 500 ) {
            digitalWrite( enable, HIGH ) ;
            setState( State::ON );
          }
          else if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs >= 500 ) {
            digitalWrite( enable, LOW ) ;
            digitalWrite( softStart, HIGH ) ;
            setState( State::IN_SOFT_START );
          }
         
        break ;
      }

    case State::ON : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_OFF );
        }
        break ;
      }


    case State::WAIT_OFF : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          digitalWrite( enable, LOW ) ;
          setState( State::OFF ) ;
        }
        break;
      }


    case State::IN_SOFT_START : {
        if ( ! digitalRead( powerBTN )  ) {
          digitalWrite( enable, HIGH ) ;
          state = State::SOFT_START_CONFIRM ;
        }
        else if ( millis() - inCurrentStateAtMs > 3000 ) {
          // тайм-аут
          digitalWrite( softStart, LOW ) ;
          setState( State::OFF );
        }
        break ;
      }

    case State::SOFT_START_CONFIRM  : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 2000  ) {
          digitalWrite( softStart, LOW ) ;
          setState( State::ON ) ;
        }
        break ;
      }

  } // выключатель

}  // петля

,

Пожалуйста, не меняйте поведение кода: в моем коде, даже если на выводе включения высокий уровень, а powerBTN удерживается в течение 1 секунды, вывод включения переходит в низкий уровень. в любом случае проблема сохраняется, вывод включения не остается/переходит в высокий уровень до и после того, как softStart переходит в высокий, а затем в низкий уровень., @ElectronSurf