Skip to content

由 WT_0213 贡献,Ai-Thinker 进行整理

【外设移植】Ai-WB2+FPM383C指纹


) 关于 FPM383C 指纹模块 在之前的帖子介绍的已经比较详细了可以看下这个帖子 > 【外设移植】FPM383C指纹模块+Ai-M61-32S > ) 这里主要说一下移植FPM383C指纹到Ai-WB2模块时遇到的一些问题和移植完成示例 首先是环境搭建 > 【Ai-WB2入门篇】搭建windows+eclipse环境 > 跟着园长的教程完成环境搭建基本不会出现什么意外情况,都可以正常跑起来。 如果跑不起来检查下哪里与教程不同 这里有个小坑需要注意 尽量使用克隆命令克隆项目,不要直接下载zip > git clone --recursive [https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2](https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2) 如果对配置文件不熟悉的话尽量按照现有的一些目录接口创建自己的项目这样可以尽可能少的去修改配置文件 > 如果在其他目录下创建项目,需要注意的是BL60X_SDK_PATH这个值要能找到sdkpath ![目录结构.PNG](/img/bbsdiy/ai_wb2/af08db8dd0dadda5.png){width=600} 编译过程有一些警告,如果不是自己代码中的可以忽略。 如果编译通过的话最终会生成bin文件 ![烧录文件.PNG](/img/bbsdiy/ai_wb2/19df3d7537266bed.png){width=600} 下一步就是烧录过程 > Ai-WB2烧录软件 > > [[https://docs.ai-thinker.com/](https://docs.ai-thinker.com/)\_media/bl602\_flash\_download\_tool.zip]([https://docs.ai-thinker.com/_media/bl602_flash_download_tool.zip](https://docs.ai-thinker.com/_media/bl602_flash_download_tool.zip)) 烧录过程参考 > 【Ai-WB2入门篇】新建工程和烧录指导 这里有小坑需要注意一下 ![拒绝访问.PNG](/img/bbsdiy/ai_wb2/00543a72c497c5e2.png){width=600} > 1、如果出现COM口拒绝访问,检查下时候开启的串口调试工具。 > > 2、如果提示BFLB IMG LOAD SHAKEHAND FAIL应该是没有进入烧录模式,点击Create & Download 然后按住开发板右侧的按钮,再点按左侧EN按钮松手就可以了。 **这里有大坑需要注意一下** ![烧录.PNG](/img/bbsdiy/ai_wb2/d07324b3cfab5022.png){width=600} 烧录编译的bin的时候需要使用这种烧录方式进项烧录,否则烧录后程序不能正常运行。 > 序号1、3、4选择的都是烧录工具目录下的文件 > > 序号 2 选择编译的bin即可 烧录完成后,开启串口调试工具 波特率设置为115200 ![结果.PNG](/img/bbsdiy/ai_wb2/64335aa8fc421c7a.png) 这里日志通过 printf方法打印出来的,不知道为啥blog_info不生效没有深入去看 然后是代码部分
📜 点击展开完整代码
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <bl_gpio.h>
#include "fpm383c.h"
#include <blog.h>
int is_register = 1;
int main(void) {
printf("\r\n");
// 初始化FPM383C指纹模块
fpm383c_init();
printf("clear \r\n");
// 清空指纹库
fpm383c_empty(2000);
printf("random id\r\n");
// 指纹id
int fpm383cPageId = 10;
while (1) {
if (is_register) {
// 开启注册指纹,指纹ID:0—59, 超时时间尽量在 10秒左右,需要录入四次
fpm383c_enroll(fpm383cPageId, 10000);
// 休息600毫秒进行下次注册
vTaskDelay(pdMS_TO_TICKS(600));
// 模块休眠一下
fpm383c_sleep();
is_register = 0;
printf("register OK\r\n");
} else {
// printf("identify\r\n");
// 开启自动识别
fpm383c_identify();
}
vTaskDelay(pdMS_TO_TICKS(10));
}
return 0;
}

这里值得注意的是int main(void)函数是有返回值的,返回值类型为 int 这个函数会在会执行在FreeRTOS任务中可以看下这篇分析的帖子

wb2项目启动流程分析 fpm383c.h

📜 点击展开完整代码
#ifndef __FPM383C_H
#define __FPM383C_H
#include "stdint.h"
void fpm383c_init(void);
void fpm383c_senddata(int length, uint8_t buffer[]);
void fpm383c_sleep(void);
uint8_t fpm383c_getimage(uint32_t timeout);
uint8_t fpm383c_genchar(uint32_t timeout);
uint8_t fpm383c_search(uint32_t timeout);
uint8_t fpm383c_empty(uint32_t timeout);
uint8_t fpm383c_delete(uint16_t pageID,uint32_t timeout);
uint8_t fpm383c_controlled(uint8_t PS_ControlLEDBuf[],uint32_t timeout);
void fpm383c_identify(void);
void fpm383c_enroll(uint16_t pageID,uint16_t timeout);
#endif

fpm383c.c

📜 点击展开完整代码
#include "stdlib.h"
#include "string.h"
#include "bl_sys.h"
#include <stdio.h>
#include <cli.h>
#include <hosal_uart.h>
#include <blog.h>
#include <hosal_uart.h>
#include <stdint.h>
#include <FreeRTOS.h>
#include <bl_gpio.h>
#include <blog.h>
#include "fpm383c.h"
#define GPIO_LED_PIN 14
/**
* 控制模块LED灯颜色
*/
uint8_t ps_blueledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
uint8_t ps_redledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
uint8_t ps_greenledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};
/**
* 休眠指令-设置传感器进入休眠模式
*/
uint8_t ps_sleepbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};
/**
* 清空指纹库-删除 flash 数据库中所有指纹模板。
*/
uint8_t ps_emptybuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};
/**
* 取消指令-取消自动注册模板和自动验证指纹。如表 2-1 中加密等级设置为 0 或 1 情况下支持此功能
*/
uint8_t ps_cancelbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};
/**
* 自动注册模板-一站式注册指纹,包含采集指纹、生成特征、组合模板、存储模板等功能。加密等级设置为 0 或 1 情况下支持此功能。
*/
uint8_t ps_autoenrollbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0',0x04,0x00,0x16,'\0','\0'};
/**
* 验证用获取图像-验证指纹时,探测手指,探测到后录入指纹图像存于图像缓冲区。返回确认码表示:录入成功、无手指等。
*/
uint8_t ps_getimagebuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};
/**
* 生成特征值-将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
*/
uint8_t ps_getcharbuf[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};
/**
* 搜索指纹-以模板缓冲区中的特征文件搜索整个或部分指纹库。若搜索到,则返回页码。加密等级设置为 0 或 1 情况下支持
*/
uint8_t ps_searchbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};
/**
* 删除模板-删除 flash 数据库中指定 ID 号开始的N 个指纹模板
*/
uint8_t ps_deletebuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};
/**
* 设置名为fpm383c_uart的外设句柄,用来执行串口指令的发送
*/
hosal_uart_dev_t fpm383c_uart = {
.config = {
.uart_id = 1,
.tx_pin = 4, // TXD GPIO
.rx_pin = 3, // RXD GPIO
.baud_rate = 57600,
.data_width = HOSAL_DATA_WIDTH_8BIT,
.parity = HOSAL_NO_PARITY,
.stop_bits = HOSAL_STOP_BITS_1,
.mode = HOSAL_UART_MODE_POLL,
},
};
/**
* 指纹ID和验证指纹的分数
*/
uint16_t pageID,score;
/**
* USART串口接收缓冲数组
*/
uint8_t uart_receivebuf[20];
/**
* 主循环状态标志位
*/
uint8_t scanstatus = 0;
/**
* @brief 获取状态
*
* @param timeout
*/
void fpm383c_receivedata(uint16_t timeout, uint8_t lenght)
{
// 轮询fpm383c_uart接收到的字符
int ret;
uint8_t uart_receive_len = 0;
uint8_t receivebuf_cache[20];
memset(uart_receivebuf, 0xFF, sizeof(uart_receivebuf));
while(true){
ret = hosal_uart_receive(&fpm383c_uart, receivebuf_cache, sizeof(receivebuf_cache));
if (ret > 0) {
memcpy(uart_receivebuf + uart_receive_len, receivebuf_cache, ret);
uart_receive_len += ret;
/* Uart send poll */
if(uart_receive_len >= lenght){
uart_receive_len=0;
break;
}
vTaskDelay(1);
}
/**
* 初始化FPM383C指纹模块
*/
void fpm383c_init(){
/* Uart init device */
hosal_uart_init(&fpm383c_uart);
printf("fpm383c_init\r\n");
}
/**
* USART串口发送数据
* @param length 发送数组长度
* @param fpm383c_databuf 需要发送的功能数组
*/
void fpm383c_senddata(int length, uint8_t fpm383c_databuf[])
{
hosal_uart_send(&fpm383c_uart, fpm383c_databuf, length);
}
/**
* 发送休眠指令 确认码=00H 表示休眠设置成功。确认码=01H 表示休眠设置失败。
*/
void fpm383c_sleep(void)
{
fpm383c_senddata(12, ps_sleepbuf);
}
/**
* 验证用获取图像
* @param timeout接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_getimage(uint32_t timeout)
{
uint8_t tmp;
fpm383c_senddata(12,ps_getimagebuf);
fpm383c_receivedata(timeout, 12);
tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return tmp;
}
/**
* 将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
* @param timeout 接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_genchar(uint32_t timeout)
{
uint8_t tmp;
fpm383c_senddata(13,ps_getcharbuf);
fpm383c_receivedata(timeout, 12);
tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return tmp;
}
/**
* 发送搜索指纹指令
* @param timeout 接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_search(uint32_t timeout)
{
fpm383c_senddata(17,ps_searchbuf);
fpm383c_receivedata(timeout, 16);
return (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
}
/**
* 删除指定指纹指令
* @param pageID 需要删除的指纹
* @param timeout 接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_delete(uint16_t pageID,uint32_t timeout)
{
uint8_t tmp;
ps_deletebuf[10] = (pageID>>8);
ps_deletebuf[11] = (pageID);
ps_deletebuf[14] = (0x15+ps_deletebuf[10]+ps_deletebuf[11])>>8;
ps_deletebuf[15] = (0x15+ps_deletebuf[10]+ps_deletebuf[11]);
fpm383c_senddata(16,ps_deletebuf);
fpm383c_receivedata(timeout, 12);
tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return tmp;
}
/**
* 清空指纹库
* @param timeout 接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_empty(uint32_t timeout)
{
uint8_t tmp;
fpm383c_senddata(12,ps_emptybuf);
fpm383c_receivedata(timeout, 12);
tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return tmp;
}
/**
* 发送控制灯光指令
* @param ps_controlledbuf 不同颜色的协议数据
* @param timeout 接收数据的超时时间
* @return 确认码
*/
uint8_t fpm383c_controlled(uint8_t ps_controlledbuf[],uint32_t timeout)
{
uint8_t tmp;
fpm383c_senddata(16,ps_controlledbuf);
fpm383c_receivedata(timeout, 12);
tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return tmp;
}
/**
* 验证指纹是否注册
*/
void fpm383c_identify(void)
{
if(fpm383c_getimage(2000) == 0x00)
{
if(fpm383c_genchar(2000) == 0x00)
{
bl_gpio_enable_output(GPIO_LED_PIN, 0, 0);
bl_gpio_output_set(GPIO_LED_PIN, 0);
if(fpm383c_search(2000) == 0x00)
{
score = (int)((uart_receivebuf[10] << 8) + uart_receivebuf[11]);
printf("success ID: %d \r\n",(int)score);
fpm383c_controlled(ps_greenledbuf,1000);
bl_gpio_output_set(GPIO_LED_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
bl_gpio_output_set(GPIO_LED_PIN, 0);
// 重置接收数据缓存
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return;
}else{
printf("fail \r\n");
bl_gpio_output_set(GPIO_LED_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
bl_gpio_output_set(GPIO_LED_PIN, 0);
// 重置接收数据缓存
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return;
}
/**
* 自动注册
* @param pageID 输入需要注册的指纹ID号,取值范围0—59
* @param timeout 设置注册指纹超时时间,因为需要按压四次手指,建议大于10000(即10s)
*/
void fpm383c_enroll(uint16_t pageID,uint16_t timeout)
{
blog_info("注册指纹ID: %d\r\n", pageID);
ps_autoenrollbuf[10] = (pageID>>8);
ps_autoenrollbuf[11] = (pageID);
ps_autoenrollbuf[15] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11])>>8;
ps_autoenrollbuf[16] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11]);
fpm383c_senddata(17,ps_autoenrollbuf);
fpm383c_receivedata(timeout, 14);
if(uart_receivebuf[9] == 0x00)
{
blog_info("指纹注册完成\r\n");
// 亮绿灯2秒
fpm383c_controlled(ps_greenledbuf,2000);
// 重置接收数据缓存
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
return;
}
else if(timeout == 0)
{
// 超时取消注册
fpm383c_senddata(12,ps_cancelbuf);
vTaskDelay(pdMS_TO_TICKS(50));
// 重置接收数据缓存
memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
}
// 亮红灯2秒
fpm383c_controlled(ps_redledbuf,2000);
}

以上就是主要逻辑代码 FPM383c.png 接线方式 WechatIMG15.jpg

Ai-WB2-12FFPM383C
3V3PIN3
GNDPIN6
IO3TX
IO4RX
由于复用的IO3所以蓝灯会亮
其他Ai-WB2相关知识可以看看园长整理的这篇文章
【Ai-WB2教程合集】看这一篇就够了!!

)

关于 FPM383C 指纹模块 在之前的帖子介绍的已经比较详细了可以看下这个帖子

【外设移植】FPM383C指纹模块+Ai-M61-32S

)

这里主要说一下移植FPM383C指纹到Ai-WB2模块时遇到的一些问题和移植完成示例

首先是环境搭建

【Ai-WB2入门篇】搭建windows+eclipse环境

跟着园长的教程完成环境搭建基本不会出现什么意外情况,都可以正常跑起来。

如果跑不起来检查下哪里与教程不同

这里有个小坑需要注意

尽量使用克隆命令克隆项目,不要直接下载zip

git clone --recursive <https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2>

如果对配置文件不熟悉的话尽量按照现有的一些目录接口创建自己的项目这样可以尽可能少的去修改配置文件

如果在其他目录下创建项目,需要注意的是BL60X_SDK_PATH这个值要能找到sdkpath

编译过程有一些警告,如果不是自己代码中的可以忽略。

如果编译通过的话最终会生成bin文件

下一步就是烧录过程

Ai-WB2烧录软件

[<https://docs.ai-thinker.com/>_media/bl602_flash_download_tool.zip](https://docs.ai-thinker.com/_media/bl602_flash_download_tool.zip)

烧录过程参考

【Ai-WB2入门篇】新建工程和烧录指导

这里有小坑需要注意一下

1、如果出现COM口拒绝访问,检查下时候开启的串口调试工具。

2、如果提示BFLB IMG LOAD SHAKEHAND FAIL应该是没有进入烧录模式,点击Create & Download 然后按住开发板右侧的按钮,再点按左侧EN按钮松手就可以了。

这里有大坑需要注意一下

烧录编译的bin的时候需要使用这种烧录方式进项烧录,否则烧录后程序不能正常运行。

序号1、3、4选择的都是烧录工具目录下的文件

序号 2 选择编译的bin即可

烧录完成后,开启串口调试工具

波特率设置为115200

这里日志通过 printf方法打印出来的,不知道为啥blog_info不生效没有深入去看

然后是代码部分

📜 点击展开完整代码
c
#include <stdio.h>

#include <FreeRTOS.h>

#include <task.h>

#include <bl_gpio.h>

#include "fpm383c.h"
#include <blog.h>

int is_register = 1;

int main(void) {

	printf("\r\n");
	// 初始化FPM383C指纹模块
	fpm383c_init();
	printf("clear \r\n");
	// 清空指纹库
	fpm383c_empty(2000);
	printf("random id\r\n");
	// 指纹id
	int fpm383cPageId = 10;
	while (1) {
		if (is_register) {
			// 开启注册指纹,指纹ID:0—59, 超时时间尽量在 10秒左右,需要录入四次
			fpm383c_enroll(fpm383cPageId, 10000);
			// 休息600毫秒进行下次注册
			vTaskDelay(pdMS_TO_TICKS(600));
			// 模块休眠一下
			fpm383c_sleep();
			is_register = 0;
			printf("register OK\r\n");
		} else {
//			printf("identify\r\n");
			// 开启自动识别
			fpm383c_identify();
		}
		vTaskDelay(pdMS_TO_TICKS(10));
	}
	return 0;
}

这里值得注意的是int main(void)函数是有返回值的,返回值类型为 int

这个函数会在会执行在FreeRTOS任务中可以看下这篇分析的帖子

wb2项目启动流程分析

fpm383c.h

📜 点击展开完整代码
c
#ifndef __FPM383C_H
#define __FPM383C_H

#include "stdint.h"

void fpm383c_init(void);
void fpm383c_senddata(int length, uint8_t buffer[]);
void fpm383c_sleep(void);

uint8_t fpm383c_getimage(uint32_t timeout);
uint8_t fpm383c_genchar(uint32_t timeout);
uint8_t fpm383c_search(uint32_t timeout);
uint8_t fpm383c_empty(uint32_t timeout);
uint8_t fpm383c_delete(uint16_t pageID,uint32_t timeout);
uint8_t fpm383c_controlled(uint8_t PS_ControlLEDBuf[],uint32_t timeout);
void fpm383c_identify(void);
void fpm383c_enroll(uint16_t pageID,uint16_t timeout);

#endif

fpm383c.c

📜 点击展开完整代码
c
#include "stdlib.h"
#include "string.h"
#include "bl_sys.h"
#include <stdio.h>

#include <cli.h>

#include <hosal_uart.h>

#include <blog.h>

#include <hosal_uart.h>

#include <stdint.h>

#include <FreeRTOS.h>

#include <bl_gpio.h>

#include <blog.h>

#include "fpm383c.h"

#define GPIO_LED_PIN 14

/**
 * 控制模块LED灯颜色
 */
uint8_t ps_blueledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
uint8_t ps_redledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
uint8_t ps_greenledbuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};

/**
 * 休眠指令-设置传感器进入休眠模式
 */
uint8_t ps_sleepbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};

