第09章 指纹开锁
约 4911 字大约 16 分钟
2026-02-03
9.1 指纹模组
HLK-FPM383F是一款新型面阵式半导体指纹模组, 与市面上已有产品对比, 该模组具有体积小,功耗低,识别速度快, 识别准确度高等优势。
使用方便, 尤其适合应用于门锁, 读卡器和保险箱等体积较小, 使用电池供电的设备中. 低功耗的同时可以保持优异的反应性能及高速的识别速度。
HLK-FPM383F 是一款新型面阵式半导体指纹模组, 与市面上已有产品对比, 该模组具有体积小,功耗低,识别速度快, 识别准确度高等优势。
使用方便, 尤其适合应用于门锁, 读卡器和保险箱等体积较小, 使用电池供电的设备中. 低功耗的同时可以保持优异的反应性能及高速的识别速度。





产品链接:
官方驱动参考代码:
原理图


术语解释
(1)模块 FPM383 是一个模块,它包含传感器、处理器、存储器等组件,能够独立执行指纹识别相关的操作。
(2)指纹图像 这是通过指纹传感器获取的原始指纹图像。传感器会将手指的纹路捕捉为图像数据,通常这个过程叫做“采集指纹图像”。
(3)特征提取 指从采集到的指纹图像中提取出具有代表性的细节点(如分叉点和终止点)信息,这些细节点被称为“指纹特征”。
(4)指纹模板 指纹模板是指纹特征数据的抽象表示,它包含指纹的关键特征点,供后续比对使用。每个指纹模板可以存储在模块的内部存储器中。
(5)模板 ID 每个指纹模板在模块中都有一个唯一的 ID 标识符,用于区分不同的指纹。模板 ID 是指纹存储、比对、删除操作中的关键参数。
(6)比对 比对是指将当前采集到的指纹特征与已经存储在模块中的指纹模板进行对比,以确定指纹是否匹配。比对通常会返回一个匹配度(通常是一个信任值)。
(7)信任值(相似度) 在指纹比对过程中,信任值表示当前指纹与已存储模板的匹配程度。通常信任值越高,匹配度越高,意味着指纹更可能是同一个人的。
(8)录入 录入是指将一个新指纹注册到模块中,成为可以用于比对的指纹模板。通常需要多次采集相同的指纹,以确保模板的准确性。
(9)包错误 在模块和主控板之间的通信中,如果数据包传输过程中出现错误(如数据丢失或损坏),则会产生包错误。包错误可能导致指纹操作失败。9.2 硬件接口层:FPM383
① 基础配置
实现:初始化、发送指令、接收指令、休眠、获取芯片序列号


