Здравствуйте!
Эта статья является инструкцией, для изготовления самодельного менеджера паролей. В который можно загружать до 25 аккаунтов. Для безопасности данных пришлось добавить четырехзначный пароль, для доступа к списку аккаунтов, а также двухступенчатый таймер, на тот случай если будет введен неверный пароль.
Для проекта использую:
Плату Arduino Pro Micro, на базе микроконтроллера ATmega32U4, OLED I2C дисплей 128х32 пикселя, макетная плата, и 3 кнопки.
Я собирал по этой схеме.
После чего необходимо загрузить этот скетч на плату, предварительно настроив его, как показано в видео инструкции, которая расположена ниже под скетчем.
//Начало скетча
#include <Keyboard.h>
#include "EEPROM.h"
#include <Adafruit_SSD1306.h>
#define SSD1306_DISPLAYOFF 0xAE
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int pas_1 = 2; // 1 цифра пароля (от 0 до 9)
const int pas_2 = 9; // 2 цифра пароля (от 0 до 9)
const int pas_3 = 7; // 3 цифра пароля (от 0 до 9)
const int pas_4 = 1; // 4 цифра пароля (от 0 до 9)
const int pin_OK = 6; //пин кнопки подтверждения
const int pin_UP = 7; //пин кнопки вверх
const int pin_DOWN = 8; //пин кнопки вниз
int max_account_number = 25; //количество используемых аккаунтов, должно быть меньше или равно 25
typedef struct { //эта функция делит массив на столбцы
//сайт______имя польз______логин_________пароль
char* site; char* name; char* login; char* password;} State;
State arr[25] = {
//сайт, имя польз, логин, пароль
{"site 1", "name 1", "login 1", "password 1"},
{"site 2", "name 2", "login 2", "password 2"},
{"site 3", "name 3", "login 3", "password 3"},
{"site 4", "name 4", "login 4", "password 4"},
{"site 5", "name 5", "login 5", "password 5"},
{"site 6", "name 6", "login 6", "password 6"},
{"site 7", "name 7", "login 7", "password 7"},
{"site 8", "name 8", "login 8", "password 8"},
{"site 9", "name 9", "login 9", "password 9"},
{"site 10", "name 10", "login 10", "password 10"},
{"site 11", "name 11", "login 11", "password 11"},
{"site 12", "name 12", "login 12", "password 12"},
{"site 13", "name 13", "login 13", "password 13"},
{"site 14", "name 14", "login 14", "password 14"},
{"site 15", "name 15", "login 15", "password 15"},
{"site 16", "name 16", "login 16", "password 16"},
{"site 17", "name 17", "login 17", "password 17"},
{"site 18", "name 18", "login 18", "password 18"},
{"site 19", "name 19", "login 19", "password 19"},
{"site 20", "name 20", "login 20", "password 20"},
{"site 21", "name 21", "login 21", "password 21"},
{"site 22", "name 22", "login 22", "password 22"},
{"site 23", "name 23", "login 23", "password 23"},
{"site 24", "name 24", "login 24", "password 24"},
{"site 25", "name 25", "login 25", "password 25"}
};
int pas_ST_1 = 0, pas_ST_2 = 0, pas_ST_3 = 0, pas_ST_4 = 0, flag_menu = 60, flag_RES_DISP = 0, msecs = 300;
int pin_OK_st = 0, pin_UP_st = 0, pin_DOWN_st = 0, account_number = 0, flag_RES_ACC = 0, timer = 0;
int address_FLAG = 1, flag_EEPROM = 125, seconds = 0;
int seconds1 = 10, seconds2 = 20;
void pass_menu(){ //функция для меню ввода пароля, вывод на дисплей
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,8);
display.print(F("Pass:"));
display.setCursor(60,8);
display.print(pas_ST_1, DEC);
display.setCursor(73,8);
display.print(pas_ST_2, DEC);
display.setCursor(86,8);
display.print(pas_ST_3, DEC);
display.setCursor(99,8);
display.print(pas_ST_4, DEC);
display.setCursor(flag_menu,26);
display.print(F("^"));
}
void scan_buttons(){ //функция сканирование кнопок
pin_OK_st = digitalRead(pin_OK);
pin_UP_st = digitalRead(pin_UP);
pin_DOWN_st = digitalRead(pin_DOWN);
}
void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // I2C address 128x32 0x3C,
for(;;);
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
pinMode(pin_OK, INPUT_PULLUP);
pinMode(pin_UP, INPUT_PULLUP);
pinMode(pin_DOWN, INPUT_PULLUP);
pass_menu ();
EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
if(flag_EEPROM < 10){
EEPROM.put(address_FLAG, flag_EEPROM); //запись в EEPROM
}
EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
if(flag_EEPROM == 126){
flag_menu = 126; seconds = seconds2; }//если флаг = 6, то сначала выводится таймер
}
void loop() {
scan_buttons(); //сканирование кнопок
//обновление дисплея при изменении значения пароля
if(flag_RES_DISP == 1){ pass_menu(); flag_RES_DISP = 0;}
if(pin_OK_st == LOW && (flag_menu >= 59 && flag_menu < 100)){ //переход к следующему числу пароля
flag_menu+=13; if(flag_menu < 100){ flag_RES_DISP = 1;} delay(msecs);}
if(flag_menu == 60){ //выбор 1 числа пароля
if(pin_UP_st == LOW){ pas_ST_1++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == LOW){ pas_ST_1--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_1 > 9){ pas_ST_1 = 0;} if(pas_ST_1 < 0){ pas_ST_1 = 9;}
}
if(flag_menu == 73){ //выбор 2 числа пароля
if(pin_UP_st == LOW){ pas_ST_2++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == LOW){ pas_ST_2--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_2 > 9){ pas_ST_2 = 0;} if(pas_ST_2 < 0){ pas_ST_2 = 9;}
}
if(flag_menu == 86){ //выбор 3 числа пароля
if(pin_UP_st == LOW){ pas_ST_3++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == LOW){ pas_ST_3--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_3 > 9){ pas_ST_3 = 0;} if(pas_ST_3 < 0){ pas_ST_3 = 9;}
}
if(flag_menu == 99){ //выбор 4 числа пароля
if(pin_UP_st == LOW){ pas_ST_4++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == LOW){ pas_ST_4--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_4 > 9){ pas_ST_4 = 0;} if(pas_ST_4 < 0){ pas_ST_4 = 9;}
}
if(flag_menu == 112 && pin_OK_st == LOW){ //подтверждение пароля
if(pas_ST_1 == pas_1 && pas_ST_2 == pas_2 && pas_ST_3 == pas_3 && pas_ST_4 == pas_4){
flag_menu = 125; flag_RES_ACC = 1; delay(msecs);
flag_EEPROM = 125; EEPROM.put(address_FLAG, flag_EEPROM); //восстановление флага
}else{
if(flag_EEPROM == 126){ flag_menu = 126; seconds = seconds2; } //если 2 попытка не верна
if(flag_EEPROM == 125){ flag_menu = 126; seconds = seconds1; //если 1 попытка не верна
flag_EEPROM = 126; EEPROM.put(address_FLAG, flag_EEPROM);} //изменяем флаг для второй неверной попытки
}
}
scan_buttons(); //сканирование кнопок
if(flag_menu == 125){ //выбор сайта и акаунта
if(pin_UP_st == LOW){ account_number-=1; flag_RES_ACC = 1; delay(msecs);}
if(pin_DOWN_st == LOW){ account_number+=1; flag_RES_ACC = 1; delay(msecs);}
if(account_number > max_account_number - 1){ account_number = 0;}
if(account_number < 0){ account_number = max_account_number - 1;}
}
if(flag_menu == 125 && pin_OK_st == LOW){ //печать логина и пароля
delay(msecs);
Keyboard.print(arr[account_number].login);
Keyboard.write(KEY_TAB);
Keyboard.println(arr[account_number].password);
}
if(flag_menu == 125 && flag_RES_ACC == 1){ //отображение сайта и акаунта на дисплее
display.clearDisplay();
display.setCursor(0,0);
display.print(arr[account_number].site);
display.setCursor(0,18);
display.print(arr[account_number].name);
flag_RES_ACC = 0;
}
if(flag_menu == 126){ timer = seconds; //отображение таймера на дисплее, после ввода неверного пароля
while(timer > 0){
display.clearDisplay();
display.setTextSize(2);
display.setCursor(5,0);
display.print(timer, DEC);
display.setCursor(5,18);
display.print(F("seconds"));
display.display();
delay(1000); timer--;
}
flag_menu = 60; flag_RES_DISP = 1; display.clearDisplay();
pas_ST_1 = 0; pas_ST_2 = 0; pas_ST_3 = 0; pas_ST_4 = 0;
} display.display();
}
//Конец скетча
Это скетч, который получился в результате проектирования в симуляторе Arduino UnoArduSim. Можете им воспользоваться, если есть желание протестировать, как это работает в UnoArduSim. О том как это происходило можете посмотреть в видео, которое выше!
//Начало скетча
#include "EEPROM.h"
#include "Adafruit_LiquidCrystal.h"
Adafruit_LiquidCrystal lcd(0);
const int pas_1 = 0; // 1 цифра пароля (от 0 до 9)
const int pas_2 = 0; // 2 цифра пароля (от 0 до 9)
const int pas_3 = 0; // 3 цифра пароля (от 0 до 9)
const int pas_4 = 0; // 4 цифра пароля (от 0 до 9)
const int pin_OK = 2; //пин кнопки подтверждения
const int pin_UP = 3; //пин кнопки вверх
const int pin_DOWN = 4; //пин кнопки вниз
int max_account_number = 10; //количество используемых аккаунтов, должно быть меньше или равно 10
typedef struct { //эта функция делит массив на стобцы
//сайт______имя польз______логин_________пароль
char* site; char* name; char* login; char* password;} State;
State arr[10] = {
//сайт, имя польз, логин, пароль
{"site 1", "name 1", "login 1", "password 1"},
{"site 2", "name 2", "login 2", "password 2"},
{"site 3", "name 3", "login 3", "password 3"},
{"site 4", "name 4", "login 4", "password 4"},
{"site 5", "name 5", "login 5", "password 5"},
{"site 6", "name 6", "login 6", "password 6"},
{"site 7", "name 7", "login 7", "password 7"},
{"site 8", "name 8", "login 8", "password 8"},
{"site 9", "name 9", "login 9", "password 9"},
{"site 10", "name 10", "login 10", "password 10"}
};
int pas_ST_1 = 0, pas_ST_2 = 0, pas_ST_3 = 0, pas_ST_4 = 0, flag_menu = 0, flag_RES_DISP = 0, msecs = 300;
int pin_OK_st = 0, pin_UP_st = 0, pin_DOWN_st = 0, account_number = 0, flag_RES_ACC = 0, timer = 0;
int address_FLAG = 1, flag_EEPROM = 5, seconds = 0;
int seconds1 = 5, seconds2 = 10;
void pass_menu(){ //функция для меню ввода пароля, вывод на дисплей
lcd.setCursor(0,0);
lcd.print("Pass:");
lcd.setCursor(6,0);
lcd.print(pas_ST_1);
lcd.setCursor(7,0);
lcd.print(pas_ST_2);
lcd.setCursor(8,0);
lcd.print(pas_ST_3);
lcd.setCursor(9,0);
lcd.print(pas_ST_4);
lcd.setCursor(5 + flag_menu,1);
lcd.print(" ^");
}
void scan_buttons(){ //функция сканирование кнопок
pin_OK_st = digitalRead(pin_OK);
pin_UP_st = digitalRead(pin_UP);
pin_DOWN_st = digitalRead(pin_DOWN);
}
void setup() {
lcd.begin(20, 4);
lcd.setBacklight(HIGH);
Serial.begin(9600);
pinMode(pin_OK, INPUT_PULLUP);
pinMode(pin_UP, INPUT_PULLUP);
pinMode(pin_DOWN, INPUT_PULLUP);
pass_menu ();
EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
if(flag_EEPROM < 2){
EEPROM.put(address_FLAG, flag_EEPROM); //запись в EEPROM
}
EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
if(flag_EEPROM == 6){
flag_menu = 6; seconds = seconds2; }//если флаг = 6, то сначала выводится таймер
}
void loop() {
scan_buttons(); //сканирование кнопок
//обновление дисплея при изменении значения пароля
if(flag_RES_DISP == 1){ pass_menu(); flag_RES_DISP = 0;}
if(pin_OK_st == HIGH && (flag_menu >= 0 && flag_menu < 4)){ //переход к следующему числу пароля
flag_menu++; if(flag_menu < 4){ flag_RES_DISP = 1;} delay(msecs);}
if(flag_menu == 0){ //выбор 1 числа пароля
if(pin_UP_st == HIGH){ pas_ST_1++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == HIGH){ pas_ST_1--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_1 > 9){ pas_ST_1 = 0;} if(pas_ST_1 < 0){ pas_ST_1 = 9;}
}
if(flag_menu == 1){ //выбор 2 числа пароля
if(pin_UP_st == HIGH){ pas_ST_2++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == HIGH){ pas_ST_2--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_2 > 9){ pas_ST_2 = 0;} if(pas_ST_2 < 0){ pas_ST_2 = 9;}
}
if(flag_menu == 2){ //выбор 3 числа пароля
if(pin_UP_st == HIGH){ pas_ST_3++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == HIGH){ pas_ST_3--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_3 > 9){ pas_ST_3 = 0;} if(pas_ST_3 < 0){ pas_ST_3 = 9;}
}
if(flag_menu == 3){ //выбор 4 числа пароля
if(pin_UP_st == HIGH){ pas_ST_4++; flag_RES_DISP = 1; delay(msecs);}
if(pin_DOWN_st == HIGH){ pas_ST_4--; flag_RES_DISP = 1; delay(msecs);}
if(pas_ST_4 > 9){ pas_ST_4 = 0;} if(pas_ST_4 < 0){ pas_ST_4 = 9;}
}
if(flag_menu == 4 && pin_OK_st == HIGH){ //подтверждение пароля
if(pas_ST_1 == pas_1 && pas_ST_2 == pas_2 && pas_ST_3 == pas_3 && pas_ST_4 == pas_4){
flag_menu = 5; flag_RES_ACC = 1; delay(msecs);
flag_EEPROM = 5; EEPROM.put(address_FLAG, flag_EEPROM); //востановление флага
}else{
if(flag_EEPROM == 6){ flag_menu = 6; seconds = seconds2; } //если 2 попытка не верна
if(flag_EEPROM == 5){ flag_menu = 6; seconds = seconds1; //если 1 попытка не верна
flag_EEPROM = 6; EEPROM.put(address_FLAG, flag_EEPROM);} //изменяем флаг для второй неверной попытки
}
}
scan_buttons(); //сканирование кнопок
if(flag_menu == 5){ //выбор сайта и акаунта
if(pin_UP_st == HIGH){ account_number-=1; flag_RES_ACC = 1; delay(msecs);}
if(pin_DOWN_st == HIGH){ account_number+=1; flag_RES_ACC = 1; delay(msecs);}
if(account_number > max_account_number - 1){ account_number = 0;}
if(account_number < 0){ account_number = max_account_number - 1;}
}
if(flag_menu == 5 && pin_OK_st == HIGH){ //печать логина и пароля
delay(msecs);
Serial.print(arr[account_number].login);
Serial.print(" Tab ");
Serial.println(arr[account_number].password);
}
if(flag_menu == 5 && flag_RES_ACC == 1){ //отображение сайта и акаунта на дисплее
lcd.clear();
lcd.setCursor(0,0);
lcd.print(arr[account_number].site);
lcd.setCursor(0,1);
lcd.print(arr[account_number].name);
flag_RES_ACC = 0;
}
if(flag_menu == 6){ timer = seconds; //отображение таймера на дисплее, после ввода неверного пароля
while(timer > 0){
lcd.clear();
lcd.setCursor(0,0);
lcd.print(timer); lcd.print(" seconds");
delay(1000); timer--;
}
flag_menu = 0; flag_RES_DISP = 1; lcd.clear();
pas_ST_1 = 0; pas_ST_2 = 0; pas_ST_3 = 0; pas_ST_4 = 0;
}
}
//Конец скетча