FPM383驱动
FPM383C模组通信协议_V1.2.pdf这是官方文档如有需要在这里查看
一. 简介
-
面阵式指纹传感器
-
传感器表面覆盖保护涂层
-
RGB三色LED灯
-
UART接口
-
1.0mm连接器,支持可靠连接
-
指纹模组支持3.3V供电
-
ESD防护等级>15KV
-
假率FAR(FalseAcceptanceRate):<1/1000000
-
拒真率FRR(FalseRejectionRate):<2%
-
响应速度:特征提取时间<0.30s,单枚匹配时间<0.025s
-
支持存储 50枚指纹特征(拼接12次) (实测我的模块最大只支持4次拼接)
二. 关键参数
-
串口波特率为 57.6Kbps,数据格式:8 位数据位,1 位停止位,无校验位;
-
UART 波特率可以通过指令进行设置,范围从 9600 至115200;
-
模组中断信号由Sensor芯片产生,中断输出管脚内部默认加下拉电阻,休眠时中断输出脚会维持低电平,直到有手指按压指纹传感器,此时中断输出高电平,sensor再次进入休眠后变为低电平。
-
建议用户端MCU在模组唤醒之后,屏蔽中断引脚的中断触发功能,模组进入休眠之后,再开启中断触发,并且设置为上升沿触发。(任何一条指令都可以唤醒芯片)
-
如果主控是 MCU(3.3V),则直接与 UART_TD 和UART_RD 连接;如果主控是 PC,则需要挂接 RS232 电平转换设备。
-
指令包格式

- 包头固定为0xEF01
- 设备地址在没有生成之前为缺省的 0xffffffff,一旦主控通过指令生成了设备地址,则所 有的数据包都必须按照生成的地址收发。
- 包标识固定为0x01
- 包长度 = 包长度至校验和(指令、参数或数据)的总字节数,包含校验和,但不包含包长 度本身的字节数。
- 指令为各指令名一个字节
- 参数根据各指令决定
- 校验和 = 从包标识至校验和之间所有字节之和,包含包标识不包含校验和,超出 2 字节的进位忽略。
- 对于多字节的高字节在前低字节在后(如2bytes 的 00 06 表示0006,而不是0600)
-
指令应答格式

