以下作品由安信可社区用户
WT_0213制作
关于 FPM383C 指纹模块 在之前的帖子介绍的已经比较详细了可以看下这个帖子。
【外设移植】FPM383C 指纹模块 +Ai-M61-32S
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43963&fromuid=15918
这里主要说一下移植 FPM383C 指纹到 Ai-WB2 模块时遇到的一些问题和移植完成示例。
首先是环境搭建
【Ai-WB2 入门篇】搭建 windows+eclipse 环境
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45149&fromuid=15918
跟着园长的教程完成环境搭建基本不会出现什么意外情况,都可以正常跑起来。
这里有个小坑需要注意:
尽量使用克隆命令克隆项目,不要直接下载 zip
git clone --recursive
如果对配置文件不熟悉的话尽量按照现有的一些目录接口创建自己的项目这样可以尽可能少的去修改配置文件。
如果在其他目录下创建项目,需要注意的是 BL60X_SDK_PATH 这个值要能找到 sdkpath。

编译过程有一些警告,如果不是自己代码中的可以忽略。
如果编译通过的话最终会生成 bin 文件。

Ai-WB2 烧录软件
https://docs.ai-thinker.com/_media/bl602_flash_download_tool.zip
烧录过程参考
【Ai-WB2 入门篇】新建工程和烧录指导
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45156&fromuid=15918
这里有小坑需要注意一下:

1、如果出现 COM 口拒绝访问,检查下时候开启的串口调试工具。
2、如果提示 BFLB IMG LOAD SHAKEHAND FAIL 应该是没有进入烧录模式,点击 Create & Download 然后按住开发板右侧的按钮,再点按左侧 EN 按钮松手就可以了。
这里有大坑需要注意一下:

烧录编译的 bin 的时候需要使用这种烧录方式进项烧录,否则烧录后程序不能正常运行。
序号 1、3、4 选择的都是烧录工具目录下的文件
序号 2 选择编译的 bin 即可
烧录完成后,开启串口调试工具
波特率设置为 115200

这里日志通过 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");// 指纹idint 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 项目启动流程分析
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45352&fromuid=15918
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);}
以上就是主要逻辑代码

接线方式

Ai-WB2-12F |
FPM383C |
3V3 |
PIN3 |
GND |
PIN6 |
IO3 |
TX |
IO4 |
RX |
由于复用的 IO3 所以蓝灯会亮
其他 Ai-WB2 相关知识可以看看社区整理的这篇文章
【Ai-WB2 教程合集】看这一篇就够了!!
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45314&fromuid=15918
微信改版,容易错过最新资讯和福利?
快将“安信可科技”设为星标⭐
可以第一时间接收小安的推送!
▼

10公里!超远距离传输的LoRa模块上架
0.1毫安!超超超超超低功耗雷达模组Rd-03L
安信可更多产品信息可进入以下链接查阅:
●开发资料:https://docs.ai-thinker.com/
●官方教程:https://blog.csdn.net/Boantong_
●安信可官网:www.ai-thinker.com
●安信可社区:https://bbs.ai-thinker.com
●业务咨询请联系:18022036575