/**
 * 清空指纹库-删除 flash 数据库中所有指纹模板。
 */
uint8_t ps_emptybuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};

/**
 * 取消指令-取消自动注册模板和自动验证指纹。如表 2-1 中加密等级设置为 0 或 1 情况下支持此功能
 */
uint8_t ps_cancelbuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};

/**
 * 自动注册模板-一站式注册指纹,包含采集指纹、生成特征、组合模板、存储模板等功能。加密等级设置为 0 或 1 情况下支持此功能。
 */
uint8_t ps_autoenrollbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0',0x04,0x00,0x16,'\0','\0'};

/**
 * 验证用获取图像-验证指纹时,探测手指,探测到后录入指纹图像存于图像缓冲区。返回确认码表示:录入成功、无手指等。
 */
uint8_t ps_getimagebuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};

/**
 * 生成特征值-将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
 */
uint8_t ps_getcharbuf[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};

/**
 * 搜索指纹-以模板缓冲区中的特征文件搜索整个或部分指纹库。若搜索到,则返回页码。加密等级设置为 0 或 1 情况下支持
 */
uint8_t ps_searchbuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};

/**
 * 删除模板-删除 flash 数据库中指定 ID 号开始的N 个指纹模板
 */
uint8_t ps_deletebuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};

/**
 * 设置名为fpm383c_uart的外设句柄,用来执行串口指令的发送
 */