- 包头到包标识和指令包一样
- 确认码:(只看两个常用的,只有0x00为接收成功其均为失败,其他确认码在官方文档19页)
- 00H:表示指令执行完毕或OK;
- 01H:表示数据包接收错误
三. 串口连接
代码中使用的宏和枚举类型
#define FPM383_BAUDRATE 57600
#define FPM383_UART_NUM UART_NUM_1
#define FPM383_TX_GPIO GPIO_NUM_21
#define FPM383_RX_GPIO GPIO_NUM_20
#define FPM383_INT_GPIO GPIO_NUM_10
typedef enum
{
CMD_SUCCESS,
CMD_FAILED,
} Command_Status;
typedef enum
{
switch_ON,
switch_OFF,
} switch_type;
如需移植只需实现下面这几个函数即可
1. 初始化串口和中断引脚
中断引脚设置为上升沿触发,gpio下拉输入。串口波特率57600,8位数据位,1位停止位,不使用校验位。
/**
* @brief 初始化FPM383
*
* @param 无
*
* @return 无
*/
void FPM383_Init(void)
{
/* 创建按下手指二值信号量 */
g_xBinarySemaphorePressFinger = xSemaphoreCreateBinary();
/* 中断引脚配置 */
gpio_config_t FPM383_gpio_config =
{
.intr_type = GPIO_INTR_POSEDGE, /* 上升沿触发 */
.mode = GPIO_MODE_INPUT, /* 输入模式 */
.pin_bit_mask = (1 << FPM383_INT_GPIO), /* GPIO引脚掩码 */
.pull_down_en = GPIO_PULLDOWN_ENABLE, /* 下拉输入 */
.pull_up_en = GPIO_PULLUP_DISABLE,
};
gpio_config(&FPM383_gpio_config);
/* 安装中断服务驱动 */
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL2);
/* 添加中断服务程序 */
gpio_isr_handler_add(FPM383_INT_GPIO,FPM383_isr,(void*)FPM383_INT_GPIO);
uart_config_t FPM383_uart_config =
{
.baud_rate = FPM383_BAUDRATE, /* 波特率57600*/
.data_bits = UART_DATA_8_BITS, /* 数据位8位 */
.stop_bits = UART_STOP_BITS_1, /* 停止位1位 */
.parity = UART_PARITY_DISABLE, /* 不校验 */
.source_clk = UART_SCLK_DEFAULT, /* 使用默认时钟源APB*/
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, /* 不使用硬件流控制 */
};
/* 安装串口驱动 */
uart_driver_install(FPM383_UART_NUM,UART_RX_BUFF_SIZE,UART_TX_BUFF_SIZE,0,NULL,0);
/* 配置串口1 */
uart_param_config(FPM383_UART_NUM,&FPM383_uart_config);
/* 设置串口引脚 */
uart_set_pin(FPM383_UART_NUM,FPM383_TX_GPIO,FPM383_RX_GPIO,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE);
/* 睡眠 */
FPM383_sleep();
}
2. 中断回调函数
这里使用信号量也可以使用全局变量表示手指是否按下。
/* 按下手指二值信号量 */
SemaphoreHandle_t g_xBinarySemaphorePressFinger = NULL;
/* 表示是否按下手指 */
// uint8_t pressFinger = 0;
/**
* @brief 中断回调函数
*
* @param arg: 设置中断引脚时传递的参数
*
* @return 无
*/
void FPM383_isr(void *arg)
{
/* 信号量+1 */
xSemaphoreGiveFromISR(g_xBinarySemaphorePressFinger,NULL);
//uint8_t pressFinger = 1;
/* 唤醒后关中断 */
intr_switch(switch_OFF);
}
3. 串口发送数据
/**
* @brief 串口发送数据
*
* @param Txbuff: 发送的数据
* @param Txbuff_size: 发送的数据长度
*
* @return 无
*/
static void FPM383_send_data(uint8_t *Txbuff,uint8_t Txbuff_size)
{
uint8_t len = uart_write_bytes(FPM383_UART_NUM,Txbuff,Txbuff_size);
if(len == Txbuff_size)
{
// printf("发送成功\r\n");
}
else
{
printf("发送失败\r\n");
}
}
4. 串口接收数据
/* 使用全局数据作为接收缓冲区 */
static uint8_t g_rx_buff[100];
/**
* @brief 串口接收数据
*
* @param Rxbuff_size: 应答包的数据长度
* @param timeout: 超时时间
*
* @return 无
*/
static void FPM383_receive_data(uint8_t Rxbuff_size,uint16_t timeout)
{
/* 先清空数据 因为0为接收成功,所以将数组全部置1 */
memset(g_rx_buff,1,sizeof(g_rx_buff));
uint8_t len = uart_read_bytes(FPM383_UART_NUM,g_rx_buff,Rxbuff_size,timeout);
/* 接收到长度等于应答包的长度接收成功 */
if(len == Rxbuff_size)
{
// printf("接收成功\r\n");
}
else
{
printf("接收失败\r\n");
}
}
5. 开关中断
/**
* @brief 开关中断
*
* @param type: 开关
*
* @return 无
*/
void intr_switch(switch_type type)
{
if(type == switch_ON)
{
gpio_intr_enable(FPM383_INT_GPIO);
}
else
{
gpio_intr_disable(FPM383_INT_GPIO);
}
}
6. 延迟函数
/**
* @brief 延迟函数
*
* @param ms: 延迟时间 单位:ms
*
* @return 无
*/
void delay_ms(uint32_t ms)
{
vTaskDelay(pdMS_TO_TICKS(ms));
}
四. 业务类指令集
1 通用指令集
1.1 休眠指令PS_Sleep

