image

Предыстория:


Однажды вечером, в незапамятные времена, на Хабре я увидел несколько статей по Ардуинке… и знаете что? Я тоже захотел такую штуку
На следующий день незамедлительно были заказаны с eBay:

1. Funduino Mega2560
2. LCD KeyPad Shield

Как мне показалось, этого комплекта хватит не на долго… Так и оказалось. За пару дней Ардуина и Шилд были измучены и оставлены лежать в одиночестве, в ожидании новой партии комплектующих с eBay.

Step 1

Плавным движением руки одеваем наш LCD KeyPad Shield на Мегу. У нас получается вот такой «бутерброд»:

image

Step 2

Идем за шоколадкой, сладкое нам пригодится.
После успешного открытия шоколадки открываем Arduino IDE и создаем новый скетч.

Step 3

Приступаем к написанию кода.
Начнем с объявления переменных и библиотек:

// Библиотеки
#include <LiquidCrystal.h> // Библиотека LCD
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 ); // Объявим к камим пинам подключен LCD
// Переменные
int button; // Кнопка
int codeIndex = 0; // Хранение последовательности ввода чисел
int led = 13; //  LED
int userInputs[4]; // Массив для сохранения в нем вводимых чисел с KeyPad
int doorPass[4] = {1,2,3,4}; // Пароль для "двери"
// Кнопки
const int BUTTON_NONE   = 0; 
const int BUTTON_RIGHT  = 1;
const int BUTTON_UP     = 2; // Комментарии излишни
const int BUTTON_DOWN   = 3; // думаю,что сдесь все понятно.
const int BUTTON_LEFT   = 4;
const int BUTTON_SELECT = 5;


Я старался комментировать каждую строчку кода, если вас что-то будет не понятно, с радостью отвечу в комментариях.
Затем добавим процедуру получения значения кнопки:

// Получение значения кнопки
int getPressedButton()
{
  int buttonValue = analogRead(0);
  if (buttonValue < 100) {
    return BUTTON_RIGHT;  
  }
  else if (buttonValue < 200) {
    return BUTTON_UP;
  }
  else if (buttonValue < 400){
    return BUTTON_DOWN;
  }
  else if (buttonValue < 600){
    return BUTTON_LEFT;
  }
  else if (buttonValue < 800){
    return BUTTON_SELECT;
  }
  return BUTTON_NONE;
}


Теперь создаем главную функцию:

// SETUP
void setup()
{
  Serial.begin(9600); // Задаем скорость порта
  lcd.begin(16, 2); // В моем LCD 2 строчки по 16 символов          
  lcd.print("   ENTER PIN   "); // На первой строчку пишем "ENTER PIN"
  lcd.setCursor(0, 2);  // Устанавливаем курсор на 1 символ 2-ой строки
  lcd.print("     LOCKED     "); // На вторую строчку пишем "LOCKED"
  pinMode(led, OUTPUT); // Устанавливаем ПинМод для 13 пина
}


Так же создадим функцию для программной перезагрузки Ардуино:

// RESET FUNC
void(* resetFunc) (void) = 0;


Создаем функцию loop(), она является самой главной частью нашей программы:

// LOOP
void loop()
{
 button = getPressedButton(); // Присваиваем кнопке значение
 if(button!=0 && button!=5){ // Что-то нажали
  userInputs[codeIndex]=button; // Запомнили что нажали
  delay(250); // Защита от дребезга кнопок
  codeIndex++; // Ждем следующую кнопку
 if(codeIndex >= 4){ // Пользователь ввел код целиком
  if (userInputs[0] == doorPass[0] &&
      userInputs[1] == doorPass[1] &&  // Сверка массивов
      userInputs[2] == doorPass[2] &&  // Проверка кода на правильность
      userInputs[3] == doorPass[3]) {
        lcd.setCursor(0,1);
        lcd.print(" Access Granted ");
        digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(3000);               // wait for a 3 second
        lcd.setCursor(0, 1);
        lcd.print("     LOCKED     ");
        digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
        userInputs[0] = 0;
        userInputs[1] = 0;
        userInputs[2] = 0;  // Обнуляем введеные цифры
        userInputs[3] = 0;
        userInputs[4] = 0;
        resetFunc();
      } else {
        lcd.setCursor(0,1);
        lcd.print(" Access Denied! ");
        userInputs[0] = 0;
        userInputs[1] = 0;
        userInputs[2] = 0;  // Обнуляем введеные цифры
        userInputs[3] = 0;
        userInputs[4] = 0;
        delay(3000);
        resetFunc();
    }
   }
  }
 }