Int_FPM383.h
#ifndef __INT_FPM383_H__
#define __INT_FPM383_H__
#include "Com_Debug.h"
#include "Com_Config.h"
#include "driver/gpio.h"
#include "driver/uart.h"
// 宏定义:相关引脚
#define FPM383_UART_TX_PIN GPIO_NUM_21
#define FPM383_UART_RX_PIN GPIO_NUM_20
#define FPM383_INT_PIN GPIO_NUM_10
#define FPM383_EN_PIN GPIO_NUM_8
// 宏定义:接收缓冲区大小
#define RX_BUF_SIZE 128
/**
* @brief 初始化FPM383模块
*
*/
void Int_FPM383_Init(void);
/**
* @brief 进入Sleep模式
*/
void Int_FPM383_Sleep(void);
/**
* @brief 获取FPM383模块的唯一序列号
*
*/
void Int_FPM383_GetID(void);
#endif /* __INT_FPM383_H__ */Int_FPM383.c
#include "Int_FPM383.h"
// 定义全局变量,作为接收缓冲区
static uint8_t rx_buf[RX_BUF_SIZE];
// 静态函数:向FPM383发送指令
static Com_Status Int_FPM383_SendCmd(uint8_t *cmd, uint16_t len)
{
return uart_write_bytes(UART_NUM_1, cmd, len) == len ? Com_OK : Com_ERROR;
}
// 静态函数:接收来自于FPM383的响应
static Com_Status Int_FPM383_ReceiveData(uint16_t rx_len)
{
// 清空接收缓冲区
memset(rx_buf, 0, RX_BUF_SIZE);
rx_buf[9] = 0x01; // 确认码先置为1
// 接收数据
return uart_read_bytes(UART_NUM_1, rx_buf, rx_len, 1000) == rx_len ? Com_OK : Com_ERROR;
}
/**
* @brief 初始化FPM383模块
*
*/
void Int_FPM383_Init(void)
{
// 1. 设置串口 --------------------------------
// 1.1 配置串口参数
const uart_config_t uart_config = {
.baud_rate = 57600, // 波特率:57600
.data_bits = UART_DATA_8_BITS, // 数据位:8位
.parity = UART_PARITY_DISABLE, // 奇偶校验:禁用
.stop_bits = UART_STOP_BITS_1, // 停止位:1位
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, // 硬件流控:禁用
.source_clk = UART_SCLK_DEFAULT, // 时钟源:默认(通常是APB时钟)
};
// 1.2 安装串口驱动
uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
// 1.3 参数设置
uart_param_config(UART_NUM_1, &uart_config);
// 1.4 引脚设置
uart_set_pin(UART_NUM_1, FPM383_UART_TX_PIN, FPM383_UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
// 2. GPIO 设置 ----------------------------------
// 2.1 配置参数
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE, // 禁用中断
.mode = GPIO_MODE_OUTPUT, // 设置为输出模式
.pin_bit_mask = (1 << FPM383_EN_PIN), // 设置引脚位掩码
.pull_down_en = 0, // 禁用下拉电阻
.pull_up_en = 0, // 禁用上拉电阻
};
// 2.2 使用给定配置配置GPIO
gpio_config(&io_conf);
// 2.3 设置引脚初始值,设置为低电平
gpio_set_level(FPM383_EN_PIN, 0);
// 3. 进入Sleep -----------------------------------
Int_FPM383_Sleep();
}
/**
* @brief 进入Sleep模式
*/
void Int_FPM383_Sleep(void)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[12] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x03, // 包长度
0x33, // 指令码
0x00, 0x37 // 校验和
};
// 发送命令进入Sleep,知道彻底进入Sleep
do
{
// 发送命令
Int_FPM383_SendCmd(tx_cmd, 12);
// 接收响应
Int_FPM383_ReceiveData(12);
printf("Enter Sleep ...\r\n");
} while (rx_buf[9] == 0x01);
printf("Enter Sleep Success!\r\n");
}
/**
* @brief 获取FPM383模块的唯一序列号
*
*/
void Int_FPM383_GetID(void)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[13] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x04, // 包长度
0x34, // 指令码
0x00, // 参数
0x00, 0x39 // 校验和
};
// 2. 发送命令
Int_FPM383_SendCmd(tx_cmd, 13);
// 3. 接收响应
Int_FPM383_ReceiveData(44);
// 4. 解析响应内容
if (rx_buf[9] == 0x00)
{
printf("Get ID Success: %.32s \r\n", (char *)(rx_buf + 10));
}
else
{
printf("Get ID Failed!\r\n");
}
}main.c 测试代码
#include "Int_FPM383.h"
void app_main(void)
{
MY_LOGI("Smart Lock Project");
// 初始化FPM383模块
Int_FPM383_Init();
// 获取FPM383模块的唯一序列号
Int_FPM383_GetID();
}② 检测手指按压

