Есть ли способ для клавиатуры остановить зуммер во время его работы?

Я новичок в arduino, в настоящее время я ищу способ сделать клавиатуру способной остановить зуммер, излучающий сирену, когда пароль введен неправильно, и иметь возможность перейти к экрану пароля, нажав любую кнопку на клавиатуре. Из всех видео, которые я видел, только 1 соответствует тому, как я хочу, чтобы оно работало.

https://www.hackster.io/thehack904/motion-sensing -сигнализация-с-паролем-клавиатуры-53f05c

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

//Библиотеки
#include <LiquidCrystal.h>
#include <Keypad.h>

/*-------------------------------КЛАВИАТУРА---------------------------------------*/
const byte numRows = 4; //количество строк на клавиатуре
const byte numCols = 4; //количество колонок на клавиатуре
char keypressed;
char keymap[numRows][numCols] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
//Код, показывающий подключение клавиатуры к терминалам Arduino
byte rowPins[numRows] = {2, 3, 4, 5};//строки от 0 до 3
byte colPins[numCols] = {6, 7, 8, 9};//Столбцы от 0 до 3
//инициализирует экземпляр класса Keypad
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);

/*-------------------------------КОНСТАНТЫ------------------------------------*/
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); // ЖК-дисплей
const int buzzer = 10;        //Зуммер/маленький динамик
int solenoidPin = 11;         //Соленоид

/*-------------------------------ПЕРЕМЕННЫЕ------------------------------------*/
String password = "0"; //Переменная для хранения текущего пароля
String master_key = "999"; //Переменная для хранения мастер-ключа
String tempPassword = ""; //Переменная для хранения входного пароля
int doublecheck;    // дважды проверяем новый пароль
boolean armed = false;  //Переменная для состояния системы (вооружён:true / безоружен:false)
boolean input_pass;   //Переменная для ввода пароля (правильный:true/неправильный:false)
boolean storedPassword = true;
boolean changedPassword = false;
boolean checkPassword = false;
int i = 1; //переменная для индексации массива
unsigned char WrongAttempts = 0; // глобальная переменная для хранения количества неправильных попыток кода.

/*----------------------------------------------------------------------------*/
void setup() {
  lcd.begin(16, 2); //Установка количества столбцов и строк ЖК-дисплея
  pinMode(solenoidPin, OUTPUT);
  pinMode(buzzer, OUTPUT);
  Serial.begin(9600);
}

void loop() { // Основной цикл
  unlockTheDoor();
}
/********************************ФУНКЦИИ*************************************/
void unlockTheDoor() {
lockAgain: // перейти к метке
  digitalWrite(solenoidPin, HIGH);       //Выключить соленоид
  tempPassword = "";
  lcd.clear();
  i = 6;
  noTone(buzzer);
  while (!checkPassword) {
    lcd.setCursor(0, 0);
    lcd.print("Open the door:  ");
    lcd.setCursor(0, 1);
    lcd.print("PASS>");
    keypressed = myKeypad.getKey();   //Чтение нажатых клавиш
    if (keypressed != NO_KEY) {   // Принимать только цифры и * с клавиатуры
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        tempPassword += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");       // Поместите * на ЖК-дисплей
        i++;
        tone(buzzer, 800, 200); // Звук кнопки
      }
      else if (keypressed == 'A') {
        changePassword();
        goto lockAgain;
      }
      else if (keypressed == 'D') {
        break;
      }
      else if (keypressed == '*') { //Проверить пароль
        if (password == tempPassword) { //Если все верно...
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Correct Password");
          lcd.setCursor(0, 1);
          lcd.print("Door is unlocked");
          tone(buzzer, 100);   // Воспроизвести звук, пока дверь открыта
          delay(100);        // ...на 0,1 сек
          noTone(buzzer);     // Остановить звук...
          digitalWrite(solenoidPin, LOW);      // Включить соленоид
          delay(5000);
          WrongAttempts = 0;
          changePassword(); {
            setLocked (true); ///.......чтобы снова заблокировать
            tone(buzzer, 1000); // Отправляем звуковой сигнал 1 кГц...
            delay(100);        // ...на 0,1 сек
            noTone(buzzer);     // Остановить звук...
            delay(1000);
            lcd.clear();
            goto lockAgain;
          }
          if (keypressed == '#') {
            setLocked (true); ///.......чтобы снова заблокировать
            tone(buzzer, 1000); // Отправляем звуковой сигнал 1 кГц...
            delay(100);        // ...на 0,1 сек
            noTone(buzzer);     // Остановить звук...
            delay(1000);
            lcd.clear();
            goto lockAgain;
          }
        }
        else {           // если неверно, повторить попытку
          tempPassword = "";
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*Wrong Password*");
          tone(buzzer, 500, 200);
          delay(300);
          tone(buzzer, 500, 200);
          delay(300);
          WrongAttempts++;  //ДОБАВЛЕН
          Attempts();
        }
      }
    }
  }
}