代码
/**
* @brief 睡眠
*
* @param 无
*
* @return 无
*/
void FPM383_sleep(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X33, /* 指令码 */
0X00,0X37, /* 校验和 */
};
/* 确保睡眠指令成发出,否则后续无法执行 */
do
{
delay_ms(500);
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12,500);
} while (g_rx_buff[9] != 0);
/* 开中断 */
intr_switch(switch_ON);
printf("睡眠成功\r\n");
}
1.2 获取芯片唯一序列号PS_GetChipSN

代码
/**
* @brief 获取芯片ID
*
* @param 无
*
* @return 无
*/
void FPM383_get_chipID(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X04, /* 包长度 */
0X34, /* 指令码 */
0X00, /* 参数 */
0X00,0X39, /* 校验和 */
};
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(44,3000);
if(g_rx_buff[9] == 0)
{
printf("ID:%.32s\r\n",&g_rx_buff[10]);
}
else
{
printf("ID获取失败 确认码: %x\r\n",g_rx_buff[9]);
printf("获取ID失败\r\n");
}
FPM383_sleep();
}
1.3 验证用获取图像PS_GetImage

代码
/**
* @brief 获取图像
*
* @param 无
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_get_image(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X01, /* 指令码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd,sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12,500);
if(g_rx_buff[9] == 0)
{
printf("获取图像成功\r\n");
return CMD_SUCCESS;
}
else
{
printf("获取图像失败 确认码: %x\r\n", g_rx_buff[9]);
return CMD_FAILED;
}
}
1.4 生成特征PS_GenChar

代码
/**
* @brief 生成特征
*
* @param buffID: 缓冲区号
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_generate_feature(uint8_t buffID)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X04, /* 包长度 */
0X02, /* 指令码 */
buffID, /* 缓冲区ID */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd,sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12,500);
if(g_rx_buff[9] == 0)
{
printf("生成特征成功\r\n");
return CMD_SUCCESS;
}
else
{
printf("生成特征失败 确认码: %x\r\n",g_rx_buff[9]);
return CMD_FAILED;
}
}
1.5 合并特征(生成模板)PS_RegMode