hosal_uart_dev_t fpm383c_uart = {
       .config = {
           .uart_id = 1,
           .tx_pin = 4, // TXD GPIO
           .rx_pin = 3,  // RXD GPIO
           .baud_rate = 57600,
           .data_width = HOSAL_DATA_WIDTH_8BIT,
           .parity = HOSAL_NO_PARITY,
           .stop_bits = HOSAL_STOP_BITS_1,
           .mode = HOSAL_UART_MODE_POLL,
       },
   };

/**
 * 指纹ID和验证指纹的分数
 */
uint16_t pageID,score;

/**
 * USART串口接收缓冲数组
 */
uint8_t uart_receivebuf[20];

/**
 * 主循环状态标志位
 */
uint8_t scanstatus = 0;

/**
 * @brief 获取状态
 *
 * @param timeout
 */
void fpm383c_receivedata(uint16_t timeout, uint8_t lenght)
{
	// 轮询fpm383c_uart接收到的字符
	int ret;
	uint8_t uart_receive_len = 0;
	uint8_t receivebuf_cache[20];
	memset(uart_receivebuf, 0xFF, sizeof(uart_receivebuf));
	while(true){
		ret = hosal_uart_receive(&fpm383c_uart, receivebuf_cache, sizeof(receivebuf_cache));
		if (ret > 0) {
			memcpy(uart_receivebuf + uart_receive_len, receivebuf_cache, ret);
			uart_receive_len += ret;
			/* Uart send poll */
			if(uart_receive_len >= lenght){
				uart_receive_len=0;
				break;
			}
		}
		vTaskDelay(1);
	}

}