Int_FPM383.h
/* 代码省略 ... */
// 外部声明:全局变量
extern bool is_finger_detected;
/* 代码省略 ... */Int_FPM383.c
/* 代码省略 ... */
// 定义全局变量,标记指纹是否按下
bool is_finger_detected = false;
// 静态函数:中断服务函数
static void Int_FPM383_ISR_Handler(void *arg)
{
is_finger_detected = true;
}
/* 代码省略 ... */
/**
* @brief 初始化FPM383模块
*
*/
void Int_FPM383_Init(void)
{
/* 代码省略 ... */
// 3. 中断设置 -----------------------------------
// 3.1 配置参数
gpio_config_t it_conf = {
.intr_type = GPIO_INTR_POSEDGE, // 配置GPIO引脚中断 - 上升沿触发
.pin_bit_mask = (1 << FPM383_INT_PIN), // 设置引脚位掩码,选择要配置的GPIO引脚
.mode = GPIO_MODE_INPUT, // 设置GPIO工作模式为输入模式(因为我们要检测外部信号)
.pull_up_en = GPIO_PULLUP_DISABLE, // 浮空,不使能内部上拉电阻
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 下拉
};
// 3.2 应用配置
gpio_config(&it_conf);
// 3.3 开启中断
gpio_install_isr_service(0);
// 3.4 添加中断服务函数
gpio_isr_handler_add(FPM383_INT_PIN, Int_FPM383_ISR_Handler, NULL);
// 3.5 关闭中断
gpio_intr_disable(FPM383_INT_PIN);
// 4. 进入Sleep -----------------------------------
Int_FPM383_Sleep();
}main.c 测试代码
/* 代码省略 ... */
void app_main(void)
{
MY_LOGI("Smart Lock Project");
// 初始化FPM383模块
Int_FPM383_Init();
// 获取FPM383模块的唯一序列号
Int_FPM383_GetID();
while (1)
{
// 如果检测到手指
if (is_finger_detected)
{
// 关闭中断
gpio_intr_disable(FPM383_INT_PIN);
printf("Finger Detected!\r\n");
// 清除标志位
is_finger_detected = false;
// 进入睡眠
Int_FPM383_Sleep();
}
vTaskDelay(300);
}
}③ 注册指纹


Int_FPM383.h
/* 代码省略 ... */
/**
* @brief 自动注册指纹
* @param id 指纹ID
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_AutoEnroll(uint16_t id);Int_FPM383.c
添加 Int_FPM383_CheckSum() 和 Int_FPM383_CancelAutoEnroll() 两个静态函数
添加 Int_FPM383_AutoEnroll() 函数
/* 代码省略 ... */
// 静态函数:计算校验和
static void Int_FPM383_CheckSum(uint8_t *cmd, uint16_t len)
{
// 定义变量,保存校验和
uint16_t checksum = 0;
// 遍历命令,从包标识开始
for (uint16_t i = 6; i < len - 2; i++)
{
checksum += cmd[i];
}
// 将校验和添加到命令中
cmd[len - 2] = checksum >> 8;
cmd[len - 1] = checksum & 0xFF;
}
// 静态函数:取消自动注册指纹
static void Int_FPM383_CancelAutoEnroll(void)
{
// 1. 定义指令
uint8_t tx_cmd[12] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x03, // 包长度
0x30, // 指令码
0x00, 0x00 // 校验和
};
// 2. 计算校验和
Int_FPM383_CheckSum(tx_cmd, 12);
// 发送指令,知道取消自动注册成功
do
{
// 发送指令
Int_FPM383_SendCmd(tx_cmd, 12);
// 接收应答包
Int_FPM383_ReceiveData(12);
} while (rx_buf[9] != 0x00);
printf("Cancel Auto Enroll Success \r\n");
}
/* 代码省略 ... */
/**
* @brief 自动注册指纹
* @param id 指纹ID
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_AutoEnroll(uint16_t id)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[17] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x08, // 包长度
0x31, // 指令码
id >> 8, id & 0xFF, // ID
0x01, // 录入次数
0x00, 0x37, // 参数
0x00, 0x00 // 校验和
};
// 2. 计算校验和
Int_FPM383_CheckSum(tx_cmd, 17);
MY_LOGI("FPM383 AutoEnroll: %d; ----------------------------", id);
MY_LOGI("Send CMD:");
for (uint16_t i = 0; i < 17; i++)
{
printf("%02X ", tx_cmd[i]);
}
printf("\r\n");
// 3. 取消自动注册,解决BUG,需要连续取消4次
Int_FPM383_CancelAutoEnroll();
Int_FPM383_CancelAutoEnroll();
Int_FPM383_CancelAutoEnroll();
Int_FPM383_CancelAutoEnroll();
// 4. 发送指令
Int_FPM383_SendCmd(tx_cmd, 17);
// 5. 接收多个应答包,前面的应答包接收成功再接收下一个,只要一个应答包接收失败就整体失败
do
{
// 接收应答包
Int_FPM383_ReceiveData(14);
// 接收完最后一个应答包,结束
if (rx_buf[10] == 0x06 && rx_buf[9] == 0x00)
{
MY_LOGI("ReceiveData: ");
for (uint16_t i = 0; i < 14; i++)
{
printf("%02X ", rx_buf[i]);
}
printf("\r\n");
MY_LOGI("------------------------------------");
return Com_OK;
}
} while (rx_buf[9] == 0x00);
return Com_ERROR;
}
/* 代码省略 ... */④ 读取索引表 获取最小指纹ID