//Изменить текущий пароль
void changePassword() {
retry: // метка для перехода
  tempPassword = "";
  lcd.clear();
  i = 1;
  while (!changedPassword) {      // Ожидание текущего пароля
    keypressed = myKeypad.getKey();   //Чтение нажатых клавиш
    lcd.setCursor(0, 0);
    lcd.print("CURRENT PASSWORD");
    lcd.setCursor(0, 1);
    lcd.print(">");
    if (keypressed != NO_KEY) {
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        tempPassword += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");
        i++;
        tone(buzzer, 800, 200);
      }
      else if (keypressed == '#') {
        break;
      }
      else if (keypressed == 'D') {
        goto retry;
      }
      else if (keypressed == '*') {
        i = 1;
        if (password == tempPassword) {
          storedPassword = false;
          tone(buzzer, 500, 200);
          newPassword();          //Пароль правильный, поэтому вызываем функцию newPassword
          break;
        }
        else {              //Попробуй еще раз
          tempPassword = "";
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*Wrong Password*");
          tone(buzzer, 500, 200);
          delay(300);
          tone(buzzer, 500, 200);
          delay(300);
          WrongAttempts++;  //ДОБАВЛЕН
          Attempts();
          goto retry;
        }
      }
    }
  }
}

String firstpass;
//Установить новый пароль
void newPassword() {
retry: // метка для перехода
  tempPassword = "";
  changedPassword = false;
  lcd.clear();
  i = 1;
  while (!storedPassword) {
    keypressed = myKeypad.getKey();   //Чтение нажатых клавиш
    if (doublecheck == 0) {
      lcd.setCursor(0, 0);
      lcd.print("SET NEW PASSWORD");
      lcd.setCursor(0, 1);
      lcd.print(">");
    }
    else {
      lcd.setCursor(0, 0);
      lcd.print("One more time...");
      lcd.setCursor(0, 1);
      lcd.print(">");
    }
    if (keypressed != NO_KEY) {
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        tempPassword += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");
        i++;
        tone(buzzer, 800, 200);
      }
      else if (keypressed == '#') {
        break;
      }
      else if (keypressed == 'D') {
        goto retry;
      }
      else if (keypressed == '*') {
        if (doublecheck == 0) {
          firstpass = tempPassword;
          doublecheck = 1;
          newPassword();
        }
        if (doublecheck == 1) {
          doublecheck = 0;
          if (firstpass == tempPassword) {
            i = 1;
            firstpass = "";
            password = tempPassword; // Новый пароль сохранен
            tempPassword = ""; // стираем временный пароль
            lcd.setCursor(0, 0);
            lcd.print("PASSWORD CHANGED");
            lcd.setCursor(0, 1);
            lcd.print("----------------");
            storedPassword = true;
            tone(buzzer, 500, 400);
            delay(2000);
            lcd.clear();
            break;
          }
          else {
            firstpass = "";
            newPassword();
          }
        }
      }
    }
  }
}

void setLocked(int locked) {
  if (locked) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("*** LOCKED ***");
  }
  else {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("*** UNLOCKED ***");;
  }
}

void Attempts() {
  if (WrongAttempts >= 3) { //ИБП....
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("TO UNLOCK PLEASE");
    lcd.setCursor(0, 1);
    lcd.print("INPUT MASTER KEY");
    digitalWrite(buzzer, HIGH);
    delay (5000);
    master();
  }
}

void master() {
lockAgain: // перейти к метке
retry: // метка для перехода
  tempPassword = "";
  lcd.clear();
  i = 6;
  noTone(buzzer);
  while (!checkPassword) {
    lcd.setCursor(0, 0);
    lcd.print("***MASTER KEY***");
    lcd.setCursor(0, 1);
    lcd.print(">");
    keypressed = myKeypad.getKey();   //Чтение нажатых клавиш
    if (keypressed != NO_KEY) {   // Принимать только цифры и * с клавиатуры
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        tempPassword += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");       // Поместите * на ЖК-дисплей
        i++;
        tone(buzzer, 800, 200); // Звук кнопки
      }
      else if (keypressed == 'D') {
        goto retry;
      }
      else if (keypressed == '*') { //Проверить пароль
        if (master_key == tempPassword) { //Если все верно...
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Correct Password");
          lcd.setCursor(0, 1);
          lcd.print("Door is unlocked");
          tone(buzzer, 100);   // Воспроизвести звук, пока дверь открыта
          delay(100);        // ...на 0,1 сек
          noTone(buzzer);     // Остановить звук...
          digitalWrite(solenoidPin, LOW);      // Включить соленоид
          delay(5000);
          WrongAttempts = 0;
          changePassword(); {
            setLocked (true); ///.......чтобы снова заблокировать
            tone(buzzer, 1000); // Отправляем звуковой сигнал 1 кГц...
            delay(100);        // ...на 0,1 сек
            noTone(buzzer);     // Остановить звук...
            delay(1000);
            lcd.clear();
            unlockTheDoor();
          }
          if (keypressed == '#') {
            setLocked (true); ///.......чтобы снова заблокировать
            tone(buzzer, 1000); // Отправляем звуковой сигнал 1 кГц...
            delay(100);        // ...на 0,1 сек
            noTone(buzzer);     // Остановить звук...
            delay(1000);
            lcd.clear();
            unlockTheDoor();
          }
        }
        else {           // если неверно, повторить попытку
          tempPassword = "";
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*Wrong Password*");
          tone(buzzer, 500, 200);
          delay(300);
          tone(buzzer, 500, 200);
          delay(300);
          WrongAttempts++;  //ДОБАВЛЕН
          Attempts();
        }
      }
    }
  }
}