/**
 * 初始化FPM383C指纹模块
 */
void fpm383c_init(){
    /* Uart init device */
    hosal_uart_init(&fpm383c_uart);
    printf("fpm383c_init\r\n");
}

/**
 * USART串口发送数据
 * @param length 发送数组长度
 * @param fpm383c_databuf 需要发送的功能数组
 */
void fpm383c_senddata(int length, uint8_t fpm383c_databuf[])
{
	hosal_uart_send(&fpm383c_uart, fpm383c_databuf, length);
}

/**
 * 发送休眠指令 确认码=00H 表示休眠设置成功。确认码=01H 表示休眠设置失败。
 */
void fpm383c_sleep(void)
{
	fpm383c_senddata(12, ps_sleepbuf);
}

/**
 * 验证用获取图像
 * @param timeout接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_getimage(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(12,ps_getimagebuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_genchar(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(13,ps_getcharbuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 发送搜索指纹指令
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_search(uint32_t timeout)
{
	fpm383c_senddata(17,ps_searchbuf);
	fpm383c_receivedata(timeout, 16);
	return (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
}

/**
 * 删除指定指纹指令
 * @param pageID 需要删除的指纹
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_delete(uint16_t pageID,uint32_t timeout)
{
	uint8_t tmp;
	ps_deletebuf[10] = (pageID>>8);
	ps_deletebuf[11] = (pageID);
	ps_deletebuf[14] = (0x15+ps_deletebuf[10]+ps_deletebuf[11])>>8;
	ps_deletebuf[15] = (0x15+ps_deletebuf[10]+ps_deletebuf[11]);
	fpm383c_senddata(16,ps_deletebuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 清空指纹库
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_empty(uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(12,ps_emptybuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 发送控制灯光指令
 * @param ps_controlledbuf 不同颜色的协议数据
 * @param timeout 接收数据的超时时间
 * @return 确认码
 */