Int_FPM383.h
添加函数原型 Int_FPM383_GetMinFingerID()
/* 代码省略 ... */
/**
* @brief 获取最小的未被占用的指纹ID
*
* @return int32_t 最小的未被占用的指纹ID,如果错误返回-1
*/
int32_t Int_FPM383_GetMinFingerID(void);
/* 代码省略 ... */Int_FPM383.c
添加函数 Int_FPM383_GetMinFingerID()
/* 代码省略 ... */
/**
* @brief 获取最小的未被占用的指纹ID
*
* @return int32_t 最小的未被占用的指纹ID,如果错误返回-1
*/
int32_t Int_FPM383_GetMinFingerID(void)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[13] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x04, // 包长度
0x1F, // 指令码
0x00, // 页码
0x00, 0x00 // 校验和
};
// 2. 计算校验和
Int_FPM383_CheckSum(tx_cmd, 13);
// 3. 发送命令
Int_FPM383_SendCmd(tx_cmd, 13);
// 4. 接收响应
Int_FPM383_ReceiveData(44);
// 5. 解析响应内容
if (rx_buf[9] == 0x00)
{
// 遍历所有指纹ID信息
for (uint8_t i = 10; i < 42; i++)
{
// 取出当前的字节
uint8_t byte = rx_buf[i];
// 逐位检查 byte
for (uint8_t j = 0; j < 8; j++)
{
// 检查当前的最低位是否是1
if (byte & 0x01)
{
byte >>= 1;
}
else
{
// 计算当前位的指纹ID
uint16_t finger_id = (i - 10) * 8 + j;
printf("Get Min Finger ID: %d\r\n", finger_id);
return finger_id;
}
}
}
return -1;
}
else
{
return -1;
}
}
/* 代码省略 ... */⑤ 自动验证指纹



Int_FPM383.h
添加函数原型 Int_FPM383_VerifyFinger()
/* 代码省略 ... */
/**
* @brief 验证指纹
*
* @return int32_t 验证结果,成功返回指纹ID,失败返回-1
*/
int32_t Int_FPM383_VerifyFinger(void);
/* 代码省略 ... */Int_FPM383.c
添加函数 Int_FPM383_VerifyFinger()
/* 代码省略 ... */
/**
* @brief 验证指纹
*
* @return int32_t 验证结果,成功返回指纹ID,失败返回-1
*/
int32_t Int_FPM383_VerifyFinger(void)
{
MY_LOGI("FPM383 VerifyFinger: ");
// 1. 定义要发送的命令字节
uint8_t tx_cmd[17] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x08, // 包长度
0x32, // 指令码
0x03, // 分数等级
0xFF, 0xFF, // ID号
0x00, 0x06, // 参数
0x00, 0x00 // 校验和
};
// 2. 计算校验和
Int_FPM383_CheckSum(tx_cmd, 17);
// 3. 发送命令
Int_FPM383_SendCmd(tx_cmd, 17);
// 4. 接收应答包
Int_FPM383_ReceiveData(17);
// 5. 判断验证结果
if (rx_buf[9] == 0x00)
{
uint16_t finger_id = (rx_buf[11] << 8) | rx_buf[12];
printf("Verify Finger OK! ID: %d \r\n", finger_id);
return finger_id;
}
else
{
return -1;
}
}
/* 代码省略 ... */⑥ 删除指纹


