Нужна помощь в применении логики к этому коду
Вот код:
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;
}
Итак, логика такая:
- При нажатии
powerBTN
контактenable
переключается. - Удерживая
powerBTN
в течение 1 секунды, условиеsoftStartENB
становится истинным. - Когда
softStartENB
имеет значение true, если я снова нажимаюpowerBTN
, на выводеenable
устанавливается высокий уровень, и через 2 секундыsoftStart
на низкий уровень.
Проблема в том, что после установки для softStartENB
значения 0, lastPowerState = powerReading
переключает вывод enable
на низкий уровень, но я хочу, чтобы enable
, чтобы оставаться на высоком уровне, пока я снова не нажму powerBTN
, чтобы переключить его.
- Как применить описанную логику?
@ElectronSurf, 👍-1
Обсуждение2 ответа
Лучший ответ:
Я решил проблему, используя библиотеку 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);
}
Я реструктурировал ваш код в конечный автомат. Существует минимальное количество «иностранных» участников. флаги и почти соотношение 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
- Как объявить массив переменного размера (глобально)
- Программирование Arduino с использованием Python, а не C/C ++
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Как справиться с rollover millis()?
- Является ли использование malloc() и free() действительно плохой идеей для Arduino?
- Можно ли сделать несколько функций loop() с помощью Arduino Uno?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- устаревшее преобразование из строковой константы в 'char*'
должно ли «включить» переключаться при нажатии «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