Điều khiển đếm ngược với Arduino và KEYPAD4X4

Bởi nguyentruongphi (06/09/2025) 0 Bình luận

Dự án Arduino này sử dụng một bàn phím 4x4, màn hình LCD I2C 1602, đèn LED và một chuông báo để mô phỏng hệ thống đếm ngược.

  • Thiết lập mã 4 chữ số và bộ đếm thời gian bằng cách sử dụng bàn phím.
  • Màn hình LCD hiển thị hướng dẫn và bộ đếm thời gian.

Sử dụng mã đúng để vô hiệu hóa trước khi thời gian hết, nếu không, đèn LED đỏ và chuông báo sẽ kích hoạt.

Kết nối chung:

Đèn LED nối với arduino:

  • Đỏ: Kết nối cathode của LED vào bus nguồn âm trên breadboard, và anode của LED vào một điện trở 1kΩ rồi kết nối đến chân 2 trên Arduino.

  • Xanh: Kết nối cathode của LED vào bus nguồn âm trên breadboard, và anode của LED vào một điện trở 1kΩ rồi kết nối đến chân 3 trên Arduino.

Bàn phím (Keypad) nối với arduino:

  • RowPins: Kết nối đến chân 5 đến 8 trên Arduino.

  • ColPins: Kết nối đến chân 9 đến 12 trên Arduino.

Chuông báo (Passive Buzzer)

  • +: Kết nối đến chân 4 trên Arduino.

  • -: Kết nối vào bus nguồn âm của breadboard.

Màn hình LCD I2C 1602

  • SDA: Kết nối đến chân A4 trên Arduino.

  • SCL: Kết nối đến chân A5 trên Arduino.

  • GND: Kết nối vào chân GND arduino

  • VCC: Kết nối vào chân 5V arduino

CODE:

#include <Adafruit_Keypad.h>
#include <LiquidCrystal_I2C.h>

// Pin definitions for 4x4 keypad
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
  { '1','2','3','A' },
  { '4','5','6','B' },
  { '7','8','9','C' },
  { '*','0','#','D' }
};
byte rowPins[ROWS] = { 5, 6, 7, 8 };
byte colPins[COLS] = { 9, 10, 11, 12 };
Adafruit_Keypad keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// LED and buzzer pins
const int RED_LED_PIN   = 2;
const int GREEN_LED_PIN = 3;
const int BUZZER_PIN    = 4;

// I2C LCD at address 0x27, 16 columns × 2 rows
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Storage for arm/disarm code and countdown
int armCode[4], inputCode[4];
unsigned long timeLeft = 0;

// Play a simple beep for key presses (1000Hz, 80ms)
void beepKey() {
  tone(BUZZER_PIN, 1000, 80);
}

// Play a lower beep for each countdown tick (800Hz, 100ms)
void beepCount() {
  tone(BUZZER_PIN, 800, 100);
}

// Play three quick beeps when '#' is pressed to arm
void beepHash() {
  for (int i = 0; i < 3; i++) {
    tone(BUZZER_PIN, 1000, 80);
    delay(120);
  }
}

// Play alternating tones and flash LEDs on disarm success
void beepDisarm() {
  for (int i = 0; i < 3; i++) {
    digitalWrite(RED_LED_PIN, HIGH);
    digitalWrite(GREEN_LED_PIN, LOW);
    tone(BUZZER_PIN, 1200, 200);
    delay(300);
    digitalWrite(RED_LED_PIN, LOW);
    digitalWrite(GREEN_LED_PIN, HIGH);
    tone(BUZZER_PIN, 800, 200);
    delay(300);
  }
  noTone(BUZZER_PIN);
}

