实训5——设置指纹

实训五:设置指纹实验

一、实验目的

利用ESP32和FPM10A光学指纹模块,通过蓝牙调试助手发送相应协议,实现指纹录入、指纹查询、指纹删除。指纹匹配功能需要先按一些键盘才能唤醒指纹模块,在10s内进行指纹匹配。
指纹匹配成功,启动舵机。

二、实验内容

1.蓝牙发指令录入指纹
2.蓝牙发指令删除已录入的指纹
3.蓝牙发指令查询指纹
4.按键唤醒指纹模块,然后匹配已录入的指纹
5.匹配指纹成功后启动舵机

三、实验设备

1.ESP32-WROOM-32D开发板
2.FPM10A光学指纹模块(红色:5V TX:绿色 RX:黄色 黑色:GND)
指纹模块
3.杜邦线
4.SG90舵机

四、实验步骤

1) 安装Adafruit指纹传感器库

1.Adafruit指纹传感器库下载:https://github.com/adafruit/Adafruit-Fingerprint-Sensor-Library/archive/master.zip
2.解压下载的.zip文件,你会看到一个Adafruit-Fingerprint-Sensor-Library-master文件夹
3.将Adafruit-Fingerprint-Sensor-Library-master文件夹重命名为Adafruit_Fingerprint_Sensor_Library文件夹
4.将文件夹移动到您的Arduino IDE安装库文件夹中的libraries文件夹
5.重新打开Arduino IDE

2) 连接设备

1.连接设备
将FPM10A指纹模块与ESP32连接,如下图所示:
FPM10A的RX连接ESP32引脚17
FPM10A的TX连接ESP32引脚16

在这里插入图片描述

3) 测试代码
/*Author :王滨伟
* Time :2020.6.11
*/
#include <dummy.h>
#include <Servo.h>
#include <BLEDevice.h>
#include <BLE2902.h>
#include <String.h>
#include <Keypad.h>
#include <SPI.h>
#include <MFRC522.h> 
#include <Adafruit_Fingerprint.h>
/*
* ESP32 引脚17(TX)和16(RX)上的Serial2
* 指纹模块   连 接    ESP32
  RX黄      ---      17  
  TX绿      ---      16 
*/
#define mySerial Serial2
#define SS_PIN 21  //定义RC522的SDA引脚的接线位置
#define RST_PIN 22  //定义RC522的RST引脚的接线位置
#define SERVO_PIN 15 //舵机的脚位
#define NormolClose 13

#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
#define fpInterval 10000
BLECharacteristic *pCharacteristic;
bool deviceConnected = false; 
/*
* 按键
*/
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);  //计算结构资料的数量
bool door_open_flag; //开门动作标志位
bool alarm_flag;//报警标志位
static bool lock_back_flag=false; //回锁标志位
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;
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
bool FP_busy=false;
short active_fp = -1; //激活指纹模块, -1休眠,1激活,2指纹模块正在激活时间
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进制发送
* 55aa2000363534333231 蓝牙修改密码指令
* 55aa3000000000000000 蓝牙查询指令
* 55aa3100310000000000 蓝牙注册指纹 注册id号为01
* 55aa3200330000000000 蓝牙删除指纹 删除id号为03
*/
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:{ //设置密码
         static byte temp_pw[6]; //临时密码
         for(byte i=0;i<6;i++){ 
           if(ble_rx_buffer[i+4]<=0x39 && ble_rx_buffer[i+4]>=0x30){ //保证密码在0-9之间 
                temp_pw[i]=ble_rx_buffer[i+4]-0x30; 
           }
           else{ //无效字符
              break;
           }
           if(i==5){ //密码修改完成
             Serial.println("密码修改完成");
             memcpy(init_pw,temp_pw,6); 
           }
         }
         break;
       }
       case 0x30:{ //查看指纹
         FP_busy = true;
         finger.getTemplateCount(); //查当前指纹模板的数量
         Serial.print("Sensor contains ");
         Serial.print(finger.templateCount);
         Serial.println(" templates");
         FP_busy = false;
         break;
       }
       case 0x31:{//添加指纹
         byte id;
         FP_busy = true;
         id = ble_rx_buffer[4] - 0x30; //注册指纹id
         getFingerprintEnroll(id);
         FP_busy = false; 
         break;
       }
       case 0x32:{ //删除指纹
         byte id;
         FP_busy = true;
         id = ble_rx_buffer[4] - 0x30; //删除指纹id
         Serial.print("Deleting ID #");
         Serial.println(id);
         deleteFingerprint(id);
         FP_busy = false;
         break;
       }
      }
    }
   }
};
/*配置蓝牙
* 参数: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){
   //FP_busy = false;//唤醒指纹模块,可以开始匹配
   Serial.println(key);
   active_fp = 1;
   //Serial.println(active_fp);
   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;
}
/*门磁中断函数
* 参数 open_flag:正常开门的标志位
*/
void handleInterrupt() {
 delay(100);
 if (digitalRead(NormolClose)){// 电平高,门开
     detachInterrupt(digitalPinToInterrupt(NormolClose)); //屏蔽中断脚位
     door_open_flag = 1;  
     if(!lock_back_flag){//门没在开锁时间,门磁变化,算撬门报警
       alarm_flag = 1;  
     }    
   Serial.println("door open");
 }
}