, 👍-1

Обсуждение

Почти всегда для таких вопросов ответом является использование конечного автомата. По сути, вы бесконечно проверяете, произошли ли входные данные, которые переведут вас в другое состояние. И, как бы вам это ни было больно, ВЫ НЕ ДОЛЖНЫ ИСПОЛЬЗОВАТЬ ЗАДЕРЖКИ в машине состояний. Конечные автоматы обычно не являются первым проектом, за который должен взяться новый программист. Но если хотите, я могу сделать более формальную попытку объяснить конечный автомат в ответе ниже., @st2000

Да, пожалуйста. Спасибо., @Fiery Kenichi

Хорошо, имейте в виду, что не многие здесь будут писать полные программные решения в качестве ответа. Моя собственная в том числе. Что большинство сделает, так это объяснит или укажет на ресурсы, чтобы ответить на вопрос. По сути, я советую вам начать сначала и полностью определить, что вы хотите сделать, а затем написать свой собственный код с использованием конечного автомата. Поэтому я сказал, что это не обязательно лучший подход для нового программиста., @st2000

Должен сказать, теперь, когда я прочитал вопросы несколько раз, не ясно, что вы хотите сделать. Я думаю, вы хотите, чтобы зуммер никогда не издавал шума. Как насчет того, чтобы просто удалить его из проекта?, @st2000

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

Мой план состоял в том, чтобы создать сирену с помощью зуммера, и после 3 неудачных попыток сирена будет активироваться до тех пор, пока не будет нажата кнопка на клавиатуре. И это остановит сигнал тревоги и направит экран для входа в функцию пароля. Все отлично работает без сирены, но я бы хотел, чтобы это произошло., @Fiery Kenichi

Таким образом, ЛЮБОЕ нажатие клавиши должно отключить сигнал тревоги? Кратковременно или на неопределенный срок? Возможно, имеет смысл отключить сигнал тревоги, чтобы дать пользователю возможность ввести правильный пароль, а затем повторно активировать сигнал тревоги, если он снова не сработает. Однако вам нужно подробно описать, что вы хотите сделать, прежде чем вы сможете надеяться реализовать это., @Duncan C

Делать это лучше кратко, как обратный отсчет 10 секунд. Если пароль неверный, просто снова вернитесь в состояние тревоги. Я не думал об этой части., @Fiery Kenichi


1 ответ


1

Подумайте о том, чтобы точно определить, что вы хотите, чтобы ваше приложение Arduino делало, используя подход конечный автомат. Составление диаграммы конечного автомата позволяет разработчику визуализировать входные данные конечного автомата, число & типы необходимых состояний и выходы конечного автомата. Следующая диаграмма из приведенной выше ссылки на wikipedia.org имеет два состояния:

Состояния "Заблокировано" и "Разблокировано". Вы видите, что «Монета» необходима для перехода из состояния «Заблокировано» в состояние «Разблокировано».

Для кодового замка в вопросе, вероятно, нужно учитывать еще много состояний. Например, может быть состояние для каждого введенного номера кнопки. Правильный номер перейдет к следующему состоянию. Неверный номер вернется в состояние, в котором конечный автомат ожидает увидеть 1-е число в коде. Если все цифры в коде введены правильно, последним состоянием, скорее всего, будет состояние, которое разблокирует устройство. Зуммер может иметь собственное состояние. В состоянии зуммера зуммер будет издавать шум. Ввод в конечный автомат, указывающий, что прошла 1/2 секунды, может использоваться для выхода из состояния зуммера.

Таким образом можно создать любое желаемое поведение. Кроме того, с помощью диаграммы состояний проясняются намерения конечной программы. Любые логические ошибки выявляются до создания кода.

,