代码
/**
* @brief 合并特征
*
* @param 无
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_merge_feature(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X05, /* 指令码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd,sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12, 500);
if(g_rx_buff[9] == 0)
{
printf("合并特征成功\r\n");
return CMD_SUCCESS;
}
else
{
printf("合并特征失败 确认码: %x\r\n", g_rx_buff[9]);
return CMD_FAILED;
}
}
1.6 储存模板PS_StoreChar

代码
/**
* @brief 存储模板
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_storage_template(uint16_t pageID)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X06, /* 包长度 */
0X06, /* 指令码 */
0x01, /* 缓冲区ID */
pageID >> 8,pageID & 0xFF, /* 位置号 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
uart_receive_data(12, 500);
if(0 == g_rx_buff[9])
{
printf("储存指纹成功\r\n");
return COM_OK;
}
else
{
printf("储存指纹失败 确认码: %x\r\n", g_rx_buff[9]);
return COM_ERROR;
}
}
1.7 搜索指纹PS_Search

代码
/**
* @brief 搜索指纹
*
* @param pageID: 指纹所在页码
* @param matchScore: 和指纹指纹对比得分
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_search_fingerprint(uint16_t *pageID, uint16_t *matchScore)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X08, /* 包长度 */
0X04, /* 指令码 */
0x01, /* 缓冲区ID */
0x00,0x00, /* 起始页 */
0x00,0x00, /* 页数0x00为搜索整个指纹库 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(16, 500);
if(g_rx_buff[9] == 0)
{
*pageID = ((g_rx_buff[10] << 8) | g_rx_buff[11]);
*matchScore = ((g_rx_buff[12] << 8) | g_rx_buff[13]);
//printf("搜索指纹成功\r\n");
return CMD_SUCCESS;
}
else
{
printf("搜索指纹失败 确认码: %x\r\n", g_rx_buff[9]);
return CMD_FAILED;
}
}
1.8 删除模板PS_DeletChar

代码
/**
* @brief 删除指纹
*
* @param pageID: 指纹所在页码
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_delete_fingerprint(uint16_t pageID)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X07, /* 包长度 */
0X0C, /* 指令码 */
pageID >> 8,pageID & 0xFF, /* 页码 */
0x00,0x01, /* 删除个数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12, 500);
if(g_rx_buff[9] == 0)
{
printf("删除指纹成功\r\n");
FPM383_sleep();
return CMD_SUCCESS;
}
else
{
printf("删除指纹失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return CMD_FAILED;
}
}
1.9 删除指纹库

代码
/**
* @brief 清空指纹库
*
* @param 无
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_clear_Fingerprint_database(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X0D, /* 指令码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12, 500);
if(g_rx_buff[9] == 0)
{
printf("清空指纹库成功\r\n");
FPM383_sleep();
return CMD_SUCCESS;
}
else
{
printf("清空指纹库失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return CMD_FAILED;
}
}
1.10 写系统寄存器PS_WriteReg

代码
/**
* @brief 写系统寄存器
*
* @param RegID: 寄存器号
* @param RegData: 寄存器数据
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_write_system_register(uint8_t RegID, uint8_t *RegContent)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X05, /* 包长度 */
0X0E, /* 指令码 */
RegID, /* 寄存器号 */
*RegContent, /* 内容 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
uart_receive_data(12, 500);
if(0 == g_rx_buff[9])
{
printf("写寄存器成功\r\n");
FPM383_sleep();
return COM_OK;
}
else
{
printf("写寄存器失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return COM_ERROR;
}
}
1.11 读模组基本参数PS_ReadSysPara

代码
/**
* @brief 读模组基本参数
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_read_module_basics_params(void)
{
uint16_t registerCount; /* 注册次数 */
uint16_t fingerprintTemplateSize; /* 指纹模板大小 */
uint16_t fingerprintDatabaseSize; /* 指纹库大小 */
uint16_t scoreLevel; /* 分数等级 */
uint8_t deviceAddress[4]; /* 设备地址 */
uint16_t packetSize; /* 数据包大小 */
uint16_t baudRate; /* 波特率设置 */
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X0F, /* 指令码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
uart_receive_data(28, 500);
registerCount = (g_rx_buff[10] << 8) | g_rx_buff[11]; /* 注册次数 */
fingerprintTemplateSize = (g_rx_buff[12] << 8)
| g_rx_buff[13]; /* 指纹模板大小*/
fingerprintDatabaseSize = (g_rx_buff[14] << 8)
| g_rx_buff[15]; /* 指纹库大小 */
scoreLevel = (g_rx_buff[16] << 8) | g_rx_buff[17]; /* 分数等级 */
deviceAddress[0] = g_rx_buff[18]; /* 设备地址 */
deviceAddress[1] = g_rx_buff[19];
deviceAddress[2] = g_rx_buff[20];
deviceAddress[3] = g_rx_buff[21];
packetSize = (g_rx_buff[22] << 8) | g_rx_buff[23]; /* 数据包大小 */
baudRate = (g_rx_buff[24] << 8) | g_rx_buff[25]; /* 波特率设置 */
if(0 == packetSize)
{
packetSize = 32;
}
else if(1 == packetSize)
{
packetSize = 64;
}
else if(2 == packetSize)
{
packetSize = 128;
}
else if(3 == packetSize)
{
packetSize = 256;
}
if(0 == g_rx_buff[9])
{
printf("读模组基本参数成功\
\r\n 注册次数: %d\
\r\n 指纹模板大小: %d\
\r\n 指纹库大小: %d\
\r\n 分数等级: %d\
\r\n 设备地址: %x %x %x %x\
\r\n 数据包大小: %dbytes\
\r\n 波特率设置: %d\r\n",registerCount,
fingerprintTemplateSize,
fingerprintDatabaseSize,
scoreLevel,
deviceAddress[0],
deviceAddress[1],
deviceAddress[2],
deviceAddress[3],
packetSize,
baudRate * 9600);
FPM383_sleep();
return COM_OK;
}
else
{
printf("读模组基本参数失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return COM_ERROR;
}
}
1.12 LED控制灯指令PS_ControlBLN