uint8_t fpm383c_controlled(uint8_t ps_controlledbuf[],uint32_t timeout)
{
	uint8_t tmp;
	fpm383c_senddata(16,ps_controlledbuf);
	fpm383c_receivedata(timeout, 12);
	tmp = (uart_receivebuf[6] == 0x07 ? uart_receivebuf[9] : 0xFF);
	memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	return tmp;
}

/**
 * 验证指纹是否注册
 */
void fpm383c_identify(void)
{
	if(fpm383c_getimage(2000) == 0x00)
	{
		if(fpm383c_genchar(2000) == 0x00)
		{
			bl_gpio_enable_output(GPIO_LED_PIN, 0, 0);
			bl_gpio_output_set(GPIO_LED_PIN, 0);
			if(fpm383c_search(2000) == 0x00)
			{
				score = (int)((uart_receivebuf[10] << 8) + uart_receivebuf[11]);
				printf("success ID: %d \r\n",(int)score);
				fpm383c_controlled(ps_greenledbuf,1000);

				bl_gpio_output_set(GPIO_LED_PIN, 1);
				vTaskDelay(pdMS_TO_TICKS(1000));
				bl_gpio_output_set(GPIO_LED_PIN, 0);
				// 重置接收数据缓存
				memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
				return;
			}else{
				printf("fail \r\n");
				bl_gpio_output_set(GPIO_LED_PIN, 1);
				vTaskDelay(pdMS_TO_TICKS(1000));
				bl_gpio_output_set(GPIO_LED_PIN, 0);
				// 重置接收数据缓存
				memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
				return;
			}
		}
	}
}

