Кодовый замок на Arduino можно приспособить для различных целей. Это могут быть двери, шкатулки, сейфы или запуск какого-либо действия, например, запуск ракеты).
Техническое задание
Разработать кодовый замок на Arduino, который управляет электромагнитным реле. При правильном вводе 5-значного кода, срабатывает реле и загорается зеленый светодиод. Через 5 секунд реле приходит в изначальное состояние и зеленый светодиод гаснет. Если код введен неверно, то загорается красный светодиод в течение 5 секунд. Код можно вводить бесконечное количество раз.
Разработка
Давайте для начала смоделируем схему в Proteus
На схеме мы видим матрицу из кнопок, два светодиода и вместо катушки реле для удобства взят спикер, который при эмуляции начинает трещать. При правильном наборе кода загорается светодиод L_1 и трещит спикер LS1 в течение 5 секунд.
Код программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include <Keypad.h> #define LED1 10 // красный светодиод #define LED2 11 // зеленый светодиод #define RELAY 12 // реле на замок #define NUM_KEYS 5 // количество знаков в коде char key ; char myarraw [ NUM_KEYS ] = { ‘1’ , ‘2’ , ‘3’ , ‘4’ , ‘5’ } ; // массив с верным кодом char button_pressed [ NUM_KEYS ] ; //массив для хранения нажатых кнопок int k = 0 ; // счетчик нажатий int s = 0 ; // счетчик совпадений нажатых кнопок с верными const byte ROWS = 4 ; // количество строк в матрице клавиатуры const byte COLS = 4 ; // количество столбцов char keys [ ROWS ] [ COLS ] = { // таблица соответствия кнопок символам { ‘1’ , ‘2’ , ‘3’ , ‘A’ } , { ‘4’ , ‘5’ , ‘6’ , ‘B’ } , { ‘7’ , ‘8’ , ‘9’ , ‘C’ } , { ‘*’ , ‘0’ , ‘#’ , ‘D’ } } ; byte rowPins [ ROWS ] = { 5 , 4 , 3 , 2 } ; // пины подключенных строк byte colPins [ COLS ] = { 9 , 8 , 7 , 6 } ; // пины подключенных столбцов Keypad keypad = Keypad ( makeKeymap ( keys ) , rowPins , colPins , ROWS , COLS ) ; // создаем объект клавиатуры для работы с ней void setup ( ) { pinMode ( LED1 , OUTPUT ) ; // красный светодиод pinMode ( LED2 , OUTPUT ) ; // зеленый светодиод pinMode ( RELAY , OUTPUT ) ; // реле управления замком digitalWrite ( RELAY , HIGH ) ; // вход реле инверсный, поэтому его сразу включаем (?!) } void loop ( ) { key = keypad . getKey ( ) ; // спрашиваем у клавиатуры, есть нажатая кнопка? if ( key ! = NO_KEY ) // если она все-таки есть { button_pressed [ k ] = key ; //сохраняем эту кнопочку в массиве k = k + 1 ; // запоминаем сколько уже кнопок нажали if ( k == NUM_KEYS ) // если нажали нужное количество кнопок { for ( uint8_t i = 0 ; i < NUM_KEYS ; i ++ ) // пройдемся по всему массиву { if ( button_pressed [ i ] == myarraw [ i ] ) // и проверим нажатые кнопки с верным кодом { s = s + 1 ; // плюсуем счетчик совпадений } } if ( s == NUM_KEYS ) //если у нас все кнопки совпали с кодом, то включаем реле { digitalWrite ( RELAY , LOW ) ; // включили реле digitalWrite ( LED2 , HIGH ) ; // зажгли зеленый светик (пользователь ввел верный код) delay ( 5000 ) ; // ждем 5 секунд пока горит светик зеленый и включено реле digitalWrite ( RELAY , HIGH ) ; // гасим реле digitalWrite ( LED2 , LOW ) ; // гасим светик k = 0 ; //сбрасываем счетчик нажатий нашей переменной s = 0 ; // сбрасываем счетчик совпадений нашей переменной } else { // если не все кнопки совпали с верным кодом digitalWrite ( LED1 , HIGH ) ; // включаем красный светик (пользователь ввел неверный код) delay ( 5000 ) ; // ждем 5 секунд digitalWrite ( LED1 , LOW ) ; // гасим красн светик k = 0 ; // обнуляем счетчики, чтобы начать все заново s = 0 ; // } } } } |
Описание кода
1 | #include <Keypad.h> |
Для того чтобы мы могли обрабатывать, нажатия клавиш на нашей клавиатуре, мы могли бы написать сами с нуля, библиотеку обработки, но это заняло бы много времени, и в данном случае, программируя на Ардуино, на языке высокого уровня, в этом нет необходимости. Достаточно только подключить готовую библиотеку, которая идет в комплекте библиотек с нашей Arduino IDE.
1 2 3 4 5 6 7 | #define LED1 10 // красный светодиод #define LED2 11 // зеленый светодиод #define RELAY 12 // реле на замок #define NUM_KEYS 5 // количество знаков в коде |
В данном проекте, нам потребуется использовать три значения, которые мы будем использовать при написании нашего кода. Мы могли бы пойти стандартным путем и создать три переменные, присвоить им имена и значения, и затем просто использовать их. Но мы решили пойти немножко дальше, и показать, как можно еще более удобным способом решить данную задачу. Мы создаем 4 директивы, LED 1, LED2 и RELAY, NUM_KEYS и присваиваем им постоянное значение, которое идет после названия директивы. После значения, точку с запятой, как мы привыкли, закрывать нашу строку, ставить не требуется.
1 2 3 4 5 | char key ; char myarraw [ NUM_KEYS ] = { ‘1’ , ‘2’ , ‘3’ , ‘4’ , ‘5’ } ; // массив с верным кодом char button_pressed [ NUM_KEYS ] ; //массив для хранения нажатых кнопок |
Здесь мы знакомимся с новым типом массивов и переменных char, в котором помимо цифровых значений, могут храниться символьные, например буквы, и различные знаки. Итак, мы создаем массив myarraw, который содержит 5 знаков, (не забываем про создание директивы). В данный массив мы записываем 5 значений, которые содержатся в фигурных скобках. Они будут являться кодом, по которому будет открываться наш замок, их вы впоследствии сможете поменять на любые другие. Затем нам нужно создать еще один массив, также 5 знаков, в котором будут храниться значения, наших нажатых кнопок.
1 2 3 | int k = 0 ; // счетчик нажатий int s = 0 ; // счетчик совпадений нажатых кнопок с верными |
Здесь мы объявляем две переменные, к и s, и присваиваем им значение 0. В первой из них у нас будет храниться количество нажатий, а во второй количество совпадений, кода для открытия замка, который мы задали ранее в массиве, с кодом набранным на клавиатуре.
1 2 3 | const byte ROWS = 4 ; // количество строк в матрице клавиатуры const byte COLS = 4 ; // количество столбцов |
Здесь же, мы задаем 2 константы формата byte, в целях экономии памяти, нашего контроллера мы пользуемся форматом для хранения переменных byte, а не привычный многим формат int. В данном случае он будет избыточен, для наших задач.
1 2 3 4 5 6 7 8 9 | char keys [ ROWS ] [ COLS ] = { // таблица соответствия кнопок символам { ‘1’ , ‘2’ , ‘3’ , ‘A’ } , { ‘4’ , ‘5’ , ‘6’ , ‘B’ } , { ‘7’ , ‘8’ , ‘9’ , ‘C’ } , { ‘*’ , ‘0’ , ‘#’ , ‘D’ } } ; |
Теперь же, нам нужно будет создать, таблицу соответствия, кнопок клавиатуры символам, которыебудут сохраняться в наших массивах. Как мы видим, их расположение, совпадает с нанесенными значками на клавиатуре.
1 2 3 | byte rowPins [ ROWS ] = { 5 , 4 , 3 , 2 } ; // пины подключенных строк byte colPins [ COLS ] = { 9 , 8 , 7 , 6 } ; // пины подключенных столбцов |
Ну а здесь, нам требуется создать два массива, по 4 знака каждый, соответственно по количеству строк и столбцов, и задать, к каким пинам ардуино они у нас будут подключены. Формат переменной, как и в прошлом случае, у нас выбран byte.