diff --git a/src/src/main.cpp b/src/src/main.cpp index c85a191..f19e722 100644 --- a/src/src/main.cpp +++ b/src/src/main.cpp @@ -4,12 +4,12 @@ #include // piny -constexpr byte ENCODER_CLK_PIN = 11; // pwm pin, ale nepoužívá se +constexpr byte ENCODER_CLK_PIN = 11; constexpr byte ENCODER_DT_PIN = 12; -constexpr byte BUTTON_PIN = 13; -constexpr byte RGB_RED_PIN = 3; // pwm -constexpr byte RGB_GREEN_PIN = 5; // pwm -constexpr byte RGB_BLUE_PIN = 6; // pwm +constexpr byte BUTTON_PIN = 2; // ZMĚNA: přesunuto na pin 2 (INT0) kvůli přerušení +constexpr byte RGB_RED_PIN = 3; +constexpr byte RGB_GREEN_PIN = 5; +constexpr byte RGB_BLUE_PIN = 6; constexpr byte SERVO_PIN = 9; constexpr byte BUZZER_PIN = 8; @@ -21,46 +21,48 @@ Servo servo; // LCD LiquidCrystal_I2C lcd(0x27, 16, 2); -// proměnné -// příklad je zadávané heslo, stavy, apod. -int password = 0; // 0-9999 +int password = 0; int passwordValue = 0; String savedPassword = ""; -// stav zámku bool isOpen = false; -// enkodér int lastCLK = HIGH; -// blokace po špatných pokusech constexpr byte MAX_WRONG_ATTEMPTS = 3; constexpr unsigned long LOCKOUT_DURATION_MS = 30000UL; byte wrongAttempts = 0; bool lockedOut = false; unsigned long lockoutStart = 0; -// maska – po kolika ms nečinnosti se heslo maskuje constexpr unsigned long MASK_DELAY_MS = 2000; unsigned long lastEncoderMove = 0; bool masked = false; -// přeformátování kódu na 4 cifry +// přerušení tlačítka +volatile bool buttonPressed = false; +constexpr unsigned long DEBOUNCE_MS = 50; +unsigned long lastButtonTime = 0; + +void onButtonPress() { + if (const unsigned long now = millis(); now - lastButtonTime >= DEBOUNCE_MS) { + lastButtonTime = now; + buttonPressed = true; + } +} + String formatCode(const int value) { auto s = String(value); while (s.length() < 4) s = "0" + s; return s; } -// chování zámku -void OpenLock() { servo.write(OPEN_POS); } +void OpenLock() { servo.write(OPEN_POS); } void CloseLock() { servo.write(CLOSED_POS); } -// chování bzučáku void OpenSound() { - const int melody[] = { 262, 330, 392, 523 }; // C4, E4, G4, C5 + const int melody[] = { 262, 330, 392, 523 }; const int durations[] = { 150, 150, 150, 300 }; - for (int i = 0; i < 4; i++) { tone(BUZZER_PIN, melody[i], durations[i]); delay(durations[i] + 30); @@ -75,100 +77,73 @@ void CloseSound() { } void ConfirmSound() { - tone(BUZZER_PIN, 440, 100); - delay(130); - tone(BUZZER_PIN, 880, 200); - delay(230); + tone(BUZZER_PIN, 440, 100); delay(130); + tone(BUZZER_PIN, 880, 200); delay(230); noTone(BUZZER_PIN); } -// chování RGB LED void OpenLED() { analogWrite(RGB_GREEN_PIN, 120); - analogWrite(RGB_BLUE_PIN, 0); - analogWrite(RGB_RED_PIN, 0); + analogWrite(RGB_BLUE_PIN, 0); + analogWrite(RGB_RED_PIN, 0); } void CloseLED() { analogWrite(RGB_GREEN_PIN, 0); - analogWrite(RGB_BLUE_PIN, 0); - analogWrite(RGB_RED_PIN, 120); + analogWrite(RGB_BLUE_PIN, 0); + analogWrite(RGB_RED_PIN, 120); } -// když není uložené heslo, ukazuje se modrá void NeutralLED() { analogWrite(RGB_GREEN_PIN, 0); - analogWrite(RGB_BLUE_PIN, 120); - analogWrite(RGB_RED_PIN, 0); + analogWrite(RGB_BLUE_PIN, 120); + analogWrite(RGB_RED_PIN, 0); } -// blikání červené během blokace void BlockedLED() { - // bliká každých 500 ms const bool blink = millis() / 500 % 2 == 0; analogWrite(RGB_RED_PIN, blink ? 120 : 0); analogWrite(RGB_GREEN_PIN, 0); analogWrite(RGB_BLUE_PIN, 0); } -void ButtonPressed() { - if (savedPassword != "") - { - if (formatCode(password) == savedPassword) { - OpenLock(); - OpenSound(); - OpenLED(); - password = 0; - } - else { - CloseLock(); - CloseSound(); - CloseLED(); - password = 0; - } - } -} - -// zobrazení zadávací obrazovky void showEntryScreen(const bool showValue) { lcd.setCursor(0, 0); lcd.printstr("Zadejte heslo: "); lcd.setCursor(0, 1); if (showValue) { String code = formatCode(password); - const String display = code[0] + String(" ") + code[1] + String(" ") + code[2] + String(" ") + code[3] + String(" "); + String display = code[0] + String(" ") + code[1] + String(" ") + code[2] + String(" ") + code[3] + String(" "); lcd.printstr(display.c_str()); } else { lcd.printstr("* * * * "); } } -// zobrazení setup obrazovky void showSetupScreen(const bool showValue) { lcd.setCursor(0, 0); lcd.printstr("Nastavte heslo: "); lcd.setCursor(0, 1); if (showValue) { String code = formatCode(passwordValue); - const String display = code[0] + String(" ") + code[1] + String(" ") + code[2] + String(" ") + code[3] + String(" "); + String display = code[0] + String(" ") + code[1] + String(" ") + code[2] + String(" ") + code[3] + String(" "); lcd.printstr(display.c_str()); } else { lcd.printstr("* * * * "); } } -// setup fáze – blokující, dokud není heslo uloženo void runPasswordSetup() { NeutralLED(); passwordValue = 0; masked = false; lastEncoderMove = millis(); lastCLK = digitalRead(ENCODER_CLK_PIN); + buttonPressed = false; // vyprázdnit případný příznak z doby před setupem showSetupScreen(true); while (savedPassword == "") { - // čtení enkodéru const int currentCLK = digitalRead(ENCODER_CLK_PIN); if (currentCLK != lastCLK && currentCLK == LOW) { if (const int dt = digitalRead(ENCODER_DT_PIN); dt != currentCLK) { @@ -182,14 +157,15 @@ void runPasswordSetup() { } lastCLK = currentCLK; - // maskování po nečinnosti if (!masked && millis() - lastEncoderMove >= MASK_DELAY_MS) { masked = true; showSetupScreen(false); } - // potvrzení tlačítkem - if (digitalRead(BUTTON_PIN) == HIGH) { + // přerušení – konzumace příznaku místo přímého čtení pinu + if (buttonPressed) { + buttonPressed = false; + savedPassword = formatCode(passwordValue); ConfirmSound(); @@ -199,15 +175,10 @@ void runPasswordSetup() { lcd.printstr("* * * * "); delay(1500); - // přechod do normálního režimu lcd.setCursor(0, 0); lcd.printstr("Zadejte heslo: "); lcd.setCursor(0, 1); lcd.printstr(" "); - - // debounce - while (digitalRead(BUTTON_PIN) == HIGH) {} - delay(50); } } } @@ -224,41 +195,40 @@ void setup() { lcd.printstr("Program startuje"); lcd.setCursor(0, 1); lcd.printstr("NastavujeSeMotor"); - delay(100); Serial.println("Nastavování motoru."); servo.attach(SERVO_PIN); - servo.write(CLOSED_POS); // ve výchozím stavu je zamčeno + servo.write(CLOSED_POS); Serial.println("Motor nastaven."); lcd.setCursor(0, 1); lcd.printstr("Motor nastaven. "); - delay(100); lcd.setCursor(0, 1); lcd.printstr("NastavujiSePiny."); Serial.println("Nastavování pinů"); - // Credit: formátování vymyšleno přes Claude Sonnet 4.6 - pinMode(BUTTON_PIN, INPUT_PULLDOWN); Serial.println("Piny: 1/8"); - pinMode(RGB_RED_PIN, OUTPUT); Serial.println("Piny: 2/8"); - pinMode(RGB_GREEN_PIN, OUTPUT); Serial.println("Piny: 3/8"); - pinMode(RGB_BLUE_PIN, OUTPUT); Serial.println("Piny: 4/8"); + pinMode(BUTTON_PIN, INPUT_PULLDOWN); Serial.println("Piny: 1/8"); + pinMode(RGB_RED_PIN, OUTPUT); Serial.println("Piny: 2/8"); + pinMode(RGB_GREEN_PIN, OUTPUT); Serial.println("Piny: 3/8"); + pinMode(RGB_BLUE_PIN, OUTPUT); Serial.println("Piny: 4/8"); pinMode(ENCODER_CLK_PIN, INPUT); Serial.println("Piny: 5/8"); - pinMode(ENCODER_DT_PIN, INPUT); Serial.println("Piny: 6/8"); - pinMode(SERVO_PIN, OUTPUT); Serial.println("Piny: 7/8"); - pinMode(BUZZER_PIN, OUTPUT); Serial.println("Piny: 8/8"); + pinMode(ENCODER_DT_PIN, INPUT); Serial.println("Piny: 6/8"); + pinMode(SERVO_PIN, OUTPUT); Serial.println("Piny: 7/8"); + pinMode(BUZZER_PIN, OUTPUT); Serial.println("Piny: 8/8"); Serial.println("Piny nastaveny."); lcd.setCursor(0, 1); lcd.printstr("Piny nastaveny. "); delay(1000); + // registrace přerušení – RISING: stisk při HIGH (INPUT_PULLDOWN) + attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), onButtonPress, RISING); + runPasswordSetup(); } void loop() { - // Serial Monitor – příkaz "unblock" zruší blokaci if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); @@ -280,10 +250,8 @@ void loop() { } } - // blokace – čeká odpočítávání, neblokuje loop if (lockedOut) { if (const unsigned long elapsed = millis() - lockoutStart; elapsed >= LOCKOUT_DURATION_MS) { - // konec blokace lockedOut = false; wrongAttempts = 0; Serial.println("Blokace skoncila."); @@ -293,7 +261,6 @@ void loop() { lastEncoderMove = millis(); showEntryScreen(true); } else { - // odpočítávání na LCD – aktualizuje jen každou sekundu static unsigned long lastCountdownUpdate = 0; if (millis() - lastCountdownUpdate >= 1000) { lastCountdownUpdate = millis(); @@ -307,11 +274,10 @@ void loop() { } BlockedLED(); } - return; // zbytek loop se přeskočí + buttonPressed = false; // zahazovat stisky během blokace + return; } - // čtení enkodéru – jen pokud je zamčeno - // (při odemčeném stavu enkodér nemá smysl) if (!isOpen) { const int currentCLK = digitalRead(ENCODER_CLK_PIN); if (currentCLK != lastCLK && currentCLK == LOW) { @@ -326,24 +292,20 @@ void loop() { } lastCLK = currentCLK; - // maskování po nečinnosti if (!masked && millis() - lastEncoderMove >= MASK_DELAY_MS) { masked = true; showEntryScreen(false); } } - // tlačítko - if (digitalRead(BUTTON_PIN) == HIGH) { - // debounce - while (digitalRead(BUTTON_PIN) == HIGH) {} - delay(50); + // konzumace příznaku z přerušení + if (buttonPressed) { + buttonPressed = false; if (!isOpen) { - // pokus o odemčení if (formatCode(password) == savedPassword) { isOpen = true; - wrongAttempts = 0; // reset po úspěšném odemčení + wrongAttempts = 0; OpenLock(); OpenLED(); OpenSound(); @@ -353,7 +315,6 @@ void loop() { lcd.setCursor(0, 1); lcd.printstr("Stiskni pro zamk"); } else { - // špatné heslo wrongAttempts++; Serial.print("Spatny pokus: "); Serial.print(wrongAttempts); @@ -363,7 +324,6 @@ void loop() { CloseSound(); if (wrongAttempts >= MAX_WRONG_ATTEMPTS) { - // spustit blokaci lockedOut = true; lockoutStart = millis(); Serial.println("Zamek zablokovan na 30 sekund. Pouzij 'unblock' pro zruseni."); @@ -382,14 +342,12 @@ void loop() { lcd.printstr(" "); delay(1500); - // návrat na zadávací obrazovku, hodnota zachována masked = false; lastEncoderMove = millis(); showEntryScreen(true); } } } else { - // zamčení isOpen = false; CloseLock(); CloseLED(); @@ -401,4 +359,4 @@ void loop() { showEntryScreen(true); } } -} +} \ No newline at end of file