Есть ли способ для клавиатуры остановить зуммер во время его работы?
Я новичок в 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();
}
}
}
}
}
@Fiery Kenichi, 👍-1
Обсуждение1 ответ
Подумайте о том, чтобы точно определить, что вы хотите, чтобы ваше приложение Arduino делало, используя подход конечный автомат. Составление диаграммы конечного автомата позволяет разработчику визуализировать входные данные конечного автомата, число & типы необходимых состояний и выходы конечного автомата. Следующая диаграмма из приведенной выше ссылки на wikipedia.org имеет два состояния:
Состояния "Заблокировано" и "Разблокировано". Вы видите, что «Монета» необходима для перехода из состояния «Заблокировано» в состояние «Разблокировано».
Для кодового замка в вопросе, вероятно, нужно учитывать еще много состояний. Например, может быть состояние для каждого введенного номера кнопки. Правильный номер перейдет к следующему состоянию. Неверный номер вернется в состояние, в котором конечный автомат ожидает увидеть 1-е число в коде. Если все цифры в коде введены правильно, последним состоянием, скорее всего, будет состояние, которое разблокирует устройство. Зуммер может иметь собственное состояние. В состоянии зуммера зуммер будет издавать шум. Ввод в конечный автомат, указывающий, что прошла 1/2 секунды, может использоваться для выхода из состояния зуммера.
Таким образом можно создать любое желаемое поведение. Кроме того, с помощью диаграммы состояний проясняются намерения конечной программы. Любые логические ошибки выявляются до создания кода.
- Цепь с зуммером не работает
- Пассивный зуммер работает с AnalogWrite(), но не с DigitalWrite(). Он также имеет постоянный статический шум.
- Ток потребления зуммера
- Почему пассивный зуммер щелкает, а не гудит, когда установлен на ВЫСОКИЙ?
- Можем ли мы генерировать тон 20 кГц с обычным зуммером в arduino?
- Не выходит из цикла for
- Как можно иметь два мигающих светодиода и один гаснущий?
- Моя программа использует слишком много памяти
Почти всегда для таких вопросов ответом является использование конечного автомата. По сути, вы бесконечно проверяете, произошли ли входные данные, которые переведут вас в другое состояние. И, как бы вам это ни было больно, ВЫ НЕ ДОЛЖНЫ ИСПОЛЬЗОВАТЬ ЗАДЕРЖКИ в машине состояний. Конечные автоматы обычно не являются первым проектом, за который должен взяться новый программист. Но если хотите, я могу сделать более формальную попытку объяснить конечный автомат в ответе ниже., @st2000
Да, пожалуйста. Спасибо., @Fiery Kenichi
Хорошо, имейте в виду, что не многие здесь будут писать полные программные решения в качестве ответа. Моя собственная в том числе. Что большинство сделает, так это объяснит или укажет на ресурсы, чтобы ответить на вопрос. По сути, я советую вам начать сначала и полностью определить, что вы хотите сделать, а затем написать свой собственный код с использованием конечного автомата. Поэтому я сказал, что это не обязательно лучший подход для нового программиста., @st2000
Должен сказать, теперь, когда я прочитал вопросы несколько раз, не ясно, что вы хотите сделать. Я думаю, вы хотите, чтобы зуммер никогда не издавал шума. Как насчет того, чтобы просто удалить его из проекта?, @st2000
у вас неправильное представление о взаимодействии между микроконтроллером, клавиатурой и сиреной .... сирена никогда не управляется кепадом ... она всегда управляется микроконтроллером .... клавиатура только передает нажатия клавиш на микроконтроллер ... то, что происходит в результате этих нажатий клавиш, определяется программой ... так что все, что вам нужно, это обнаружить последовательность нажатий .... активна ли сирена во время этих нажатий клавиш, не имеет отношения к обнаружению последовательности клавиш .... начните с написания программы определения последовательности клавиш, @jsotola
Мой план состоял в том, чтобы создать сирену с помощью зуммера, и после 3 неудачных попыток сирена будет активироваться до тех пор, пока не будет нажата кнопка на клавиатуре. И это остановит сигнал тревоги и направит экран для входа в функцию пароля. Все отлично работает без сирены, но я бы хотел, чтобы это произошло., @Fiery Kenichi
Таким образом, ЛЮБОЕ нажатие клавиши должно отключить сигнал тревоги? Кратковременно или на неопределенный срок? Возможно, имеет смысл отключить сигнал тревоги, чтобы дать пользователю возможность ввести правильный пароль, а затем повторно активировать сигнал тревоги, если он снова не сработает. Однако вам нужно подробно описать, что вы хотите сделать, прежде чем вы сможете надеяться реализовать это., @Duncan C
Делать это лучше кратко, как обратный отсчет 10 секунд. Если пароль неверный, просто снова вернитесь в состояние тревоги. Я не думал об этой части., @Fiery Kenichi