void setup() {
  Serial.begin(9600);
  keypad.begin();
  pinMode(RED_LED_PIN, OUTPUT);
  pinMode(GREEN_LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  // Initialize LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();

  // 1. Enter 4-digit arm code
  digitalWrite(RED_LED_PIN, HIGH);
  digitalWrite(GREEN_LED_PIN, HIGH);
  lcd.setCursor(0, 0);
  lcd.print("Ma Kich hoat");
  lcd.setCursor(0, 1);
  lcd.print("Code: ");
  for (int i = 0, col = 6; i < 4; ) {
    keypad.tick();
    if (keypad.available()) {
      auto e = keypad.read();
      if (e.bit.EVENT == KEY_JUST_PRESSED && isDigit(e.bit.KEY)) {
        beepKey();
        armCode[i++] = e.bit.KEY - '0';
        lcd.setCursor(col++, 1);
        lcd.print((char)e.bit.KEY);
      }
    }
  }
  delay(500);
  digitalWrite(RED_LED_PIN, LOW);
  digitalWrite(GREEN_LED_PIN, LOW);

  // 2. Show disarm code
  digitalWrite(RED_LED_PIN, HIGH);
  digitalWrite(GREEN_LED_PIN, HIGH);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Disarm Code:");
  lcd.setCursor(0, 1);
  for (int i = 0; i < 4; i++) {
    lcd.print(armCode[i]);
  }
  delay(1000);

  // 3. Set countdown time (HH:MM:SS)
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Time: HH:MM:SS");
  lcd.setCursor(0, 1);
  lcd.print("SET: ");
  int t[6];
  for (int i = 0; i < 6; ) {
    keypad.tick();
    if (keypad.available()) {
      auto e = keypad.read();
      if (e.bit.EVENT == KEY_JUST_PRESSED && isDigit(e.bit.KEY)) {
        beepKey();
        t[i] = e.bit.KEY - '0';
        int pos = (i < 2 ? 5 + i : (i < 4 ? 8 + (i - 2) : 11 + (i - 4)));
        lcd.setCursor(pos, 1);
        lcd.print((char)e.bit.KEY);
        i++;
      }
    }
  }
  int HH = t[0]*10 + t[1];
  int MM = t[2]*10 + t[3];
  int SS = t[4]*10 + t[5];
  timeLeft = HH*3600UL + MM*60UL + SS;

  // 4. Center display initial countdown for 2 seconds
  char buf[9];
  sprintf(buf, "%02d:%02d:%02d", HH, MM, SS);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Time:");
  lcd.setCursor((16 - 8) / 2, 1);
  lcd.print(buf);
  delay(2000);

  // 5. Prompt to arm with centered "# To Arm"
  lcd.clear();
  lcd.setCursor((16 - 7) / 2, 0);
  lcd.print("# Ready");
  while (true) {
    keypad.tick();
    if (keypad.available()) {
      auto e = keypad.read();
      if (e.bit.EVENT == KEY_JUST_PRESSED && e.bit.KEY == '#') {
        beepHash();
        break;
      }
    }
  }

  // 6. Show armed message for 2 seconds
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Kich hoat!");
  lcd.setCursor(0, 1);
  lcd.print("Bat dau dem");
  digitalWrite(GREEN_LED_PIN, HIGH);
  delay(2000);
}

void loop() {
  static unsigned long prev = millis();
  static bool disarmMode = false;
  static int di = 0;
  char buf[9];

  keypad.tick();

  // 7. Update countdown every second on second line
  unsigned long now = millis();
  if (now - prev >= 1000) {
    prev += 1000;
    if (timeLeft > 0) {
      timeLeft--;
      int h = timeLeft / 3600;
      int m = (timeLeft % 3600) / 60;
      int s = timeLeft % 60;
      sprintf(buf, "%02d:%02d:%02d", h, m, s);
      if (!disarmMode) {
        lcd.clear();
      }
      lcd.setCursor(0, 1);
      lcd.print("Time:");
      lcd.print(buf);
      beepCount();
    }
  }

  // 8. Press '*' to disarm (does not pause countdown)
  if (keypad.available()) {
    auto e = keypad.read();
    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      beepKey();
      if (e.bit.KEY == '*' && !disarmMode) {
        disarmMode = true;
        di = 0;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Code:");
        sprintf(buf, "%02d:%02d:%02d",
                timeLeft / 3600,
                (timeLeft % 3600) / 60,
                timeLeft % 60);
        lcd.setCursor(0, 1);
        lcd.print("Time:");
        lcd.print(buf);
      }
      else if (disarmMode && isDigit(e.bit.KEY) && di < 4) {
        inputCode[di] = e.bit.KEY - '0';
        lcd.setCursor(6 + di, 0);
        lcd.print((char)e.bit.KEY);
        di++;
        if (di == 4) {
          bool ok = true;
          for (int i = 0; i < 4; i++) {
            if (inputCode[i] != armCode[i]) ok = false;
          }
          if (ok) {
            beepDisarm();
            lcd.clear();
            lcd.setCursor(0, 0);
            lcd.print("Vo hieu hoa!");
            lcd.setCursor(0, 1);
            lcd.print("Well Done!");
            while (true);  // stop further action
          }
          disarmMode = false;  // wrong code, back to countdown
        }
      }
    }
  }

  // 11. Explode when time reaches zero
  if (timeLeft == 0) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("DONE");
    lcd.setCursor(0, 1);
    lcd.print(".....!!!");
    while (true) {
      digitalWrite(RED_LED_PIN, HIGH);
      digitalWrite(GREEN_LED_PIN, LOW);
      beepKey();         // use same “beep” tone
      delay(100);
      digitalWrite(RED_LED_PIN, LOW);
      digitalWrite(GREEN_LED_PIN, HIGH);
      beepKey();
      delay(100);
    }
  }
}

Đóng góp ý kiến

Hotline 0938379351