原创内容----转载请说明。
材料(只是主要的):
名称 | 个数 |
Arduino UNO | 1 |
LCD1602A--IIC(要带IIC转接板) | 1 |
矩形按键3*4 (也可以自制) | 1 |
继电器模块 (也可以自制 Q8550+IN4148) | 1 |
任意V电磁锁 | 1 |
5mm或3mm led | 2 |
杜邦线 | n |
接口定义
名称 | 接口 单片机 硬件 |
备注 |
蓝牙 | 10<------RX 11------->TX VCC---+5V GND----GND |
SoftwareSerial.h 原0(RX)口无法正常通讯 |
LCD1602AIIC | SDA---SDA SCL---SCL VCC---+5V GND---GND |
void |
矩形按键3*4 | 2, 3, 4, 5 //行 6, 7, 8 //列 |
void |
达成启动 (继电器) |
9 | |
警告led | 12 | 密码输入错误 |
错误led | 13 | 严重错误(可省略) |
Passwordlock.h | 自定义 |
Keypad.h | 标 |
Wire.h | 标 |
LiquidCrystal_I2C.h | 标 |
SoftwareSerial.h | 标 |
使用的是多文件编写,主要使用的是C(不包括库文件{头文件}),现在只是写完,但为完善
例如:
下次添加(可选):
1.开门一直不关检测 2.NFC开门(刷卡) 3.WLAN(无线,互联网,远程)开门
4.可找回密码(需要USB连入电脑/手机)并且要管理员密码.....
想办法进行断电保存...
说明:
接键输入密码开门,可以改密码,并且可以删除输入(#键);
蓝牙输入密码开门,可以改密码。
互不冲突(不同密码)也可以同密码需改下。
蓝牙连接上可提示。
有任何问题会亮灯并在usb波特9800报错。
不多说了上代码:
Passwordlock.ino
#include"Passwordlock.h"
SoftwareSerial BT(10,11); //10-RX 11-TX
bool GetKey_Value(); //获取键盘值
void Failure_function(); //失效函数
void Strand_door(); //串口
char Serial_port();//串口接收到信息 并返回
void Serial_PortManagement(); //串口管理
const byte ROWS = 4; //行
const byte COLS = 3; //列
//按键接口定义
byte rowePins[ROWS] = {2, 3, 4, 5}; //行
byte colPins[COLS] = {6, 7, 8}; //列
//辅助脚位定义
byte reach = 9; //达成启动-脚位
byte led_reachErrors = 12; //警告-脚位
byte led_errors = 13; //错误-脚位
short reac_time = 3000; //达成启动-时间
//定义矩形按键,键位值
char Keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
//用户密码-用于保存
char User_Password[Password_Max] = {'1', '2', '3', '4', '5'};
//用户串口密码-用于保存
char BT_Password[Password_Max] = {'1', '2', '3', '4', '5'};
//用户串口临时密码
char BT_UserPd[Password_Max];
//设置LCD1602设备地址,具体看模块手册
LiquidCrystal_I2C lcd(0x27, 16, 2);
//设置矩形键盘
Keypad keypad = Keypad(makeKeymap(Keys), rowePins, colPins, ROWS, COLS);
void setup() //在main ()中调用
{
pinMode(led_errors, OUTPUT);
pinMode(led_reachErrors, OUTPUT);
pinMode(reach, OUTPUT); //达成
Serial.begin(9600);
BT.begin(38400);
lcd.init(); // 初始化LCD
lcd.backlight(); //设置LCD背景等亮
digitalWrite(reach, HIGH); //关闭继电器
digitalWrite(led_errors, LOW);
}
int ergodic = 10; //遍历
char auxiliary; //辅助键使用(决定程序走向)
char Temporary_password[Password_Max]; //临时密码 用于比较
void loop() //在main ()中for( ; ; ;)调用
{
//analogRead(Bluetooth);
init_errors: //goto
/****************************/
//只让执行一遍,否则重复打印
if (ergodic == 10)
{
lcd.clear(); // 清屏
lcd.setCursor(0, 0); //设置显示指针
lcd.print("QWQ-Welcome-QAQ");
lcd.setCursor(0, 1);
lcd.print("'#'Key InPassword");
//初始化-临时密码
if ((change_init_password(Temporary_password)))
{
Serial.println("[state]:init_password:ok");
}
else
{ //初始化失败
Serial.println("[error]:init_password:on");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Press the '*' key");
lcd.setCursor(0, 1);
lcd.print("[error]:init...");
Failure_function();
ergodic = 10;
goto init_errors;
}
BT.println("Enter the password in '3S'");
BT.println("____________________________");
BT.println("Please enter a selection:");
BT.println(">'1'-Open the door");
BT.println(">'2'-Change password");
} //只让执行一遍,否则重复打印
/****************************/
ergodic = 0;
//串口开门
while (BT.available())
{
Strand_door();
ergodic = 10;
delay(2500);
}
auxiliary = keypad.getKey();
if ((auxiliary != NO_KEY) && auxiliary == '#')
{ //开始
Serial.println("Start InPassword");
delay(20);
Cancel_pd:
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("#Key in password"); //输入密码
lcd.setCursor(0, 1);
lcd.print("*Key change password"); //改密码
Serial.println("[state]:Input password");
while (1)
{
auxiliary = keypad.getKey();
if ((auxiliary != NO_KEY) && auxiliary == '*' || auxiliary == '#')
{
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
/****************'*'*************************/
if (auxiliary == '*')
{
lcd.print("In Original pd:"); //输入密码
if (GetKey_Value())
if ((Password_Comparison(Temporary_password, User_Password)))
{ //相等
Serial.println("[state]:change password..");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("New password:"); //新密码
if (GetKey_Value())
{ //获取密钥值
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Original password:YES"); //改密码
delay(1900);
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("* Key Determine"); //确定改密码
lcd.setCursor(0, 1);
lcd.print("# Key Cancel"); //改密码
Serial.println("Original password:YES");
while (1)
{
auxiliary = keypad.getKey();
if ((auxiliary != NO_KEY) && auxiliary == '*' || auxiliary == '#')
{
if (auxiliary == '*')
{
//密码更改 临时密码,用户密码
if (Password_Change(Temporary_password, User_Password))
{ //密码更改 成功
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Pd Ce success!");
delay(1000);
Serial.println("|change password:success!|");
goto Cancel_pdok;
}//密码更改 失败
else
{
Serial.println("[error]:Acquisition failed");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Press the '*' key");
lcd.setCursor(0, 1);
lcd.print("[error]:Acquisition failed");
Failure_function();
}//else
}//if*
else
goto Cancel_pd;
}//if if(* #)
}//while...while
}//IF获取密钥值
else
{ //获取密钥值失败
Serial.println("[error]:Acquisition failed");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Press the '*' key");
lcd.setCursor(0, 1);
lcd.print("[error]:Acquisition failed");
continue;
}//获取密钥值失败
}//if相等
else
{
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("OlPassword error"); //输入密码
Serial.println("OriginalPassword error");
continue;
}
}//if *
else if (auxiliary == '#')
{
/****************'##########'*********/
lcd.print("In password:");
Serial.println("[state]:In_password");
if (GetKey_Value())
break;
else
{
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("#Key in password"); //输入密码
lcd.setCursor(0, 1);
lcd.print("*Key change password"); //改密码
Serial.println("[state]:Input password");
continue;
}
}
}
delay(50);
//串口开门
while (BT.available())
{
Strand_door();
ergodic = 10;
delay(2000);
}
}//while
Cancel_pdok:
//密码比较 临时,用户
if ((Password_Comparison(Temporary_password, User_Password)))
{ //相等
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Unlocked");
Serial.println("[state]:Password equality");
digitalWrite(reach, LOW);
delay(reac_time);
digitalWrite(reach, HIGH);
}
else
{
Serial.println("Passwords are not equal");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("[warning]:");
lcd.setCursor(0, 1);
lcd.print("NOPassword");
digitalWrite(led_reachErrors, HIGH);
delay(3000);
digitalWrite(led_reachErrors, LOW);
//密码比较 临时,用户
}//else
ergodic = 10; //
}//if 进入条件
}//loop();
/********************************/
bool GetKey_Value()
{
while (1)
{
//获得按键值
for (ergodic = 0; ergodic < Password_Max;)
{
Temporary_password[ergodic] = keypad.getKey();
//检查获得
if ((Temporary_password[ergodic] != NO_KEY) && Temporary_password[ergodic] != '#')
{
if (Temporary_password[ergodic] == '*')
{
ergodic = 10;
delay(20);
return true;
}
lcd.setCursor(ergodic, 1);
lcd.print("*");
ergodic++;
}
else if (Temporary_password[ergodic] == '#')
{
Temporary_password[ergodic--] = NO_KEY;
Temporary_password[ergodic] = NO_KEY;
lcd.setCursor(ergodic, 1);
lcd.print(' ');
}
}//FOR
if (ergodic == Password_Max)
return true;
else
{ //获取失败
Serial.println("[error]:Acquisition failed");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Press the '*' key");
lcd.setCursor(0, 1);
lcd.print("[error]:Acquisition failed");
Failure_function();
//获取失败
return false;
}//else
}//while
}//GetKey_Value
//失败 函数
void Failure_function()
{
while (1)
{
char nopd;
digitalWrite(led_errors, HIGH);
delay(300);
digitalWrite(led_errors, LOW);
nopd = keypad.getKey();
if (nopd != NO_KEY && nopd == Keys[3][0])
{
lcd.clear(); // 清屏
delay(10);
break;
}
}//while
}
void Serial_PortManagement() //串口管理
{
}
//串口开门
void Strand_door()
{
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Serial input.....");
BT_UserPd[0] = Serial_port(); //获取 1-开门 2-改密码
if (BT_UserPd[0] == '1') //1-开门
{
while (BT.available())
{ // 当串口还有信息后
BT.read();
}//主要清空缓冲区
//请输入密码
BT.println("Please input a password:");
delay(3500); //3.5s等待用户输入
//获取
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT_UserPd[ergodic] = Serial_port();
delay(5);
while (BT.available())
{ // 当串口还有信息后
BT.read();
}//主要清空缓冲区
//比较
if((Password_Comparison(BT_UserPd,BT_Password)))
{
BT.println("The password is correct!");
//相等
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("Unlocked");
BT.println("[state]:Password equality");
digitalWrite(reach, LOW);
delay(reac_time);
digitalWrite(reach, HIGH);
}
else
{
BT.println("Password error!");
BT.println("Passwords are not equal");
lcd.clear(); // 清屏
lcd.setCursor(0, 0);
lcd.print("[warning]:");
lcd.setCursor(0, 1);
lcd.print("NOPassword");
digitalWrite(led_reachErrors, HIGH);
delay(3000);
digitalWrite(led_reachErrors, LOW);
}
/****************************************/
}
else if (BT_UserPd[0] == '2') /******2-改密码****/
{
/****************************************/
while (BT.available())
{ // 当串口还有后
BT.read();
}//主要清空缓冲区
BT.println("Enter the original password:");
delay(3500);//3.5s等待用户输入
//获取
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT_UserPd[ergodic] = Serial_port();
delay(5);
while (BT.available())
{
BT.read();
}//主要清空缓冲区
//比较
if((Password_Comparison(BT_UserPd,BT_Password)))
{
BT.println("The password is correct!");
BT.println("Enter new password:");
delay(3500);//3.5s等待用户输入
//获取
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT_UserPd[ergodic] = Serial_port();
//替换
if((Password_Change(BT_UserPd,BT_Password)))
{
BT.println("Saved,New password:");
//打印提示
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT.print(BT_Password[ergodic]);
BT.print("\n");
}
else
{
//保存失败
BT.println("Saved failed");
BT.println("Password is:");
delay(5);
//保存失败-给与1-n(n<=Password_Max)
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT_Password[ergodic] = (char)(ergodic+1);
//打印提示
for (ergodic = 0; ergodic < Password_Max; ergodic++)
BT.print(BT_Password[ergodic]);
BT.print("\n");
}
delay(5);
while (BT.available())
{ //主要清空缓冲区
BT.read();
}
//可以优化处: 防止远程改了密码
return false;
}
else
{
BT.println("Password error!");
return false;
}
}
while (BT.available())
{ //主要清空缓冲区
BT.read();
}
//对Arduino的缓存区有心理阴影
lcd.clear(); // 清屏
}
//串口接收到信息 并返回
char Serial_port()
{
char serialData;
//等待缓冲区拿到值
delay(10);
if (BT.available())
{ // 当串口接收到信息后
serialData = BT.read();
}
return serialData;
}
Otherfunctions.cpp:
#include"Passwordlock.h"
//改变初始化_临时密码
bool change_init_password(char *init_password)
{
int temporary;
char increas='A';
for(temporary=0;temporary<Password_Max;temporary++)
{
*(init_password+temporary)=increas++; //非语法糖
}
if(temporary)
return true;
else
return false;
}
//密码比较 临时密码,用户密码 strcmp();
bool Password_Comparison(const char *Temporary_pd,const char *User_Pd)
{
int temporary,db=1;
for(temporary=0;temporary<Password_Max;temporary++)
{
db*=((User_Pd[temporary])==(Temporary_pd[temporary]));
}
if(db)
return true;
else
return false;
}
//密码更改 临时密码,用户密码
bool Password_Change (char *Temporary_pd ,char *use_pdn)
{
if(Password_Comparison(Temporary_pd,use_pdn))
return true;
int temporary ;
for(temporary=0;temporary<Password_Max;temporary++)
{
use_pdn[temporary]=Temporary_pd[temporary];
}
if(Password_Comparison(Temporary_pd,use_pdn))
return true;
else
{
for(temporary=0;temporary<Password_Max;temporary++)
{
use_pdn[temporary]=temporary;
}
return false;
}
}
Passwordlock.h:
#include<Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h> //引用I2C库
#include <SoftwareSerial.h>
#define Password_Max 5 //密码长度
//#define Serial_PORTPassworD "8210"
//#define PC_PASSWORD 8210
//改变初始化_临时密码
bool change_init_password(char *);
//密码比较 临时密码,用户密码 strcmp();
bool Password_Comparison(const char *,const char *);
//密码更改 临时密码,用户密码
bool Password_Change(char *,char *);
本人是自学(而且专业还不是这方面QAQ).原创内容--转载请务必说明!!
说实话还挺简单的,就是蓝牙RX(0)通讯耗了时间,还有Arduino IDE 真的不好用,个人.用的是vscode.
后续会发Windows cmd下贪吃蛇,连点器,俄罗斯方块……
个人邮箱:Starry_night_mc@outlook.com
有BUG反馈.
原创内容--转载请务必说明!