/*指纹模块配置函数
* configure_FP()
*/
void configure_FP(){
   finger.begin(57600);
   if (finger.verifyPassword()) {
       Serial.println("Found fingerprint sensor!");
       finger.getTemplateCount();
       Serial.print("Sensor contains ");
       Serial.print(finger.templateCount);
       Serial.println(" templates");
       Serial.println("Waiting for valid finger...");
   }
   else {
     delay(1000);
     Serial.println("Did not find fingerprint sensor :");
   }
}

/* 匹配指纹函数
*  传入:searchFinger,表示匹配指纹与否
* returns -1 if failed, otherwise returns ID
*/
int getFingerprintIDez() {
 uint8_t p = finger.getImage();
 if (p != FINGERPRINT_OK)  return -1;

 p = finger.image2Tz();
 if (p != FINGERPRINT_OK)  return -1;

 p = finger.fingerFastSearch();
 if (p != FINGERPRINT_OK)  return -1;
 // Found a match!
 //searchFinger = 1;
 //idSearch = finger.fingerID;
 Serial.print("Found ID #"); Serial.print(finger.fingerID); 
 Serial.print(" with confidence of "); Serial.println(finger.confidence);
 //active_fp = -1; //休眠
 return finger.fingerID; 
}
/*指纹注册函数
* 输入参数: id为注册指纹的id
* 返回值: uint8_t p, p=0时录入成功
*/
uint8_t getFingerprintEnroll(byte id) {
 int p = -1;
 Serial.print("Waiting for valid finger to enroll as ");
 Serial.println(id);
 while (p != FINGERPRINT_OK) {
   p = finger.getImage();
   switch (p) {
   case FINGERPRINT_OK:
     Serial.println("Image taken");
     break;
   case FINGERPRINT_NOFINGER:
     Serial.println(".");
     break;
   case FINGERPRINT_PACKETRECIEVEERR:
     Serial.println("Communication error");
     break;
   case FINGERPRINT_IMAGEFAIL:
     Serial.println("Imaging error");
     break;
   default:
     Serial.println("Unknown error");
     break;
   }
 }
//第一次采集结束
//槽位置放置要素模板
 p = finger.image2Tz(1);
 switch (p) {
   case FINGERPRINT_OK:
     Serial.println("Image converted");
     break;
   case FINGERPRINT_IMAGEMESS:
     Serial.println("Image too messy");
     return p;
   case FINGERPRINT_PACKETRECIEVEERR:
     Serial.println("Communication error");
     return p;
   case FINGERPRINT_FEATUREFAIL:
     Serial.println("Could not find fingerprint features");
     return p;
   case FINGERPRINT_INVALIDIMAGE:
     Serial.println("Could not find fingerprint features");
     return p;
   default:
     Serial.println("Unknown error");
     return p;
 }
 //OK Success
 
 Serial.println("Remove finger");
 delay(2000);
 p = 0;
 
 while (p != FINGERPRINT_NOFINGER) {
   p = finger.getImage();                              //请求传感器采集指纹
 }
 Serial.print("ID "); 
 Serial.println(id);
 
 p = -1;
 Serial.println("Place same finger again");
 while (p != FINGERPRINT_OK) {
   p = finger.getImage();
   switch (p) {
   case FINGERPRINT_OK:
     Serial.println("Image taken");
     break;
   case FINGERPRINT_NOFINGER:
     Serial.print(".");
     break;
   case FINGERPRINT_PACKETRECIEVEERR:
     Serial.println("Communication error");
     break;
   case FINGERPRINT_IMAGEFAIL:
     Serial.println("Imaging error");
     break;
   default:
     Serial.println("Unknown error");
     break;
   }
 }
// OK success!

 p = finger.image2Tz(2);
 switch (p) {
   case FINGERPRINT_OK:
     Serial.println("Image converted");
     break;
   case FINGERPRINT_IMAGEMESS:
     Serial.println("Image too messy");
     return p;
   case FINGERPRINT_PACKETRECIEVEERR:
     Serial.println("Communication error");
     return p;
   case FINGERPRINT_FEATUREFAIL:
     Serial.println("Could not find fingerprint features");
     return p;
   case FINGERPRINT_INVALIDIMAGE:
     Serial.println("Could not find fingerprint features");
     return p;
   default:
     Serial.println("Unknown error");
     return p;
 }
 
 // OK converted!
 Serial.print("Creating model for =");
 Serial.println(id);
 
 p = finger.createModel();   //要求传感器采用两个打印特征模板并创建模型
 if (p == FINGERPRINT_OK) {
   Serial.println("Print matched");
 } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
   Serial.println("Communication error");
   return p;
 } else if (p == FINGERPRINT_ENROLLMISMATCH) {
   Serial.println("Fingerprints did not match");
   return p;
 } else {
   Serial.println("Unknown error");
   return p;
 }   
 
 Serial.print("ID: "); 
 Serial.println(id);
 p = finger.storeModel(id);  //要求传感器存储计算模型以进行后续匹配
 if (p == FINGERPRINT_OK) {
   Serial.println("Stored!");
   return 1;
 } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
   Serial.println("Communication error");
   return p;
 } else if (p == FINGERPRINT_BADLOCATION) {
   Serial.println("Could not store in that location");
   return p;
 } else if (p == FINGERPRINT_FLASHERR) {
   Serial.println("Error writing to flash");
   return p;
 } else {
   Serial.println("Unknown error");
   return p;
 }  
}
/*删除指纹函数
* 输入参数:id为指纹id
* 返回值:p,p=0时,表示指纹模块删除成功
*/
uint8_t deleteFingerprint(uint8_t id) {
 uint8_t p = -1;
 p = finger.deleteModel(id);             //删除指纹成功返回0x00
 if (p == FINGERPRINT_OK) {
   Serial.println("Deleted!");
 } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
   Serial.println("Communication error");
   return p;
 } else if (p == FINGERPRINT_BADLOCATION) {
   Serial.println("Could not delete in that location");
   return p;
 } else if (p == FINGERPRINT_FLASHERR) {
   Serial.println("Error writing to flash");
   return p;
 } else {
   Serial.print("Unknown error: 0x"); 
   Serial.println(p, HEX);
   return p;
 }   
}

