Как устранить дребезг показаний битовой маски с помощью Arduino? (не кнопки)

У меня есть этот фрагмент кода, который я хотел бы устранить: я хочу убедиться, что даже через ± 1,5 секунды показания будут одинаковыми (если это так, сделайте что-нибудь, иначе сделайте что-нибудь еще...).

функция wining_check() получает битовую маску в качестве входных данных и запускается внутри цикла().

void winning_check(uint16_t mask) {
if ((mask & 0b11111000000000) == 0b11111000000000) {  // btm row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(BTM_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(BTM_ROW_SENSOR_PIN)) digitalWrite(BTM_ROW_MOTOR_PIN, HIGH);
}
if ((mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}
if ((mask & 0b00000000001111) == 0b00000000001111) {  // top row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(TOP_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(TOP_ROW_SENSOR_PIN)) digitalWrite(TOP_ROW_MOTOR_PIN, HIGH);
}

}

Я пробовал это, но, похоже, это не работает:

void winning_check(uint16_t mask) {
if ((mask & 0b11111000000000) == 0b11111000000000) {  // btm row winning sequence
    last_debounce_time = millis();
    if ((millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS) {
        if ((mask & 0b11111000000000) == 0b11111000000000) {
            digitalWrite(WINNING_SENSOR_PIN, HIGH);
            digitalWrite(BTM_ROW_MOTOR_PIN, LOW);  // =turn on
        }
    }
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(BTM_ROW_SENSOR_PIN)) digitalWrite(BTM_ROW_MOTOR_PIN, HIGH);
}
if ((mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}
if ((mask & 0b00000000001111) == 0b00000000001111) {  // top row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(TOP_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(TOP_ROW_SENSOR_PIN)) digitalWrite(TOP_ROW_MOTOR_PIN, HIGH);
}

}

заранее спасибо.

ИЗМЕНИТЬ

Вот новый код: я хотел бы отметить, что маска относится к механическим переключателям, поэтому они не сбрасываются до тех пор, пока не будет обнаружена победа строки, а затем двигатель (например, MID_ROW_MOTOR_PIN) сбрасывает ту же самую строку.

Что касается сброса WinningState в LOW, у меня есть функция сброса, которая вызывается, когда игра окончена, то есть когда я сбрасываю WinningState.

Новая проблема заключается в том, что когда я перезагружаю Arduino, запускаю игру и достигаю правильной выигрышной маски, код работает в первый раз с временем устранения дребезга, которое мы сделали, но когда я делаю это снова, он снова не считает, а сразу сбрасывает маска ряда...

Другая причина, которая может вызвать это, заключается в том, что оператор else всегда вызывается. Я проверил это в последовательном мониторе, используя Serial.println().

void winning_check(uint16_t mask) {
if (((mask & 0b11111000000000) == 0b11111000000000 || (mask & 0b00000111110000) == 0b00000111110000 || (mask & 0b00000000001111) == 0b00000000001111) && (winning_state == false)) {
    Serial.println("Win detected");
    winning_state = true;
    last_debounce_time = millis();
}
if ((millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS && (mask & 0b11111000000000) == 0b11111000000000) {  // btm row winning sequence
    Serial.println("btm row win confirmed");
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(BTM_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    Serial.println(".");
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(BTM_ROW_SENSOR_PIN)) digitalWrite(BTM_ROW_MOTOR_PIN, HIGH);
}
if ((millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS && (mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}
if ((millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS && (mask & 0b00000000001111) == 0b00000000001111) {  // top row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(TOP_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(TOP_ROW_SENSOR_PIN)) digitalWrite(TOP_ROW_MOTOR_PIN, HIGH);
}

}

Вот функция, которая вызывает последовательность:

uint16_t get_clowns_state() {
uint16_t clowns_mask = 0;
for (uint16_t i = 0; i < 14; i++) {
    clowns_mask |= (uint16_t)(digitalRead(clowns_pins[i]) << i);
}

return clowns_mask;

}

и внутри цикла() я вызываю:wining_check(get_clowns_state());


person KD Technology    schedule 25.03.2020    source источник
comment
Вы устанавливаете last_debounce_time непосредственно перед его использованием, поэтому millis() - last_debounce_time по существу всегда будет 0   -  person Nick    schedule 25.03.2020
comment
где еще я должен установить это? Мне нужно начать считать в тот момент, когда он обнаружит правильную маску   -  person KD Technology    schedule 25.03.2020


Ответы (2)


Поскольку вам нужен конечный автомат, он работает следующим образом:

 // Global var place before setup()
bool winningState = false;

void winning_check(uint16_t mask) {
    // We check if a winning state is hit
    
if ( ( (mask & 0b11111000000000) == 0b11111000000000 // added bracket
|| (mask & 0b00000111110000) == 0b00000111110000 
|| (mask & 0b00000000001111) == 0b00000000001111 ) // added bracket
&& winningState == false) {  // we hit for the first time herebtm row winning sequence
    winningState = true;
    last_debounce_time = millis();
}
    // we hit for the next 1.5 sec time herebtm row winning sequence
    
    if ((millis() - last_debounce_time) <= DEBOUNCE_DELAY_MS && (mask & 0b11111000000000) == 0b11111000000000) { // inversed logic opposite to yours
            digitalWrite(WINNING_SENSOR_PIN, HIGH);
            digitalWrite(BTM_ROW_MOTOR_PIN, LOW);  // =turn on
        }
    } else {
        winningState = false; // Reset the var
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(BTM_ROW_SENSOR_PIN)) digitalWrite(BTM_ROW_MOTOR_PIN, HIGH);
    
}
if ((millis() - last_debounce_time) <= DEBOUNCE_DELAY_MS &&(mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    winningState = false; // Reset the var
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}
if ((millis() - last_debounce_time) <= DEBOUNCE_DELAY_MS && (mask & 0b00000000001111) == 0b00000000001111) {  // top row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(TOP_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    winningState = false; // Reset the var
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(TOP_ROW_SENSOR_PIN)) digitalWrite(TOP_ROW_MOTOR_PIN, HIGH);
}

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

Изменить

Изменены скобки и обратная логика устранения дребезга (отказ от логики ОП)

Второе редактирование

Основной вопрос:
должно ли то, что следует после if, произойти через 1,5 секунды только один раз, тогда используйте эту логику:

(millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS   // Your logic

то применяется следующий код

 if ((millis() - last_debounce_time) >= DEBOUNCE_DELAY_MS &&(mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
     winningState = false; // Reset the var
} else {
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}

или это должно произойти в течение 1,5 секунд, а затем изменить состояние:

  (millis() - last_debounce_time) <= DEBOUNCE_DELAY_MS   // "My" logic

чем этот код применяется:

if ((millis() - last_debounce_time) <= DEBOUNCE_DELAY_MS &&(mask & 0b00000111110000) == 0b00000111110000) {  // mid row winning sequence
    digitalWrite(WINNING_SENSOR_PIN, HIGH);
    digitalWrite(MID_ROW_MOTOR_PIN, LOW);  // =turn on
} else {
    winningState = false; // Reset the var
    // digitalWrite(WINNING_SENSOR_PIN, LOW);
    if (!digitalRead(MID_ROW_SENSOR_PIN)) digitalWrite(MID_ROW_MOTOR_PIN, HIGH);
}

Будет полезно, если вы примените диаграмму состояний следующим образом.

  • Определить состояние (определенная маска)
  • сделать что-то1 в течение 1500 мс и не изменить состояние
  • остановить что-то1 при изменении состояния и времени ‹ 1500 мс -> сброс и возврат
  • остановить что-то1, если время истекло И состояние не изменилось --› сделать что-то2
person Codebreaker007    schedule 25.03.2020
comment
Теперь ничего не происходит... Думаю, вы пропустили перезапуск WinningState в LOW? - person KD Technology; 26.03.2020
comment
Поскольку я не знаю вашей логики. Я не могу указать, где сбросить до НИЗКОГО, если вы предоставите диаграмму состояния, нет проблем - я просто хотел дать вам основную идею о том, как структурировать общую логику, см. редактирование через минуту. - person Codebreaker007; 26.03.2020
comment
спасибо за помощь, но инверсия не помогла. Мне нужно подождать время DEBOUNCE_DELAY_MS, если маска обнаружена, поэтому предыдущий код был хорошим. Единственная проблема заключается в том, что он всегда вызывает опцию else, и это делает WinningState ложным, что позволяет повторить первый оператор if. - person KD Technology; 26.03.2020
comment
Я постараюсь найти подходящее место для сброса WinningState в LOW - person KD Technology; 26.03.2020
comment
Логика делать за 1,5 сек что-то если есть выигрышная маска? Затем millis() - startTtime ‹= 1500 && WiningMask Пример 2000-1000 ‹= 1500 прошла одна секунда -- поверьте мне, поэтому каждый раз происходит else ИЛИ маска появляется только один раз, а затем сбрасывается? - затем используйте выигрышное состояние вместо выигрышной маски во втором, если видите редактирование - person Codebreaker007; 26.03.2020
comment
Я нашел правильное место, и он работает в первый раз, но после того, как я выиграл один раз, он больше не проверяет время отката. Может быть, мне также следует сбросить переменную last_debounce_time (хотя она каждый раз получает новую миллис()) - person KD Technology; 26.03.2020
comment
Попробуйте мое решение для редактирования 2. Или отредактируйте свой вопрос и опубликуйте последнюю версию кода. - person Codebreaker007; 26.03.2020
comment
Теперь три утверждения if одинаковы... Выигрышное состояние не появляется один раз. (Маска остается, не сбрасывается - это механические переключатели) - person KD Technology; 26.03.2020
comment
отредактируйте свой вопрос и опубликуйте свою последнюю половину рабочей версии кода, которая работает один раз, а также ваш цикл, в котором вы вызываете последовательность - person Codebreaker007; 26.03.2020
comment
сделал это. взглянем :) - person KD Technology; 26.03.2020
comment
см. замененное второе редактирование и, пожалуйста, ответьте на вопросы, касающиеся логики - person Codebreaker007; 26.03.2020
comment
Отредактировал ваш код, см. вставку win_state = false; после одобрения коллег - person Codebreaker007; 26.03.2020

Теперь, когда я стал гораздо лучшим программистом, требуется некоторое обновление, но логика очень здравая, и она действительно работает исключительно хорошо. Попробуйте мою библиотеку eRCaGuy_EventReader debounce отсюда: https://github.com/ElectricRCAircraftGuy/eRCaGuy_EventReader.

Вот пример использования. Обратите внимание, что у вас есть несколько вариантов: вы можете действовать в соответствии с 1) действием/событием, отклоненным (в момент изменения состояния с false на true или true на false), ИЛИ 2) в соответствии с состояние отклонено. Изучите приведенный ниже пример кода, и я думаю, вы сможете понять разницу.

Примечание: этот код также теперь публикуется в качестве основного примера в проекте eRCaGuy_EventReader, ссылка на который приведена выше.

#include <eRCaGuy_EventReader.h>

// 1500ms, or 1.5 sec debounce delay (last state must remain unchanged for this duration or else the
// debounce is not yet considered "complete")
constexpr unsigned int DEBOUNCE_DELAY_MS = 1500; 
constexpr bool EVENT_STATE_WHEN_EVENT_OCCURS = true;

// In this example I create one debouncer. It looks like you will need
// to create several to accomplish what you want. Create one debouncer
// object for each event you'd like to debounce, and follow the pattern
// and usage shown below according to your needs.
eRCaGuy_EventReader debouncer(DEBOUNCE_DELAY_MS, EVENT_STATE_WHEN_EVENT_OCCURS);

void setup()
{

}

void loop()
{
  // Check your masks here
  // ***FILL IN YOUR REAL LOGIC HERE TO CHECK IF THE MASKS ARE THE SAME!***
  bool masks_are_same = true; 

  // Register a new reading
  debouncer.readEvent(masks_are_same);

  // Now get debounced values

  int8_t debounced_action = debouncer.getDebouncedAction();
  switch (debounced_action)
  {
    // No change in the true, debounced event state since last time interpreting the event, or 
    // debounceDelay time not yet elapsed
    case eRCaGuy_EventReader::NO_ACTION:
      // do what you want here
      break;
    // A new event just occurred (debounce delay has elapsed)
    // ie: debounced version of `masks_are_same` has gone from false to true!
    case eRCaGuy_EventReader::ACTION_OCCURRED:
      // do what you want here
      break;
    // A new event just "un-occurred" by going back to its resting state (debounce delay has 
    // elapsed); ie: debounced version of `masks_are_same` has just gone from true back to false!
    case eRCaGuy_EventReader::ACTION_UNOCCURRED:
      // do what you want here
      break;
  }

  // This is the debounced version of `masks_are_same`
  bool masks_are_same_debounced = debouncer.getDebouncedState();
  if (masks_are_same_debounced)
  {
    // do whatever you want if the masks are the same
  }
  else
  {
    // do whatever you want if the masks are different
  }
}
person Gabriel Staples    schedule 11.04.2020