一、简单介绍
本项目基于Arduino开发,支持刷卡(复旦卡)和蓝牙串口密码发送两种方式,支持舵机和继电器(可接电磁锁等)两种开锁方式。详情见代码,代码注释很全的。
文章末尾附源程序、库文件、3D打印外壳模型链接
蓝牙开锁:
- 连接蓝牙
- 打开手机蓝牙串口助手
- 发送密码,初始密码为:‘123456’
- 舵机状态发送第一次开锁,再发送一次闭锁
- 电磁继电器发送一次开锁,5秒后自动关锁
RF522开锁:
????????先将卡片序列号写入程序,方法如下:
- 连接硬件,烧录程序
- 打开串口窗口
- 将卡放在RF522模块识别区
- 串口打印出卡号
- 将16进制卡号写入程序中,方法参考示例
- 将卡片快速放在RF522模块上,然后快速取开,放置时间过长会导致反复开关锁,上方读卡号一样
- 舵机状态放置第一次开锁,再放置一次闭锁
- 电磁继电器放置一次开锁,5秒后自动关锁
支持蓝牙串口改密码:
- 连接蓝牙
- 打开手机蓝牙串口助手
- 发送改密码的高级指令,程序默认:‘1357924680’,不含引号
- 串口返回值后,按指示操作
- 切记,改密码期间,每次输入有效时间为5秒,否则弹出超时警告,然后退出改密码程序。
温馨提示:
- 因为舵机电源线加了电磁继电器,所以空闲状态下舵机是可以转动的,当然可以不接电磁继电器,不影响使用
- 蓝牙和RF522模块可以同时使用,不会冲突
- 每次设备重启后会重置密码
- 未知原因,设备长期通电,RF522模块会失效(可能是休眠了),但蓝牙正常
- 可以修改蓝牙模块的名字和初始连接密码,详见其他相关文章
- 所有密码只支持数字,但不限位数,(不建议太长,容易报错)
需要硬件:
Arduino UNO开发板、RF522读写模块、HC-05蓝牙模块、单路高电平触发继电器、舵机(或单路继电器、电磁锁)。
如果使用大舵机,需要5-9V电源、或两节18650电池(及电池仓)。
二、硬件
接线图见程序
三、程序
/*
本程序实现通过蓝牙串口发送密码和刷卡两种方式实现无接触式开锁,目前支持两种锁,第一种可以通过驱动舵机实现自动开锁,可以用于改装旧门锁,
第二种是使用继电器,可以驱动电磁锁等,适用于进行演示。
该程序目前运行良好,经过检验,但仍有部分小小的bug,比如说长时间运行,RF522模块就会无法使用,复位后便可恢复正常。
程序注释了每隔三分钟自动断开蓝牙的那一部分。
程序默认使用舵机开锁。
舵机旋转角度:180.
建议舵机独立供电,只需共地。
*/
/*******************************************************************************
* 接线定义如下
* 继电器 Arduino
* IN1 2 控制继电器接通舵机电源,高电平有效
* IN2 3 控制继电器断开蓝牙电源,高电平有效
* BT 接蓝牙,蓝牙模块,正常使用
* TDX 4
* RXD 5
*
* OUT 接舵机,用于控制舵机,程序默认使用该方式开锁
* OUT/IN 6
*
* IN 按键开锁,预留通道,暂未使用
* IN 7
*
* OUT 连接继电器,用于控制电磁锁等,程序默认注释
* OUT/IN 8
*
* RFID 接RFID模块
* RST 9
* SDA(SS) 10
* MOSI 11
* MISO 12
* SCK 13
*****************************************************************************/
#include<SoftwareSerial.h> //蓝牙头文件
//#include<MsTimer2.h> //定时器库的头文件
#include<SPI.h> //SPI通信头文件
#include<MFRC522.h> //RFC522模块头文件
#define SS_PIN 10
#define RST_PIN 9
SoftwareSerial BT(4,5); //定义蓝牙口
//unsigned long BTOn=5000,BTOff=180000; //定义蓝牙中断的时间长度,每180秒重置一次
//int BTStatus; //定义蓝牙的状态,HIGH or LOWm
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
byte nuidPICC[4];
String str; //定义密码变量
String str1;
String str2;
String str3;
int servopin=6; //设置舵机驱动脚到数字口6
int myangle; //定义角度变量
int pulsewidth; //定义脉宽变量
int val1; //定义密码储存变量
int val2;
int val3=0;
int val4;
int i;
void servopulse(int servopin,int myangle)//定义一个脉冲函数,用来模拟方式产生PWM值
{
pulsewidth=(myangle*11)+500; //将角度转化为500-2480 的脉宽值
digitalWrite(servopin,HIGH); //将舵机接口电平置高
delayMicroseconds(pulsewidth); //延时脉宽值的微秒数
digitalWrite(servopin,LOW); //将舵机接口电平置低
delay(20-pulsewidth/1000); //延时周期内剩余时间
}
void setup()
{
pinMode(2,OUTPUT); //定义舵机电源电平
digitalWrite(2,LOW);
// pinMode(3,OUTPUT); //定义蓝牙状态
// digitalWrite(3,LOW);
// BTStatus=LOW;
pinMode(8,OUTPUT);
digitalWrite(8,HIGH); //继电器拉高为关,拉低为开
pinMode(servopin,OUTPUT); //设定舵机接口为输出接口
Serial.begin(9600); //设置波特率为9600
SPI.begin(); // Init SPI bus
rfid.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++)
{
key.keyByte[i] = 0xFF;
}
Serial.println(F("This code scan the MIFARE Classsic NUID."));
Serial.print(F("Using the following key:"));
printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
//*************************************************************
str3=123456; //定义初始密码,只能是数字
//**************************************************************
Serial.println("UNO is ready"); //串口打印状态
Serial.println("RFID is ready");
Serial.println("servo=o_seral_simple ready" ) ;
BT.begin(9600); //蓝牙打印状态
BT.println("UNO is ready!");
BT.println("BT is ready!");
BT.println("RFID is ready");
BT.println("servo=o_seral_simple ready" ) ;
}
void loop()
{
//蓝牙部分
if (BT.available()) //判断蓝牙串口是否有字符
{
while (BT.available() > 0)
{
val1 = BT.read(); //将蓝牙串口的数值读取出来
if (isDigit(val1))
{
str += (char)val1;
}
val1 = 0;
delay(2);
}
Serial.println(str);
/*************************
*以下代码为蓝牙密码修改代码
*默认隐藏,激活密码为
*1357924680
*只能是数字
*进入密码修改界面后,请在10秒内输入回答
*否则就会退出密码修改状态
*蓝牙串口打印中文时,会出现乱码情况
************************/
if(str=="1357924680")
{
str="";
Serial.println("The page for changing the Bluetooth password is displayed");
Serial.println("Enter '1' to change the password and '0' to exit");
BT.println("The page for changing the Bluetooth password is displayed");
BT.println("Enter '1' to change the password and '0' to exit");
delay(5000);
val1 = BT.read();
Serial.println(val1);
if (isDigit(val1))
{
str += (char)val1;
}
val1 = 0;
delay(500);
if(str=="1")
{
str="";
str1="";
str2="";
Serial.println("Please enter your password:");
BT.println("Please enter your password:");
delay(5000);
while(BT.available() > 0)
{
val1=BT.read();
if (isDigit(val1))
{
str1 += (char)val1;
}
val1=0;
delay(10);
}
delay(500);
Serial.println(str1);
Serial.println("Please enter your password again:");
BT.println("Please enter your password again:");
delay(5000);
while(BT.available() > 0)
{
val4=BT.read();
if (isDigit(val4))
{
str2 += (char)val4;
}
val4=0;
delay(500);
Serial.println(str2);
}
if(str1==str2)
{
Serial.println("The password is successfully changed. Exit 5 seconds later");
BT.println("The password is successfully changed. Exit 5 seconds later");
str3=str1;
delay(5000);
}
else if(str1!=str2)
{
Serial.println("Password change failed!! Two different passwords!! Quit in 5 seconds!!");
BT.println("Password change failed!! Two different passwords!! Quit in 5 seconds!!");
delay(5000);
}
}
else if(str=="0")
{
Serial.println("You have quit password change!");
BT.println("You have quit password change!");
}
else
{
Serial.println("Timeout, exit password change interface!!");
BT.println("Timeout, exit password change interface!!");
}
}
/************************
*以下为开锁程序
*前部分为继电器程序
*后部分为舵机程序
*使用一个时,请注释另一个程序
************************/
else if(str == str3)
{
/*
//继电器开锁方式,可以接电磁锁
digitalWrite(8,LOW);
Serial.println("已开锁");
BT.println("已开锁");
delay(3000);
digitalWrite(8,HIGH);
Serial.println("已闭锁");
BT.println("已闭锁");
*/
str = "";
//舵机
//舵机程序默认初始位置为开锁状态
if(val3==0)
{
digitalWrite(2,HIGH);
delay(500);
val2=0;
val3=1;
for(i=0;i<=50;i++) //产生PWM个数,等效延时以保证能转到响应角度
{
servopulse(servopin,val2);//模拟产生PWM
}
digitalWrite(2,LOW);
BT.println("Open the door");
}
else if(val3==1)
{
digitalWrite(2,HIGH);
delay(500);
val2=180;
val3=0;
for(i=0;i<=50;i++) //产生PWM个数,等效延时以保证能转到响应角度
{
servopulse(servopin,val2);//模拟产生PWM
}
digitalWrite(2,LOW);
BT.println("close the door");
}
}
else str="";
}
//RFID部分
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! rfid.PICC_IsNewCardPresent())
return;
// Verify if the NUID has been readed
if ( ! rfid.PICC_ReadCardSerial())
return;
Serial.print(F("PICC type: "));
MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
Serial.println(rfid.PICC_GetTypeName(piccType));
// Check is the PICC of Classic MIFARE type
if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("Your tag is not of type MIFARE Classic."));
return;
}
//下面为卡号,目前无法读取加密卡,卡号会从串口打印出来
if (
//下面两行代码中不同的位置即使要修改的卡号‘00’‘FF’
(rfid.uid.uidByte[0] == 0x00 && rfid.uid.uidByte[1] == 0x00 && rfid.uid.uidByte[2] == 0x00 && rfid.uid.uidByte[3] == 0x00)||
(rfid.uid.uidByte[0] == 0xFF && rfid.uid.uidByte[1] == 0xFF && rfid.uid.uidByte[2] == 0xFF && rfid.uid.uidByte[3] == 0xFF)
)
{
Serial.println(F("A card has been detected."));
if(val3==0)
{
digitalWrite(2,HIGH);
delay(500);
val2=0; //舵机旋转角度
val3=1;
for(i=0;i<=50;i++) //产生PWM个数,等效延时以保证能转到响应角度
{
servopulse(servopin,val2);//模拟产生PWM
}
digitalWrite(2,LOW);
BT.println("Open the door");
}
else if(val3==1)
{
digitalWrite(2,HIGH);
delay(500);
val2=180;
val3=0;
for(i=0;i<=50;i++) //产生PWM个数,等效延时以保证能转到响应角度
{
servopulse(servopin,val2);//模拟产生PWM
}
digitalWrite(2,LOW);
BT.println("close the door");
}
}
Serial.println(F("The NUID tag is:"));
Serial.print(F("In hex: "));
printHex(rfid.uid.uidByte, rfid.uid.size);
Serial.println();
Serial.print(F("In dec: "));
printDec(rfid.uid.uidByte, rfid.uid.size);
Serial.println();
/*
//以下为蓝牙自动断开的程序
unsigned long nowtime=millis(); //获取当前的系统运行时间长度
if(BTStatus==LOW) //如果当前蓝牙状态为AT,则执行该程序
{
if(nowtime>BTOn) //检测系统运行时间长度是否到
{
BTOn=nowtime; //记录当前时间长度,第一次为500ms,赋值给ledOn
BTOff=nowtime+5000; //计算出下一次led灯变化的时刻,第一次运行程序时应该在1000ms时关灯
digitalWrite(3,HIGH); //关掉蓝牙AT模式
BTStatus=HIGH; //记录当前led灯状态,下一次使用
}
}
else{
if(nowtime>BTOff)
{
BTOff=nowtime;
BTOn=nowtime+180000;
digitalWrite(3,LOW);
BTStatus=LOW;
}
}
*/
}
//读卡程序,勿动
void printHex(byte *buffer, byte bufferSize)
{
for (byte i = 0; i < bufferSize; i++)
{
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
void printDec(byte *buffer, byte bufferSize)
{
for (byte i = 0; i < bufferSize; i++)
{
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], DEC);
}
}
如有问题请留言,看到后必会答复。
附源程序、库文件、3D打印外壳模型
基于Arduino的智能无接触式门禁系统-嵌入式文档类资源-CSDN文库https://download.csdn.net/download/m0_56219648/77514315
|