实验六:RFID刷卡开锁实验
一、实验目的
通过ML-RC522读取S50IC卡的用户身份证明信息使用SPI通信协议传送给ESP32,ESP32接受到信息后与自身设定的可用的用户身份证明信息进行对比,并显示是否验证通过。
二、实验内容
1.连接ESP32和ML-RC522的引脚
2.将程序上传到ESP32
3.使用ML-RC522读取标签卡片用户身份证明并打印验证信息
4.若验证通过,驱动电机
三、实验设备
ML-RC522 RFID模块
S50 异性IC卡
ESP32开发板
SG90舵机
杜邦线
四、实验步骤
1)连接引脚
RC522:
RC522的引脚:
引脚依次为:SDA SCK MOSI MISO SCL GND RST 3.3V
ESP32:
ESP32的引脚图:
连接:
将RC522与ESP32上对应的引脚连接:
2)上传程序
程序中需要MFRC522的库,在arduino上方工具->管理库中搜索MFRC522下载库
#include <dummy.h>
#include <Servo.h>
#include <BLEDevice.h>
#include <BLE2902.h>
#include <String.h>
#include <Keypad.h>
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 21 //定义RC522的SDA引脚的接线位置
#define RST_PIN 22 //定义RC522的RST引脚的接线位置
#define SERVO_PIN 15
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define openInterval 5000
/*
* 按键
*/
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {33, 27, 14, 12}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 0, 2}; //connect to the column pinouts of the keypad
/*
* RFID
*/
struct RFIDTag { //Tag标签结构体
uint8_t uid[4];
char *name;
};
MFRC522 rfid(SS_PIN, RST_PIN); //实例化类
struct RFIDTag tags[20] = { // 初始化结构资料,请自行修改RFID识别码
{{233, 232, 210, 126}, "Mini_Tag"},
{{0, 0, 0, 0}, "Mini_Tag1"},
{{1, 1, 1, 1}, "Mini_Tag2"},
};
byte totalTags = sizeof(tags) / sizeof(RFIDTag); //计算结构资料的数量
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
byte ble_rx_buffer[20]; //接收蓝牙指令
byte verfi_code[6] = {0x31,0x32,0x33,0x34,0x35,0x36};//初始密码
byte init_pw[6] = {1,2,3,4,5,6};//初始按键密码
Servo myservo;
int pos=0;
bool toggle; //开锁判断位
void locker(bool toggle) { //开锁
myservo.attach(SERVO_PIN);
if (toggle) {
myservo.write(90); // 开锁
} else {
myservo.write(0); // 关锁
}
delay(500); // 等马达转到定位
myservo.detach();
}
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
//55aa1000313233343536 蓝牙发送开门指令,hex 16进制发送
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
byte op;
for (int i = 0; i < rxValue.length(); i++){
ble_rx_buffer[i] = rxValue[i];
Serial.print(rxValue[i]);
}
if(ble_rx_buffer[0] == 0x55 && ble_rx_buffer[1] == 0xaa){
op=ble_rx_buffer[2];
switch(op){
case 0x10:{ //蓝牙开门
if(memcmp(ble_rx_buffer+4,verfi_code,6) == 0){ //匹配成功
toggle = true;
Serial.println("开门成功");
}
else{
Serial.println("密码错误");
}
break;
}
case 0x20:{ //设置密码
break;
}
case 0x30:{ //查看指纹
break;
}
case 0x31:{//添加指纹
break;
}
case 0x32:{ //删除指纹
break;
}
}
//locker(toggle);
}
}
};
/*配置蓝牙
* 参数:BLEName 蓝牙名字
*/
void setupBLE(String BLEName){
const char *ble_name = BLEName.c_str();
BLEDevice::init(ble_name);
BLEServer *pServer = BLEDevice::createServer(); //创建服务
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); //添加描述
BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
pCharacteristic->setCallbacks(new MyCallbacks()); //receive message callback
pService->start();// Start the service
pServer->getAdvertising()->start();// Start advertising
Serial.println("Waiting a client connection to notify...");
}
/*按键输入的匹配函数
* 参数:key为一次按键输入的值
*/
bool compare_pw(char key){
static byte pw[20];
static byte keys_len = 0;
bool pw_flag = false; //匹配密码的标志位
if(key){
Serial.println(key);
switch(key){
case '#':{ //确认键
if(keys_len == 6 && memcmp(pw,init_pw,6)==0){ //匹配成功,开锁
Serial.println("开门成功");
pw_flag = true;
}
else{
Serial.println("密码错误");
}
keys_len=0; //清零
break;
}
case '*':{ //回退键
if(keys_len >0)
keys_len--;
break;
}
default:{ //默认数字键0-9
pw[keys_len++]=key-'0';
if(keys_len>19){
Serial.println("OverSize");
keys_len=0;
}
break;
}
}
}
return pw_flag;
}
void printDec(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++){
//Serial.print(buffer[i] < 0x10 ? " 0" : "");
Serial.print(buffer[i]);
Serial.print(" ");
}
}
/*
* RFID匹配函数
* 参数:card_num为卡片资料的总数
*/
bool Match_Card(byte card_num){
bool foundTag = false; //是否找到记录中的标签,初始是false
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { //寻找新卡
byte *id = rfid.uid.uidByte; // 取得卡片的UID
byte idSize = rfid.uid.size; // 取得UID的长度
Serial.print("十进制UID:");
printDec(rfid.uid.uidByte, rfid.uid.size);
Serial.println();
for (byte i = 0; i < card_num; i++) {
if (memcmp(tags[i].uid, id, idSize) == 0) { // 比对阵列资料值
Serial.println(tags[i].name); //显示标签名字
foundTag = true;
break;
}
if(i==card_num-1){
Serial.println("验证失败");
}
}
// 使放置在读卡区的IC卡进入休眠状态,不再重复读卡
rfid.PICC_HaltA();
// 停止读卡模块编码
rfid.PCD_StopCrypto1();
}
return foundTag;
}
void setup() {
Serial.begin(115200);
setupBLE("ESP32 Device");//设置蓝牙名称
myservo.attach(SERVO_PIN); //引脚12为PWM脚
SPI.begin(); // 初始化SPI总线
rfid.PCD_Init(); // 初始化 MFRC522
}
void loop() {
static unsigned long toggle_time = millis();
static bool lock_back_flag=false;
static bool foundTag; //匹配标签
if(compare_pw(keypad.getKey()) || Match_Card(totalTags)){ //密码正确 or 刷卡成功
toggle = true;
}
if(toggle){ //开门
locker(toggle); //开锁
toggle = false;
lock_back_flag = true;
toggle_time = millis();
}
if(millis() - toggle_time > openInterval && lock_back_flag){ //回锁时间5s
lock_back_flag = false;
locker(toggle);//回锁
}
}
3)读取S50信息并验证
将注册过的标签接近ML-RC522串口监视器打印验证结果,串口显示标签的名字,Servo马达转动。
否则,串口显示验证失败。
五、其他问题