代码(一般指示灯可以使用,我的七彩呼吸灯不能使用)
/* LED灯功能码 */
typedef enum
{
LED_MODE_NORMAL_BREATHING = 1, // 普通呼吸灯
LED_MODE_BLINKING, // 闪烁灯
LED_MODE_ON, // 常开灯
LED_MODE_OFF, // 常闭灯
LED_MODE_FADE_IN, // 渐开灯
LED_MODE_FADE_OUT, // 渐闭灯
LED_MODE_RAINBOW_BREATHING // 七彩编程呼吸灯
} LED_mode_type;
/* 颜色类型 */
typedef enum
{
COLOR_CODE_NONE, // 无颜色
COLOR_CODE_BLUE, // 蓝色
COLOR_CODE_GREEN, // 绿色
COLOR_CODE_CYAN, // 青色
COLOR_CODE_RED, // 红色
COLOR_CODE_MAGENTA, // 品红色
COLOR_CODE_YELLOW, // 黄色
COLOR_CODE_WHITE, // 白色
} color_type;
/* 一般指示灯 */
typedef struct
{
led_mode_t mode; /* 指示灯模式 */
uint8_t start_color; /* 起始颜色 */
uint8_t finish_color; /* 结束颜色 */
uint8_t cycles_num; /* 循环次数 */
}led_config_t;
/**
* @brief 一般指示灯
*
* @param led_config: 指示灯配置
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_general_indicate_light(led_config_t led_config)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X07, /* 包长度 */
0X3C, /* 指令码 */
led_config.mode, /* 功能码 */
led_config.start_color, /* 起始颜色 */
led_config.finish_color, /* 结束颜色 */
led_config.cycles_num, /* 循环次数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
uart_receive_data(12, 500);
if(0 == g_rx_buff[9])
{
printf("指示灯设置成功\r\n");
FPM383_sleep();
return COM_OK;
}
else
{
printf("指示灯设置失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return COM_ERROR;
}
}
/* 七彩呼吸灯 */
typedef struct
{
uint8_t timebit; /* 时间位(0.1s~10.0s,范围1~100) */
uint8_t colors[5]; /* 颜色码数组,每个字节分为2个4位单元 */
uint8_t cycles_num; /* 循环次数 */
}colorful_breathing_config_t;
/**
* @brief 七彩呼吸灯
*
* @param colorful_breathing_config: 七彩呼吸灯配置
* 每个字节的颜色码分成 2 个单元,每个单元有 4位,从高位开始分为一个有效位,和 3 个颜色控制位。
* 每个单元控制某种颜色的灯从灭到亮,再到灭的过程。
* 另外,编程后的呼吸灯 1 次循环点亮顺序是从颜色 1 的单元 1 开始,
* 然后是颜色 1的单元 2,接着是颜色 2 的单元 1,以此类推。
* @param cyclesNum: 循环次数
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_colorful_breathing_light(colorful_breathing_config_t colorful_breathing_config)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X0B, /* 包长度 */
0X3C, /* 指令码 */
LED_MODE_RAINBOW_BREATHING, /* 功能码 */
colorful_breathing_config.timebit, /* 时间位 */
colorful_breathing_config.colors[0], /* 颜色1 */
colorful_breathing_config.colors[1], /* 颜色2 */
colorful_breathing_config.colors[2], /* 颜色3 */
colorful_breathing_config.colors[3], /* 颜色4 */
colorful_breathing_config.colors[4], /* 颜色5 */
colorful_breathing_config.cycles_num, /* 循环次数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 接收应答包 */
uart_receive_data(12, 500);
if(0 == g_rx_buff[9])
{
printf("七彩呼吸灯设置成功\r\n");
FPM383_sleep();
return COM_OK;
}
else
{
printf("七彩呼吸灯设置失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return COM_ERROR;
}
}
1.13 读索引表PS_ReadIndexTable