Int_FPM383.h
添加函数原型 Int_FPM383_DeleteFinger()、Int_FPM383_DeleteAllFingers()
/* 代码省略 ... */
/**
* @brief 删除指定ID的指纹
*
* @param id 要删除的指纹ID
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_DeleteFinger(uint16_t id);
/**
* @brief 删除所有指纹
*
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_DeleteAllFingers(void);
/* 代码省略 ... */Int_FPM383.c
添加函数 Int_FPM383_DeleteFinger()、Int_FPM383_DeleteAllFingers()
/* 代码省略 ... */
/**
* @brief 删除指定ID的指纹
*
* @param id 要删除的指纹ID
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_DeleteFinger(uint16_t id)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[16] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x07, // 包长度
0x0C, // 指令码
id >> 8, id & 0xFF, // ID
0x00, 0x01, // 删除个数
0x00, 0x00 // 校验和
};
// 2. 计算校验和
Int_FPM383_CheckSum(tx_cmd, 16);
// 3. 发送指令
Int_FPM383_SendCmd(tx_cmd, 16);
// 4. 接收应答包
Int_FPM383_ReceiveData(12);
// 5. 解析应答包
if (rx_buf[9] == 0x00)
{
return Com_OK;
}
return Com_ERROR;
}
/**
* @brief 删除所有指纹
*
* @return Com_Status 状态码
*/
Com_Status Int_FPM383_DeleteAllFingers(void)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[12] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x03, // 包长度
0x0D, // 指令码
0x00, 0x11 // 校验和
};
// 2. 发送指令
Int_FPM383_SendCmd(tx_cmd, 12);
// 3. 接收应答包
Int_FPM383_ReceiveData(12);
// 4. 解析应答包
if (rx_buf[9] == 0x00)
{
return Com_OK;
}
return Com_ERROR;
}
/* 代码省略 ... */⑦ 获取已注册指纹数量
Int_FPM383.h
添加函数原型 Int_FPM383_GetFingerCount()
/* 代码省略 ... */
/**
* @brief 获取当前已注册的指纹数量
*
* @return uint8_t 已注册的指纹数量
*/
uint8_t Int_FPM383_GetFingerCount(void);
/* 代码省略 ... */Int_FPM383.c
添加函数 Int_FPM383_GetFingerCount()
/* 代码省略 ... */
/**
* @brief 获取当前已注册的指纹数量
*
* @return uint8_t 已注册的指纹数量
*/
uint8_t Int_FPM383_GetFingerCount(void)
{
// 1. 定义要发送的命令字节
uint8_t tx_cmd[12] = {
0xEF, 0x01, // 包头
0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
0x01, // 包标识
0x00, 0x03, // 包长度
0x1D, // 指令码
0x00, 0x21 // 校验和
};
// 2. 发送指令
Int_FPM383_SendCmd(tx_cmd, 12);
// 3. 接收应答包
Int_FPM383_ReceiveData(14);
// 5. 解析应答包
uint8_t count = 0;
if (rx_buf[9] == 0x00)
{
count = (rx_buf[10] << 8) | rx_buf[11];
}
printf("GetFingerCount: %d \r\n", count);
return count;
}
/* 代码省略 ... */9.3 应用层
① 需求分析
按键
“20” 添加指纹
"21" 删除指定的指纹
"22" 删除所有指纹
任务轮询
触发中断后,比对指纹,比对通过,开锁② 创建指纹处理任务
main.c
/* 代码省略 ... */
#include "App_Finger.h"
/* 代码省略 ... */
// 扫描指纹任务 ---------------------
// 任务函数的原型
void vScanFingerTaskFunc(void *pvParameters);
// 任务名称
#define SCAN_FINGER_TASK_NAME "ScanFingerTask"
// 任务栈大小
#define SCAN_FINGER_TASK_STACK_SIZE 4096
// 任务优先级
#define SCAN_FINGER_TASK_PRIORITY 5
// 任务句柄
TaskHandle_t xScanFingerTaskHandle = NULL;
void app_main(void)
{
MY_LOGI("Smart Lock Project");
// 初始化IO模块
App_IO_Init();
// 初始化指纹模块
App_Finger_Init();
// 创建扫描按键任务
xTaskCreate(vScanKeyTaskFunc, SCAN_KEY_TASK_NAME, SCAN_KEY_TASK_STACK_SIZE, NULL, SCAN_KEY_TASK_PRIORITY, &xScanKeyTaskHandle);
MY_LOGI("ScanKeyTask created");
/* 代码省略 ... */
}
/* 代码省略 ... */
// 扫描指纹任务函数
void vScanFingerTaskFunc(void *pvParameters)
{
MY_LOGI("Scan Finger Task Start ...");
// 循环
while (1)
{
// 处理指纹操作
App_Finger_ProcessFinger();
// 阻塞延时
vTaskDelay(50);
}
}③ 任务处理函数
添加指纹步骤
关闭中断
语音播报:放置手指
延时给用户时间放置手指
获取最小可用ID
自动注册指纹
重新睡眠删除指定指纹步骤
关闭中断
语音播报:放置手指
延时给用户时间放置手指
获取当前指纹ID
执行删除
重新睡眠删除所有指纹步骤
关闭中断
删除所有
重新睡眠指纹比对
如果触发中断
验证指纹,验证通过开锁代码: App_Finger.h
#ifndef __APP_FINGER_H__
#define __APP_FINGER_H__
#include "Com_Config.h"
#include "Com_Debug.h"
#include "Int_WTN6170.h"
#include "Int_FPM383.h"
#include "Int_BDR6120S.h"
/**
* @brief 初始化
*
*/
void App_Finger_Init(void);
/**
* @brief 处理指纹操作,需要在任务中轮询调用
*
*/
void App_Finger_ProcessFinger(void);
#endif /* __APP_FINGER_H__ */代码:App_Finger.c
#include "App_Finger.h"
/**
* @brief 初始化
*
*/
void App_Finger_Init(void)
{
// 初始化指纹模块
Int_FPM383_Init();
// 获取指纹模块唯一序列号
Int_FPM383_GetID();
}
/**
* @brief 处理指纹操作,需要在任务中轮询调用
*
*/
void App_Finger_ProcessFinger(void)
{
// 等待任务通知,不阻塞
uint32_t action = 0;
xTaskNotifyWait(UINT32_MAX, UINT32_MAX, &action, 0);
// action是1,添加指纹
if (action == 1)
{
// 关闭中断
gpio_intr_disable(FPM383_INT_PIN);
// 语音播报:放置手指
sayWithoutInt();
sayPlaceFinger();
// 延时给用户放置手指时间
vTaskDelay(2000);
// 获取最小ID,如果获取失败,退出
int32_t id = Int_FPM383_GetMinFingerID();
if (id == -1)
{
sayWithoutInt();
sayAddFail();
// 再次进入睡眠
Int_FPM383_Sleep();
return;
}
// 自动注册指纹
if (Int_FPM383_AutoEnroll((uint16_t)id) != Com_OK)
{
sayWithoutInt();
sayAddFail();
// 再次进入睡眠
Int_FPM383_Sleep();
return;
}
// 语音播报:添加成功
sayWithoutInt();
sayAddSucc();
// 再次进入睡眠
Int_FPM383_Sleep();
}
// action 是 2,删除指定指纹
else if (action == 2)
{
// 关闭中断
gpio_intr_disable(FPM383_INT_PIN);
// 语音播报: 放置手指
sayWithoutInt();
sayPlaceFinger();
// 延时给用户放置手指时间
vTaskDelay(2000);
// 获取当前指纹的ID(验证指纹), 如果获取失败,退出
int32_t id = Int_FPM383_VerifyFinger();
if (id == -1)
{
sayWithoutInt();
sayDelFail();
// 再次进入睡眠
Int_FPM383_Sleep();
return;
}
// 删除指定指纹
if (Int_FPM383_DeleteFinger((uint16_t)id) != Com_OK)
{
sayWithoutInt();
sayDelFail();
// 再次进入睡眠
Int_FPM383_Sleep();
return;
}
// 语音播报:删除成功
sayWithoutInt();
sayDelSucc();
// 再次进入睡眠
Int_FPM383_Sleep();
}
// acton 是 3,删除所有指纹
else if (action == 3)
{
// 直接删除所有指纹
if (Int_FPM383_DeleteAllFingers() != Com_OK)
{
sayWithoutInt();
sayDelFail();
return;
}
// 语音播报:删除所有成功
sayWithoutInt();
sayDelSucc();
}
// 其他情况,比对指纹,比对成功,开锁
else
{
// 如果产生中断
if (is_fingerprint_detected)
{
// 关闭中断
gpio_intr_disable(FPM383_INT_PIN);
// 清除标记变量
is_fingerprint_detected = false;
// 已注册指纹>1且指纹对比成功,开锁
if (Int_FPM383_GetFingerCount() > 0 && Int_FPM383_VerifyFinger() != -1)
{
// 语音播报:验证成功
sayWithoutInt();
sayVerifySucc();
// 语音播报:开门
sayWithoutInt();
sayDoorOpen();
// 开锁
Int_BDR6120S_OpenLock();
}
else
{
// 语音播报:验证失败
sayWithoutInt();
sayVerifyFail();
// 语音播报:再次尝试
sayWithoutInt();
sayRetry();
}
// 再次进入睡眠
Int_FPM383_Sleep();
}
}
}④ 按键判断逻辑
App_IO.c
修改函数 App_IO_ProcessKeys()
/* 代码省略 ... */
// 声明指纹任务句柄
extern TaskHandle_t xScanFingerTaskHandle;
/* 代码省略 ... */
/**
* @brief 根据按键值确定进行何种操作
*
* @param keys 按下的按键值组成的数组
*/
void App_IO_ProcessKeys(uint8_t *keys)
{
/* 代码省略 ... */
// 长度是2,说明是指令
if (keys_len == 2)
{
/* 代码省略 ... */
else if (keys[0] == '2' && keys[1] == '0')
{
// 添加指纹
printf("add finger \r\n");
// 语音播报:添加指纹
sayWithoutInt();
sayAddUserFingerprint();
// 验证管理员密码,如果验证失败,直接退出
if (!App_IO_CheckAdmin())
{
// 直接退出
sayWithoutInt();
sayAddFail();
return;
}
// 任务通知扫描指纹任务,通知值是1,表示添加指纹
xTaskNotify(xScanFingerTaskHandle, 1, eSetValueWithOverwrite);
}
else if (keys[0] == '2' && keys[1] == '1')
{
// 删除指定的指纹
printf("delete finger \r\n");
// 语音播报:删除指纹
sayWithoutInt();
sayDelUserFingerprint();
// 验证管理员密码,如果验证失败,直接退出
if (!App_IO_CheckAdmin())
{
// 直接退出
sayWithoutInt();
sayDelFail();
return;
}
// 任务通知扫描指纹任务,通知值是2,表示删除指定指纹
xTaskNotify(xScanFingerTaskHandle, 2, eSetValueWithOverwrite);
}
else if (keys[0] == '2' && keys[1] == '2')
{
// 删除所有指纹
printf("delete all finger \r\n");
// 语音播报:删除所有指纹
sayWithoutInt();
sayDelAll();
// 验证管理员密码,如果验证失败,直接退出
if (!App_IO_CheckAdmin())
{
// 直接退出
sayWithoutInt();
sayDelFail();
return;
}
// 任务通知扫描指纹任务,通知值是3,表示删除所有指纹
xTaskNotify(xScanFingerTaskHandle, 3, eSetValueWithOverwrite);
}
/* 代码省略 ... */
}
/* 代码省略 ... */
}