void setup() { 
 Serial.begin(115200);
 setupBLE("ESP32 Device");//设置蓝牙名称
 myservo.attach(SERVO_PIN); //引脚12为PWM脚  
 SPI.begin(); // 初始化SPI总线
 rfid.PCD_Init(); // 初始化 MFRC522
 configure_FP();//配置指纹模块
 pinMode(NormolClose, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(NormolClose), handleInterrupt, RISING); 
}
void loop() {
 static unsigned long toggle_time = millis();
 static unsigned long fp_time = millis();
 //Serial.print("Active_fp=");
 //Serial.println(active_fp);
 short idSearch = -1;       //匹配的指纹id
 if (!digitalRead(NormolClose)){ //电平低,门关
   attachInterrupt(digitalPinToInterrupt(NormolClose), handleInterrupt, RISING); // 设置中断脚位,检测下降沿电压
   door_open_flag = 0; 
 }
 if(!FP_busy && active_fp==2) //指纹模块空闲时进行指纹匹配 && 指纹模块正在激活期间
   idSearch=getFingerprintIDez(); //指纹匹配
 if(compare_pw(keypad.getKey()) || Match_Card(totalTags) || idSearch!=-1){ //密码正确 or 刷卡成功 or 指纹开门
   //Serial.println("开门");
   //Serial.println(idSearch);
   toggle = true;
   alarm_flag = false; //解除报警
 }
 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);//回锁
 }
 
 if(active_fp == 1){ //激活指纹模块
   fp_time = millis();
   active_fp=2;
 }
 if(active_fp==2 && millis() - fp_time > fpInterval){ //指纹激活时间5s
   active_fp = -1; //休眠
 }
 //报警信息:1、门未关好 2、有人撬门
 if(!lock_back_flag && door_open_flag){//关锁 and 门的状态是开
   if(alarm_flag){ //非法撬门
     Serial.println("非法撬门");
   }
   else{ //门未关好
     Serial.println("门未关好");
   }
 } 
}

4) 手机APP发送消息
通讯协议:
字段帧头标识校验和数据
长度2B1B1B16B

帧头:55aa
标识:
10 : 蓝牙开门
20:设置密码
30:查看指纹
31:添加指纹
32:删除指纹
检验和:目前不做校验,填00即可
数据位: 16字节,可以不填满

蓝牙添加指纹
字段帧头标识校验和数据
内容55aa31001B(添加指纹的ID)

蓝牙添加指纹发送消息案例:55aa3100330000000000,添加指纹ID=3
ps:都是以16进制发送,对应相应的ASCII码

蓝牙查询指纹
字段帧头标识校验和数据
内容55aa3000选填

蓝牙查询指纹发送消息案例:55aa3000000000000000
ps:都是以16进制发送,对应相应的ASCII码

蓝牙删除指纹
字段帧头标识校验和数据
内容55aa32001B(删除的指纹ID)

蓝牙删除指纹发送消息案例:55aa3200330000000000,删除的指纹ID=3
ps:都是以16进制发送,对应相应的ASCII码

5) 测试结果
指纹匹配

首先按一下键盘中的任意一键,唤醒指纹模块。在10s内,将手指放置到指纹模块上。若为注册过的指纹,则驱动舵机开门。

指纹匹配

指纹查询

蓝牙调试助手发送消息55aa3000000000000000,在串口调试助手上显示当前已注册指纹模块的数量。
指纹查询模块

蓝牙添加指纹

蓝牙调试助手发送55aa3100330000000000,当前消息例子表示注册指纹ID3。
蓝牙添加指纹

蓝牙删除指纹

蓝牙调试助手发送55aa3200330000000000,当前消息例子表示删除指纹ID=3的指纹。
蓝牙删除指纹

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值