代码
/**
* @brief 读取索引表
*
* @param pageID: 页码
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_read_index_table(uint8_t pageID)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X04, /* 包长度 */
0X1F, /* 指令码 */
pageID, /* 页码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd,sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(44,3000);
if(g_rx_buff[9] == 0)
{
printf("读取索引表成功\r\n");
memcpy(IDIndxTable, &g_rx_buff[10], 32);
// for(uint8_t i = 0;i < 32;i++)
// {
// printf("模板%d-%d的录取情况: %x\r\n",i * 8,(i + 1) * 8 - 1,
// g_rx_buff[10 + i]);
// }
FPM383_sleep();
return CMD_SUCCESS;
}
else
{
printf("读取索引表失败 确认码: %x\r\n",g_rx_buff[9]);
FPM383_sleep();
return CMD_FAILED;
}
}
2.模块指令集
2.1 自动注册模板PS_AutoEnro

代码
/**
* @brief 自动注册指纹
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_auto_register_fingerprint(void)
{
uint8_t i = 1;
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X08, /* 包长度 */
0X31, /* 指令码 */
g_pageID_inidx >> 8,g_pageID_inidx & 0xFF, /* ID号 */
ENTRY_NUM, /* 录入次数 */
0X00,0X12, /* 参数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 指令合法验证 */
FPM383_auto_verify_reply(0x00, 0x00);
while(i < ENTRY_NUM + 1)
{
/* 获取指纹图像 */
if(COM_OK != FPM383_auto_verify_reply(0x01, i))
goto err;
/* 生成特征 */
if(COM_OK != FPM383_auto_verify_reply(0x02, i))
goto err;
/* 手指离开 */
if(COM_OK != FPM383_auto_verify_reply(0x03, i))
goto err;
i++;
}
/* 合成模板 */
if(COM_OK != FPM383_auto_verify_reply(0x04, 0xF0))
goto err;
/* 指纹重复检测 */
if(COM_OK != FPM383_auto_verify_reply(0x05, 0xF1))
goto err;
/* 登记模板成功 */
if(COM_OK != FPM383_auto_verify_reply(0x06, 0xF2))
goto err;
printf("注册指纹成功");
FPM383_sleep();
return COM_ERROR;
err:
printf("注册指纹失败");
FPM383_sleep();
return COM_ERROR;
}
2.2 自动验证指纹PS_AutoIdentify

代码
/**
* @brief 自动验证指纹
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_auto_verify_fingerprint(void)
{
uint16_t pageID = 0;
uint8_t matchScore = 0;
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X08, /* 包长度 */
0X32, /* 指令码 */
0x03, /* 分数等级 */
0xFF,0xFF, /* ID号 */
0X00,0X02, /* 参数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 指令合法验证 */
FPM383_auto_verify_reply(0x00, 0x00);
/* 获取指纹图像成功 */
if(COM_OK != FPM383_auto_verify_reply(0x00, 0x01))
goto err;
/* 生成特征成功,指纹对比成功 */
if(COM_OK != FPM383_auto_verify_reply(0x00, 0x05))
goto err;
pageID = ((g_rx_buff[10] << 8) | (g_rx_buff[11] & 0xFF));
matchScore = g_rx_buff[12];
printf("指纹验证成功 指纹所在页: %x,\
和指纹库对比得分: %x\r\n",pageID,
matchScore);
FPM383_sleep();
return COM_ERROR;
err:
printf("验证指纹失败");
FPM383_sleep();
return COM_ERROR;
}
2.3 取消指令PS_Cancel

代码
/**
* @brief 取消指令
*
* @param 无
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_cancel_cmd(void)
{
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X03, /* 包长度 */
0X30, /* 指令码 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd,sizeof(cmd));
/* 发送指令 */
FPM383_send_data(cmd,sizeof(cmd));
/* 接收应答包 */
FPM383_receive_data(12, 500);
if(g_rx_buff[9] == 0)
{
printf("取消指令成功\r\n");
FPM383_sleep();
return CMD_SUCCESS;
}
else
{
printf("取消指令失败 确认码: %x\r\n", g_rx_buff[9]);
FPM383_sleep();
return CMD_FAILED;
}
}
五. 通用指令通信流程
1. 通用指令注册指纹流程

