// ************************************
// ** Кодовый замок 08.10.2017 **
// ************************************
//Дисплей TM1637
#include "SevenSegmentTM1637.h"
#include "SevenSegmentExtended.h"
#include "SevenSegmentFun.h"
//Определяем пины для подключения к плате Arduino
#define TONE_PIN 2 //Пишалка
#define CLK_PIN 3 //Дисплей CLK
#define DIO_PIN 4 //Дисплей DIO
#define MIN5V_PIN A2 //Управляемый минус 5V (для вкл/вык питания сервы)
#define ZAMOK_PIN 5 //Управление серво
#define LEDRED_PIN A0 //Красный светодиод
#define LEDGREEN_PIN A1 //Зеленый светодиод
SevenSegmentFun display(CLK_PIN, DIO_PIN);
//Ячейки памяти
#include
#define EEPROM_Z 0 //Состояние замка
#define EEPROM_S 1 //Режим звука
#define EEPROM_LO 2 //Положение сервы в режиме открыто (две ячейки)
#define EEPROM_LC 4 //Положение сервы в режиме закрыто (две ячейки)
#define EEPROM_P 6 //Храним пинкод
//Клавиатура
#include
const byte ROWS = 4; // 4 строки
const byte COLS = 4; // 4 столбца
#include //Библиотека для управления сервоприводом (сервой)
Servo myServo;
bool sound; //Режим звука
bool zamok; //Состояние замка 0 - открыт
bool dostup = false; // Состояние доступа. Когда истина, доступны функции смены кода и установки положения сервы
#define NMAX 4 //Максимальное количество цифр в коде (при желании можно увеличить)
int latch_op, latch_cl; //Значение угла для открытой и закрытой защелки
char pin0[NMAX]; //Правильный код
char pin[NMAX]; //Введенный код
char newpin1[NMAX]; //Новый код, введенный первый раз
char newpin2[NMAX]; //Новый код, введенный второй раз
byte newpin = 0; //Режим 0 = обычный ввод, 1 и 2 ввод нового пароля, 3 - настройка сервы
byte n; //Сколько цифр уже введено
unsigned long currentMillis; //Текущее значение внутреннего времени
unsigned long previousMillis; //Запомненное значение внутреннего времени
bool flag = true; //Флаг. устанавливается когда начали ввод... и сбрасывается через 5 секунд (если ничего не вводили)
char keys[ROWS][COLS] = { //Коды клавиш
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {6, 7, 8, 9};
//byte colPins[COLS] = {13, 12, 11, 10}; //Arduino Mini
byte colPins[COLS] = {15, 14, 16, 10}; //Arduino Micro
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup(){
//Инициализация модуля дисплея
display.begin(); // initializes the display
display.setBacklight(100); // set the brightness to 100 %
//Определяем назначение выводов
pinMode(MIN5V_PIN, OUTPUT); //Управляемая земля -5V (Когда низкий уровень, питание на сервоприводе нет!
pinMode(LEDRED_PIN, OUTPUT); //Красный светодиод (закрыто)
pinMode(LEDGREEN_PIN, OUTPUT); //Зеленый светодиод (открыто)
pinMode(TONE_PIN, OUTPUT); // Пьеопишалка (звку нажатия клавишь и проигрывание мелодии)
digitalWrite(LEDRED_PIN, HIGH); // включаем светодиоды (просто для контроля)
digitalWrite(LEDGREEN_PIN, HIGH);
Serial.begin(9600); // Порт нужен только для контроля с PC
display.snake(3);
myServo.attach(ZAMOK_PIN); //Сервопривод замка // Определяем сервопривод
//Считываем настройки из памяти
if (EEPROM.read(EEPROM_S) > 1) // Начальная настройка режима звука
{
sound = 1;
EEPROM.write(EEPROM_S, sound);
}
else sound = EEPROM.read(EEPROM_S);
//первоначальные настройки сервы 55 зак 105 открыт. Опытным путем. При первой загрузке записать в память, а потом нужно закоментить и перегрузить снова
// EEPROM.write(EEPROM_LO, lowByte(55)); //Записываем младший байт
//EEPROM.write(EEPROM_LO + 1, highByte(55)); //Записываем старший байт
//EEPROM.write(EEPROM_LC, lowByte(105)); //Записываем младший байт
//EEPROM.write(EEPROM_LC + 1, highByte(105)); //Записываем старший байт
// Настройки сервы
latch_op = (EEPROM.read(EEPROM_LO + 1) << 8 | EEPROM.read(EEPROM_LO)); //Считываем значение открытого положения (два байта, старший и младший)
latch_cl = (EEPROM.read(EEPROM_LC + 1) << 8 | EEPROM.read(EEPROM_LC)); // Считываем значение закрытого положения (два байта, старший и младший)
if (EEPROM.read(EEPROM_Z) > 1) { // Начальная настройка состояния замка. По умолчанию - закрыт
zamok = 1;
EEPROM.write(EEPROM_Z, zamok);
}
else zamok = EEPROM.read(EEPROM_Z); // Если уже есть допустимое значение, то его и используем
uprzamkom(zamok); //Запускаем процедуру управления замком. На случай сбоев питиания
Serial.println("Настройки сервы: ");
Serial.print("Открыто: ");
Serial.println(latch_op);
Serial.print("Закрыто: ");
Serial.println(latch_cl);
Serial.print("Текущий код: ");
for (int i = 0; i < NMAX;i++) { // Вынимаем контрольный код из памяти
pin0[i] = (char)EEPROM.read(EEPROM_P+i); // Достаем код
if (((byte)pin0[i] < 47) || ((byte)pin0[i] > 57)) // Начальное заполнение (при первом включении заполняется нулями и код получается "0000"
{
pin0[i] = '0';
EEPROM.write(EEPROM_P+i, pin0[i]);
}
Serial.print(pin0[i]); // Выводим каждую цифру на экран. Для отладки
}
Serial.println();
play(1);
}
void loop(){ //Основной цикл
currentMillis = millis(); // Метка времени (от начала работы контроллера
char key = keypad.getKey(); // Считываем код клавиши
if (key)
{
flag = true; //Установили флаг (пометили, что начался ввод)
Serial.print(key); // Выводим клавишу в порт
previousMillis = currentMillis; // Запоминаем метку времен
switch (key) {
//***********************************************************
case '*': //Если нажата *
if (sound) sound = false;// если звук был включен, то выключим
else sound = true; // или наоборот
EEPROM.write(1, sound); //Запомним в памяти
Serial.print("sound="); // Выводим на экран PC (для отладки)
Serial.println(sound);
play(3);
break;
//***********************************************************
case '#': //Завершен ввод ввод
//Если был режим корректировки положения сервы (угол поворота замка), то записываем то, что есть (что было после настройки)
if (newpin == 3)
{
Serial.println();
Serial.println("Настройки сервы: ");
display.blink(); //Помигать записанным значением!
if (zamok) { //Если режим настройки был нажат во время закрытого замка, то настраиваем угол в закрытом состоянии
Serial.print("Закрыто: ");
Serial.println(latch_cl);
EEPROM.write(EEPROM_LC, lowByte(latch_cl)); //Записываем младший байт
EEPROM.write(EEPROM_LC + 1, highByte(latch_cl)); //Записываем старший байт
}
else { //записываем угол сервы в открытом состоянии
Serial.print("Открыто: ");
Serial.println(latch_op);
EEPROM.write(EEPROM_LO, lowByte(latch_op)); //Записываем младший байт
EEPROM.write(EEPROM_LO + 1, highByte(latch_op)); //Записываем старший байт
}
newpin = 0;
n = 0;
dostup = false; //Закрываем доступ к настройкам
play(1); // звуковой сигнал
digitalWrite(LEDGREEN_PIN, LOW);
digitalWrite(LEDRED_PIN, LOW);
break; // Выходим из подпрограммы
}
if (n == NMAX) { // Если нужное количество символов
switch (newpin) { //Если режим смены кода
case 1: // Если код один раз уже вводился
newpin = 2; // значит помечаем, как ввод второго раза
play(2);
Serial.println("Введите код еще один раз");
previousMillis = millis(); //Запомнить отметку времени (чтобы ждать следующее нажатие не более 5 с
n = 0; // Начинаем вводить с начала
break;
case 2: // Если код в режиме смены кода введен уже второй раз
for (int i = 0; i < NMAX;++i) { // Последовательно проверяем
if (newpin1[i] == newpin2[i]) dostup = true;
else {
dostup = false;
break; } //Если хоть одна ошибка - выходим
}
if (dostup) { // Если проверка прошла успешно
display.blink(); //Помигать записанным значением!
play(1); // проигрываем красивую мелодию
for (int i = 0; i 5000) { // Если прошло 5сек с момента последнего нажатия
if (flag) { // Если отметка установлена то (это просто для того, чтобы лишний раз не выполнять действия по обнулению
flag = false; //Слишком большая пауза. Сбрасываем
n = 0; // Обнуляем число уже введенных цифр
newpin = 0; // Отменяем режим ввода нового кода
dostup = false;
display.clear();
digitalWrite(MIN5V_PIN, LOW); //Выключаем питание на сервопривод
// Далее выключаем оба светодиода... (они включаются в разных случаях, а выключаются через 5 с)
digitalWrite(LEDGREEN_PIN, LOW);
digitalWrite(LEDRED_PIN, LOW);
}
}
else flag = true;
}
//Управление замком
void uprzamkom(bool zamok) {
if (zamok) {
if (newpin==0) Serial.println("Замок закрыт!");
digitalWrite(LEDRED_PIN, HIGH); //Включаем светодиод
digitalWrite(MIN5V_PIN, HIGH); // Включаем питание на сервопривод
display.clear();
display.print(latch_cl);
delay(150); //Задержка, чтоб наприжение успело востановится
myServo.write(latch_cl); //Поварачиваем на нужный угол (подбирается опытным путем, в зависимости от установки сервы)
}
else {
if (newpin == 0) Serial.println("Замок открыт!"); //Аналогично
digitalWrite(LEDGREEN_PIN, HIGH);
digitalWrite(MIN5V_PIN, HIGH);
display.clear();
display.print(latch_op);
delay(150);
myServo.write(latch_op);
}
}
//Озвучка событий
void play(byte r) {
/*
0 - ошибка
1 - успех
2 - настройка сервы
3 - нейтральное предупреждение
*/
if (sound) {
switch (r) {
case 0:
tone(TONE_PIN, 500, 1000);
display.bombTimer(3, 8, 10000, "");
break;
case 1:
tone(TONE_PIN, 700, 150);
delay(300);
tone(TONE_PIN, 700, 150);
delay(300);
tone(TONE_PIN, 780, 75);
delay(150);
tone(TONE_PIN, 700, 75);
delay(150);
tone(TONE_PIN, 625, 225);
delay(300);
tone(TONE_PIN, 590, 75);
delay(150);
tone(TONE_PIN, 520, 75);
delay(150);
tone(TONE_PIN, 460, 225);
delay(300);
tone(TONE_PIN, 350, 225);
delay(600);
break;
case 2:
tone(TONE_PIN, 300, 150);
delay(300);
tone(TONE_PIN, 300, 150);
delay(300);
break;
default:
tone(TONE_PIN, 500, 200);
delay(50);
}
}
}
void disp(char Disp[]) {
display.clear();
for (int i = 0; i