/**
 * 自动注册
 * @param pageID 输入需要注册的指纹ID号,取值范围0—59
 * @param timeout 设置注册指纹超时时间,因为需要按压四次手指,建议大于10000(即10s)
 */
void fpm383c_enroll(uint16_t pageID,uint16_t timeout)
{
	blog_info("注册指纹ID: %d\r\n", pageID);
	ps_autoenrollbuf[10] = (pageID>>8);
	ps_autoenrollbuf[11] = (pageID);
	ps_autoenrollbuf[15] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11])>>8;
	ps_autoenrollbuf[16] = (0x54+ps_autoenrollbuf[10]+ps_autoenrollbuf[11]);
	fpm383c_senddata(17,ps_autoenrollbuf);
	fpm383c_receivedata(timeout, 14);
	if(uart_receivebuf[9] == 0x00)
	{
		blog_info("指纹注册完成\r\n");
		// 亮绿灯2秒
		fpm383c_controlled(ps_greenledbuf,2000);
		// 重置接收数据缓存
		memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
		return;
	}
	else if(timeout == 0)
	{
		// 超时取消注册
		fpm383c_senddata(12,ps_cancelbuf);
		vTaskDelay(pdMS_TO_TICKS(50));
		// 重置接收数据缓存
		memset(uart_receivebuf,0xFF,sizeof(uart_receivebuf));
	}
	// 亮红灯2秒
	fpm383c_controlled(ps_redledbuf,2000);
}

以上就是主要逻辑代码

接线方式

Ai-WB2-12FFPM383C
3V3PIN3
GNDPIN6
IO3TX
IO4RX

由于复用的IO3所以蓝灯会亮

其他Ai-WB2相关知识可以看看园长整理的这篇文章

【Ai-WB2教程合集】看这一篇就够了!!

Released under the MIT License. Build Time 2026-09-11 14:52:23