代码
/**
* @brief 注册指纹
*
* @param 无
*
* @return Command_Status: 成功或失败
*/
Command_Status FPM383_register_fingerprint(void)
{
uint8_t BufferID = 1;
while( BufferID < 6)
{
/* 获取指纹图像 */
if(FPM383_get_image() != CMD_SUCCESS)
goto err;
/* 生成特征 */
if(FPM383_generate_feature(BufferID++) != CMD_SUCCESS)
goto err;
}
/* 合并特征 */
if(FPM383_merge_feature() != CMD_SUCCESS)
goto err;
/* 存储模板 */
if(FPM383_storage_template() != CMD_SUCCESS)
goto err;
printf("指纹录入成功\r\n");
/* 睡眠 */
FPM383_sleep();
return CMD_SUCCESS;
err:
printf("指纹录入失败\r\n");
FPM383_sleep();
return CMD_FAILED;
}
2. 通用指令验证指纹流程

代码
/**
* @brief 验证指纹
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_verify_fingerprint(uint16_t *pageID)
{
uint16_t matchScore = 0;
/* 获取指纹图像 */
if(COM_OK != FPM383_get_image())
goto err;
/* 生成特征 */
if(COM_OK != FPM383_generate_feature(0x01))
goto err;
/* 搜索指纹 */
if(COM_OK != FPM383_search_fingerprint(pageID, &matchScore))
goto err;
printf("指纹验证成功 指纹所在页: %x,\
和指纹库对比得分: %x\r\n", *pageID,
matchScore);
/* 睡眠 */
FPM383_sleep();
return COM_OK;
err:
printf("指纹验证失败");
FPM383_sleep();
return COM_ERROR;
}
6. 模块指令通信流程
1. 自动注册模板流程

代码
/**
* @brief 自动注册指纹
*
* @param 无
*
* @return com_status_t: 成功或失败
*/
com_status_t FPM383_auto_register_fingerprint(void)
{
uint8_t i = 1;
uint8_t cmd[] =
{
0xEF,0X01, /* 包头 */
0XFF,0XFF,0XFF,0XFF, /* 设备地址 */
0X01, /* 包标识 */
0X00,0X08, /* 包长度 */
0X31, /* 指令码 */
g_pageID_inidx >> 8,g_pageID_inidx & 0xFF, /* ID号 */
ENTRY_NUM, /* 录入次数 */
0X00,0X12, /* 参数 */
0X00,0X00, /* 校验和 */
};
/* 计算校验和 */
FPM383_checkSum(cmd, sizeof(cmd));
/* 发送指令 */
uart_send_data(cmd, sizeof(cmd));
/* 指令合法验证 */
FPM383_auto_verify_reply(0x00, 0x00);
while(i < ENTRY_NUM + 1)
{
/* 获取指纹图像 */
if(COM_OK != FPM383_auto_verify_reply(0x01, i))
goto err;
/* 生成特征 */
if(COM_OK != FPM383_auto_verify_reply(0x02, i))
goto err;
/* 手指离开 */
if(COM_OK != FPM383_auto_verify_reply(0x03, i))
goto err;
i++;
}
/* 合成模板 */
if(COM_OK != FPM383_auto_verify_reply(0x04, 0xF0))
goto err;
/* 指纹重复检测 */
if(COM_OK != FPM383_auto_verify_reply(0x05, 0xF1))
goto err;
/* 登记模板成功 */
if(COM_OK != FPM383_auto_verify_reply(0x06, 0xF2))
goto err;
printf("注册指纹成功");
FPM383_sleep();
return COM_ERROR;
err:
printf("注册指纹失败");
FPM383_sleep();
return COM_ERROR;
}
七. 常见错误
1. 卡死在睡眠
- 两条睡眠指令发送时间不能太进,否则会进不去睡眠,卡死在睡眠
- 断电重插一下,解决%99问题。
2.接收失败错误码0x01
-
检查校验和失是否错误
校验和 = 从包标识至校验和之间所有字节之和,包含包标识不包含校验和,超出 2 字节的进位忽略

-
接收应答包数据长度错误

-
接收数据等待时间太短,增加等待时间。


浙公网安备 33010602011771号