У вас должен получиться приблизительно такой код:

// Библиотеки
#include <LiquidCrystal.h> // Библиотека LCD
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 ); // Объявим к камим пинам подключен LCD
// Переменные
int button; // Кнопка
int codeIndex = 0; // Хранение последовательности ввода чисел
int led = 13; //  LED
int userInputs[4]; // Массив для сохранения в нем вводимых чисел с KeyPad
int doorPass[4] = {1,2,3,4}; // Пароль для "двери"
// Кнопки
const int BUTTON_NONE   = 0; 
const int BUTTON_RIGHT  = 1;
const int BUTTON_UP     = 2; // Комментарии излишни
const int BUTTON_DOWN   = 3; // думаю,что сдесь все понятно.
const int BUTTON_LEFT   = 4;
const int BUTTON_SELECT = 5;
// Получение значения кнопки
int getPressedButton()
{
  int buttonValue = analogRead(0);
  if (buttonValue < 100) {
    return BUTTON_RIGHT;  
  }
  else if (buttonValue < 200) {
    return BUTTON_UP;
  }
  else if (buttonValue < 400){
    return BUTTON_DOWN;
  }
  else if (buttonValue < 600){
    return BUTTON_LEFT;
  }
  else if (buttonValue < 800){
    return BUTTON_SELECT;
  }
  return BUTTON_NONE;
}
// SETUP
void setup()
{
  Serial.begin(9600); // Задаем скорость порта
  lcd.begin(16, 2); // В моем LCD 2 строчки по 16 символов          
  lcd.print("   ENTER PIN   "); // На первой строчку пишем "ENTER PIN"
  lcd.setCursor(0, 2);  // Устанавливаем курсор на 1 символ 2-ой строки
  lcd.print("     LOCKED     "); // На вторую строчку пишем "LOCKED"
  pinMode(led, OUTPUT); // Устанавливаем ПинМод для 13 пина
}
// RESET FUNC
void(* resetFunc) (void) = 0;
// LOOP
void loop()
{
 button = getPressedButton(); // Присваиваем кнопке значение
 if(button!=0 && button!=5){ // Что-то нажали
  userInputs[codeIndex]=button; // Запомнили что нажали
  delay(250); // Защита от дребезга кнопок
  codeIndex++; // Ждем следующую кнопку
 if(codeIndex >= 4){ // Пользователь ввел код целиком
  if (userInputs[0] == doorPass[0] &&
      userInputs[1] == doorPass[1] &&  // Сверка массивов
      userInputs[2] == doorPass[2] &&  // Проверка кода на правильность
      userInputs[3] == doorPass[3]) {
        lcd.setCursor(0,1);
        lcd.print(" Access Granted ");
        digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(3000);               // wait for a 3 second
        lcd.setCursor(0, 1);
        lcd.print("     LOCKED     ");
        digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
        userInputs[0] = 0;
        userInputs[1] = 0;
        userInputs[2] = 0;  // Обнуляем введеные цифры
        userInputs[3] = 0;
        userInputs[4] = 0;
        resetFunc();
      } else {
        lcd.setCursor(0,1);
        lcd.print(" Access Denied! ");
        userInputs[0] = 0;
        userInputs[1] = 0;
        userInputs[2] = 0;  // Обнуляем введенные цифры
        userInputs[3] = 0;
        userInputs[4] = 0;
        delay(3000);
        resetFunc();
    }
   }
  }
 }


Все! Теперь скорее загружаем наш скетч в контроллер.

Step 4

Давайте протестируем наш замок.
Включаем плату:

image

Давайте введем правильный пароль:

image

А теперь неправильный:

image

Дальнейшие планы:
1. Сделать запись и чтение пароля из EPROM и наконец-то добавить серву.
2. Сделать меню для смены пароля.
3. Сделать дополнительный длинный сервисный пароль, который в случае изменения пароля двери злоумышленником, поможет его изменить (и себя тоже).
4. Сделать логирование введенных паролей, как правильных, так и неправильных, даты и времени.
5. Добавить звуков.

P.S. Изначально я планировал использовать вместо светодиода — серву, но к сожалению наша почта России… да вы и сами все знаете.
P.P.S. Статья со временем будет дополняться и изменяться, в лучшую сторону конечно.