光学指纹识别传感器采用了国内著名指纹识别芯片公司杭州晟元芯片技术有限公司(Synochip) 的 AS608 指纹识别芯片。芯片内置 DSP 运算单元,集成了指纹识别算法,能高效快速采集 图像并识别指纹特征。模块配备了串口、USB 通讯接口,用户无需研究复杂的图像处理及及指纹识别算法,只需通过简单的串口、USB 按照通讯协议便可控制模块。本模块可应用于各种考勤机、保险箱柜、指纹门禁系统、指纹锁等场合。
模块来源
规格参数
工作电压:3.0-3.6V
工作电流:30~60mA
指纹存容量:300 枚(ID:0~299)
认假率:<0.001%
搜索时间:<0.3(S)
控制方式:串口或USB
管脚数量:8 Pin(2.54mm间距排针)
以上信息见厂家资料文件
移植过程
我们的目标是将例程移植至开发板上【实现添加指纹、删除指纹和搜索指纹的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
查看资料
系统内设有一个72K字节的图像缓冲区与二个512bytes大小的特征文件缓冲区,名字分别称为:lmageBuffer
,CharBuffer1
和CharBuffer2
。用户可以通过指令读写任意一个缓冲区。CharBufferl
或 CharBuffer2
既可以用于存放普通特征文件也可以用于存放模板特征文件。通过UART 口上传或下载图像时为了加快速度,只用到像素字节的高4位,即将两个像素合成一个字节传送。通过USB口则是整8位像素。
指纹库容量根据挂接的FLASH容量不同而改变,系统会自动判别。指纹模板按照序号存放,序号定义为:0—(N-1)(N为指纹库容量)。用户只能根据序号访问指纹库内容。
这里我们使用的是串口控制方式,USB的接口我们可以悬空不接。
1脚(红线):模块主电源,接3.3V供电(请勿接3.3V以上电源,否则烧毁模块!);
2脚(黄线):模块串口TX(发送端),接MCU或TTL串口的RX(接收端);
3脚(白线):模块串口RX(接收端),接MCU或TTL串口的TX(发送端);
4脚(黑线):模块电源地,接3.3V电源地(负极);
5脚(蓝线):模块触摸感应信号输出(高电平为检测到触摸),需接VTI到3.3V。
6脚(绿线):模块触摸感应电路电源(3.3V),可以与1脚(红线)并接。
7脚,8脚为USB信号线,使用串口控制模块时可以悬空不用。
引脚选择
这里选择的引脚见引脚接线表
代码移植
下载为大家准备的驱动代码文件夹,复制到自己工程中\luban-lite\application\rt-thread\helloworld\user-bsp
文件夹下
提示
如果未找到 user-bsp
这个文件夹,说明你未进行模块移植的前置操作。请转移到手册使用必要操作(点击跳转)中进行必要的配置操作!!!
接下来打开自己的工程,开始修改Kconfig文件。
1、在 VSCode 中打开 application\rt-thread\helloworld\Kconfig 文件
2、在该文件的 #endif
前面添加该模块的 Kconfig路径语句
# 指纹识别传感器
source "application/rt-thread/helloworld/user-bsp/fingerprint-recognition-sensor/Kconfig"
2
添加完成之后:
menuconfig操作
1、我们 双击 luban-lite
文件夹下的 win_env.bat
脚本打开env工具:
2、输入以下命令列出所有可用的默认配置:
scons --list-def
3、选择 d13x_JLC_rt-thread_helloworld
这个配置!这个是我们衡山派开发板的默认配置!输入以下命令即可:
scons --apply-def=7
或者
scons --apply-def=d13x_JLC_rt-thread_helloworld_defconfig
这两个命令作用是一样的,一个是 文件名 ,一个是 编号 !!!
4、输入以下命令进入menuconfig菜单
scons --menuconfig
进入以下界面:
5、选中 Porting code using the LCKFB module
按
Y
选中按
N
取消选中方向键
左右
调整 最下面菜单的选项方向键
上下
调整 列表的选项
回车
执行最下面菜单的选项
6、回车进入 Porting code using the LCKFB module
菜单
7、按方向键 上下
选中 USE Fingerprint identification sensor (AS608)
后按 Y
键,看到前面括号中出现一个 *
号,就可以下一步了。
8、按方向键 左右
选中 <Save>
然后一路回车
,然后 退出
即可
编译
我们 保存并退出menuconfig菜单 之后,输入以下命令进行编译:
scons
或
scons -j16
-j 用来选择参与编译的核心数: 我这里是选择16
大家可以根据自己的电脑来选择
核心越多编译越快
如果写的数量高于电脑本身,那么就自动按照最高可用的来运行!
镜像烧录
编译完成之后会在 \luban-lite\output\d13x_JLC_rt-thread_helloworld\images
文件夹下生成一个 d13x_JLC_v1.0.0.img
镜像文件!
然后我们烧录镜像,具体的教程请查看:镜像烧录(点击跳转🚀)
到这里完成了,请移步到 最后一节 进行移植验证。
工程代码解析
bsp_as608.c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include <getopt.h>
#include <string.h>
#include <rtthread.h>
#include <aic_core.h>
#include <stdlib.h>
#include <sys/time.h>
#include "hal_adcim.h"
#include "rtdevice.h"
#include "aic_log.h"
#include "hal_gpai.h"
#include <stdio.h>
#include "aic_hal_gpio.h"
#include "bsp_as608.h"
#define SAMPLE_UART_NAME "uart3" // 串口设备名称
#define RCV_BUFF_SIZE_MAX 1024 // 接收最大字节长度
#define WAK_PIN rt_pin_get("PE.14") // DO引脚号获取
#define GET_WAK_IN rt_pin_read(WAK_PIN) // DO引脚状态读取
static struct rt_semaphore rx_sem; // 用于接收消息的信号量
static rt_device_t serial; // 串口设备句柄
static rt_thread_t serial_recv_thread; // 串口接收线程句柄
static char serial_recv_buff[RCV_BUFF_SIZE_MAX]; // 串口接收缓存区
static char serial_recv_flag; // 串口接收标志
static int serial_recv_length; // 接收字节长度
/* ================================================== */
static unsigned char FPM10A_RECEICE_BUFFER[32];
static unsigned int finger_id = 0; // 指纹ID
const unsigned char FPM10A_Get_Device[10] ={0x01,0x00,0x07,0x13,0x00,0x00,0x00,0x00,0x00,0x1b};//口令验证
const unsigned char FPM10A_Pack_Head[6] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF}; //协议包头
const unsigned char FPM10A_Get_Img[6] = {0x01,0x00,0x03,0x01,0x00,0x05}; //获得指纹图像
const unsigned char FPM10A_Get_Templete_Count[6] ={0x01,0x00,0x03,0x1D,0x00,0x21 }; //获得模版总数
const unsigned char FPM10A_Search[11]={0x01,0x00,0x08,0x04,0x01,0x00,0x00,0x03,0xE7,0x00,0xF8}; //搜索指纹搜索范围0 - 999,使用BUFFER1中的特征码搜索
const unsigned char FPM10A_Search_0_9[11]={0x01,0x00,0x08,0x04,0x01,0x00,0x00,0x00,0x13,0x00,0x21}; //搜索0-9号指纹
const unsigned char FPM10A_Img_To_Buffer1[7]={0x01,0x00,0x04,0x02,0x01,0x00,0x08}; //将图像放入到BUFFER1
const unsigned char FPM10A_Img_To_Buffer2[7]={0x01,0x00,0x04,0x02,0x02,0x00,0x09}; //将图像放入到BUFFER2
const unsigned char FPM10A_Reg_Model[6]={0x01,0x00,0x03,0x05,0x00,0x09}; //将BUFFER1跟BUFFER2合成特征模版
const unsigned char FPM10A_Delete_All_Model[6]={0x01,0x00,0x03,0x0d,0x00,0x11};//删除指纹模块里所有的模版
volatile unsigned char FPM10A_Save_Finger[9]={0x01,0x00,0x06,0x06,0x01,0x00,0x0B,0x00,0x19};//将BUFFER1中的特征码存放到指定的位置
/* ================================================== */
void delay_ms(uint64_t ms){ rt_thread_mdelay(ms); }
void delay_us(uint64_t us){ aicos_udelay(us); }
// 中断接收回调函数
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口有数据传入后产生中断,调用此回调函数,释放信号量 */
if (size > 0)
rt_sem_release(&rx_sem);
return RT_EOK;
}
// 串口接收线程入口函数
static void serial_recv_thread_entry(void *param)
{
rt_kprintf("\nserial_recv_thread_entry run ......\n");
while(1)
{
char temp_recv_buff = 0; // 接收临时缓存区
int ret = rt_device_read(serial, 0, &temp_recv_buff, 1);
if(ret < 0) // 出现了错误
{
pr_debug("read() return [%ld] %s\n", rt_get_errno(), rt_strerror(rt_get_errno()));
}
if(ret == 0) // 未接到数据
{
// 重置信号量
rt_sem_control(&rx_sem, RT_IPC_CMD_RESET, RT_NULL);
// 获取信号量,如果没有获取得到则阻塞在这里永远等待。
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
}
if(ret == 1) // 接收到1字节的数据
{
// 防止数据超出缓存区的大小
if(serial_recv_length < RCV_BUFF_SIZE_MAX - 1)
{
// 存入接收缓存区并递增长度
serial_recv_buff[serial_recv_length++] = temp_recv_buff;
// rt_kprintf("%x\n", temp_recv_buff); // 打印接收到的字节,用于调试
}
else
{
// 如果缓冲区已满,则从0开始覆盖旧数据
serial_recv_length = 0;
serial_recv_buff[serial_recv_length++] = temp_recv_buff;
}
// 为接收缓存区最后添加 '\0'
serial_recv_buff[serial_recv_length] = '\0';
// 设置串口接收完成标志
serial_recv_flag = 1;
}
}
}
// GPIO初始化
void AS608_GPIO_Init(void)
{
// 设定WAK引脚的模式
rt_pin_mode(WAK_PIN, PIN_MODE_INPUT_PULLDOWN);
}
// AS608初始化
int AS608_Init(void)
{
int ret = 0;
// 清空接收缓存区
rt_memset(serial_recv_buff,0,sizeof(serial_recv_buff));
// 清空标志位
serial_recv_flag = 0;
// 清空缓存区长度计量
serial_recv_length = 0;
rt_kprintf("Try to open(%s)\n", SAMPLE_UART_NAME);
// 获取串口句柄
serial = rt_device_find(SAMPLE_UART_NAME);
if (!serial)
{
LOG_E("find %s failed!\n", SAMPLE_UART_NAME);
return -RT_ERROR;
}
// 初始化信号量
ret = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
if (ret != RT_EOK)
{
LOG_E("failed to rt_sem_init !\n");
return -RT_ERROR;
}
// 打开串口设备
ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
if (ret != RT_EOK)
{
LOG_E("open %s failed : %d !\n", SAMPLE_UART_NAME, ret);
return -RT_ERROR;
}
// 设置接收回调函数
rt_device_set_rx_indicate(serial, uart_input);
// 创建串口数据接收线程
serial_recv_thread = rt_thread_create("serial", serial_recv_thread_entry, RT_NULL, 1024*2, 15, 20);
if (serial_recv_thread != RT_NULL)
{
// 启动线程
rt_thread_startup(serial_recv_thread);
}
else
{
rt_device_close(serial);
LOG_E("Failed to [rt_thread_create] !!!");
return -RT_ERROR;
}
// WAK引脚初始化
AS608_GPIO_Init();
// 测试write功能
ret = serial_send_byte(0x66);
if(ret == 1)
{
rt_kprintf("rt_device_write TEST successful!!\n");
}
return RT_EOK;
}
// 清除AS608模块的初始化
int AS608_DeInit(void)
{
int ret = RT_EOK;
rt_kprintf("\nAS608_DeInit Run........\n");
ret = rt_thread_delete(serial_recv_thread);
if(ret != RT_EOK)
{
LOG_E("rt_thread_delete failed!!!");
return ret;
}
ret = rt_device_close(serial);
if(ret != RT_EOK)
{
LOG_E("rt_device_close failed!!!");
return ret;
}
ret = rt_sem_detach(&rx_sem);
if(ret != RT_EOK)
{
LOG_E("rt_sem_detach failed!!!");
return ret;
}
finger_id = 0; // 指纹ID归0
rt_kprintf("\nAS608 DeInit successful!!\n");
return RT_EOK;
}
/************************************************
函数名称 : Clear_recv_buff
功 能 : 清空串口接收缓存区
参 数 : 无
返 回 值 :
作 者 : LC
*************************************************/
void Clear_recv_buff(void)
{
// 清空接收缓存区
rt_memset(serial_recv_buff,0,sizeof(serial_recv_buff));
// 清空标志位
serial_recv_flag = 0;
// 清空缓存区长度计量
serial_recv_length = 0;
}
/************************************************
函数名称 : serial_send_byte
功 能 : 串口发送一个字节
参 数 : dat:要发送的字节
返 回 值 : 1则为写入的字节数 -1为错误标志
作 者 : LC
*************************************************/
int serial_send_byte(uint8_t dat)
{
int ret = rt_device_write(serial, 0, &dat, 1);
if(ret != 1)
{
LOG_E("Failed to [serial_send_byte] !!!");
return -1;
}
return ret;
}
/******************************************************************
* 函 数 名 称:get_as608_touch
* 函 数 说 明:获取是否有手指触摸识别区
* 函 数 形 参:无
* 函 数 返 回:0没有触摸 1有触摸
* 作 者:LC
* 备 注:无
******************************************************************/
char get_as608_touch(void)
{
delay_ms(300); // 等待触摸稳定
if( GET_WAK_IN == 1 )//触摸为1
{
// printf("Touch-1\r\n");
return 1;
}
//printf("Touch-0\r\n");
return 0;
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Send_Pack_Head
* 函 数 说 明:发送包头
* 函 数 形 参:无
* 函 数 返 回:wu
* 作 者:LC
* 备 注:无
******************************************************************/
void FPM10A_Cmd_Send_Pack_Head(void)
{
for( int i = 0; i < 6; i++ ) //包头
{
serial_send_byte(FPM10A_Pack_Head[i]);
}
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Check
* 函 数 说 明:发送指令
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FPM10A_Cmd_Check(void)
{
int i = 0;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for(i=0;i<10;i++)
{
serial_send_byte(FPM10A_Get_Device[i]);
}
}
/******************************************************************
* 函 数 名 称:FPM10A_Receive_Data
* 函 数 说 明:接收反馈数据缓冲
* 函 数 形 参:ucLength 接收长度
* 函 数 返 回:RT_EOK:成功 其他:错误
* 作 者:LC
* 备 注:无
******************************************************************/
int FPM10A_Receive_Data(uint8_t ucLength)
{
// rt_kprintf("FPM10A_Receive_Data Run.....\n");
uint8_t i = 0;
int timeout = 2000; // 超时时间,单位Ms
// 为了之后的数据检查
FPM10A_RECEICE_BUFFER[9] = 0x99;
FPM10A_RECEICE_BUFFER[8] = 0x88;
//等待数据接收完毕
while( (serial_recv_length < ucLength) && (timeout > 0) )
{
aicos_mdelay(10);
timeout -= 10;
}
// 转存数据
for( i = 0; i < ucLength; i++ )
{
FPM10A_RECEICE_BUFFER[i] = serial_recv_buff[i];
}
// 检查接收到的数据是否正确
if( FPM10A_RECEICE_BUFFER[9] != 0x99 ||
FPM10A_RECEICE_BUFFER[8] != 0x88 )
{
Clear_recv_buff(); // 清除接收缓存区
return RT_EOK;
}
else
{
//Error, no data received
rt_kprintf("The data received is wrong !\n");
Clear_recv_buff(); // 清除接收缓存区
return RT_ERROR;
}
// rt_kprintf("FPM10A_Receive_Data END !!\n");
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Get_Img
* 函 数 说 明:获得指纹图像命令
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FPM10A_Cmd_Get_Img(void)
{
uint8_t i;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for( i = 0; i < 6; i++ ) //发送命令 0x1d
{
serial_send_byte(FPM10A_Get_Img[i]);
}
}
/******************************************************************
* 函 数 名 称:FINGERPRINT_Cmd_Img_To_Buffer1
* 函 数 说 明:将图像转换成特征码存放在Buffer1中
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FINGERPRINT_Cmd_Img_To_Buffer1(void)
{
uint8_t i;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for( i = 0; i < 7; i++ ) //发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
{
serial_send_byte(FPM10A_Img_To_Buffer1[i]);
}
}
/******************************************************************
* 函 数 名 称:FINGERPRINT_Cmd_Img_To_Buffer2
* 函 数 说 明:将图像转换成特征码存放在Buffer2中
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FINGERPRINT_Cmd_Img_To_Buffer2(void)
{
uint8_t i;
for( i = 0; i < 6; i++ ) //发送包头
{
serial_send_byte(FPM10A_Pack_Head[i]);
}
for( i = 0; i < 7; i++ ) //发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
{
serial_send_byte(FPM10A_Img_To_Buffer2[i]);
}
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Search_Finger
* 函 数 说 明:搜索全部用户999枚
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FPM10A_Cmd_Search_Finger(void)
{
uint8_t i;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for( i = 0 ; i < 11; i++ )
{
serial_send_byte(FPM10A_Search[i]);
}
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Reg_Model
* 函 数 说 明:将BUFFER1跟BUFFER2合成特征模版
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FPM10A_Cmd_Reg_Model(void)
{
uint8_t i;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for( i = 0; i < 6; i++ )
{
serial_send_byte(FPM10A_Reg_Model[i]);
}
}
/******************************************************************
* 函 数 名 称:FINGERPRINT_Cmd_Delete_All_Model
* 函 数 说 明:删除指纹模块里的所有指纹模版
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void FINGERPRINT_Cmd_Delete_All_Model(void)
{
uint8_t i;
for( i = 0; i < 6; i++ ) //包头
{
serial_send_byte(FPM10A_Pack_Head[i]);
}
for( i = 0; i < 6; i++ ) //命令合并指纹模版
{
serial_send_byte(FPM10A_Delete_All_Model[i]);
}
}
/******************************************************************
* 函 数 名 称:FPM10A_Cmd_Save_Finger
* 函 数 说 明:保存指纹
* 函 数 形 参:保存指纹的位置(ID号)
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
int FPM10A_Cmd_Save_Finger( unsigned int storeID )
{
uint64_t temp = 0;
uint8_t i;
FPM10A_Save_Finger[5] =(storeID&0xFF00)>>8;
FPM10A_Save_Finger[6] = (storeID&0x00FF);
for( i = 0; i < 7; i++ ) //计算校验和
{
temp = temp + FPM10A_Save_Finger[i];
}
FPM10A_Save_Finger[7]=(temp & 0x00FF00) >> 8; //存放校验数据
FPM10A_Save_Finger[8]= temp & 0x0000FF;
FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
for( i = 0; i < 9; i++ )
{
//发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
serial_send_byte(FPM10A_Save_Finger[i]);
}
return RT_EOK;
}
/******************************************************************
* 函 数 名 称:AS608_Add_Fingerprint
* 函 数 说 明:添加指纹
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
int AS608_Add_Fingerprint(void)
{
int success_flag = 0; // 添加成功标志
int add_count1 = 3; // 循环次数
int add_count2 = 3; // 循环次数
rt_kprintf("Please keep your finger on the touch area!\n");
// 等待手指放在触摸区域
while(get_as608_touch() == 0){ delay_ms(100); }
rt_kprintf("\n[Start add fingerprints]\n");
// 手指放在触摸区域
while( get_as608_touch() == 1 )
{
// 次数自减
add_count1--;
FPM10A_RECEICE_BUFFER[9] = 1;
FPM10A_Cmd_Get_Img(); //获得指纹图像
FPM10A_Receive_Data(12);
//判断接收到的确认码,等于0指纹获取成功
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
FINGERPRINT_Cmd_Img_To_Buffer1();
FPM10A_Receive_Data(12);
while( get_as608_touch() == 1 )
{
// 次数自减
add_count2--;
FPM10A_RECEICE_BUFFER[9] = 1;
FPM10A_Cmd_Get_Img(); //获得指纹图像
FPM10A_Receive_Data(12);
//判断接收到的确认码,等于0指纹获取成功
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
rt_kprintf("Successful added, ID = %d\n",finger_id);
FINGERPRINT_Cmd_Img_To_Buffer2();
FPM10A_Receive_Data(12);
FPM10A_Cmd_Reg_Model();//转换成特征码
FPM10A_Receive_Data(12);
//保存指纹
FPM10A_Cmd_Save_Finger(finger_id++);
FPM10A_Receive_Data(12);
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
// 指纹添加标志位至1
success_flag = 1;
goto ADD_END;
}
}
// 超过了循环次数也没有成功则返回最后
if(add_count2 <= 0)
goto ADD_END;
delay_ms(50);
}
}
// 超过了循环次数也没有成功则返回最后
if(add_count1 <= 0)
goto ADD_END;
delay_ms(50);
}
ADD_END:
if(success_flag == 1)
{
rt_kprintf("Add fingerprint successfully !!!\n");
}
else
{
rt_kprintf("Failed to add fingerprint !!!\n");
}
rt_kprintf("Lift up your fingers!!!\n");
// 确保手指抬起
while(get_as608_touch() == 1){ delay_ms(100); }
rt_kprintf("The finger is up !\n");
delay_ms(200);
return RT_EOK; // 根据成功标志返回相应的值
}
/******************************************************************
* 函 数 名 称:AS608_Find_Fingerprint
* 函 数 说 明:搜索指纹
* 函 数 形 参:无
* 函 数 返 回:-1:未查到 其他:指纹ID号
* 作 者:LC
* 备 注:
******************************************************************/
int AS608_Find_Fingerprint(void)
{
int find_fingerid = -1; // 指纹ID缓存区
int return_value = -1; // 返回值
// 确保手指按在触摸区域
while( get_as608_touch() == 0 ){ delay_ms(10); }
/*=================================================*/
FPM10A_Cmd_Get_Img(); //获得指纹图像
FPM10A_Receive_Data(12);
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
FINGERPRINT_Cmd_Img_To_Buffer1();
FPM10A_Receive_Data(12);
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
FPM10A_Cmd_Search_Finger();
FPM10A_Receive_Data(16);
if(FPM10A_RECEICE_BUFFER[9] == 0)
{
// 拼接指纹ID
find_fingerid = FPM10A_RECEICE_BUFFER[10]*256 + FPM10A_RECEICE_BUFFER[11];
}
else
{
find_fingerid = -1;
}
}
else
{
find_fingerid = -1;
}
}
else
{
find_fingerid = -1;
}
/*=================================================*/
if(find_fingerid != -1)
return_value = find_fingerid;
if(find_fingerid > finger_id)
return_value = -1;
return return_value;
}
/******************************************************************
* 函 数 名 称:AS608_Delete_All_Fingerprint
* 函 数 说 明:删除所有存贮的指纹库
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
int AS608_Delete_All_Fingerprint(void)
{
rt_kprintf("\nStart deleting all fingerprints in the database......\n");
FINGERPRINT_Cmd_Delete_All_Model();
FPM10A_Receive_Data(12);
finger_id = 0; // 指纹ID归0
rt_kprintf("Delete fingerprint database completed !!!\n");
return RT_EOK;
}
/******************************************************************
* 函 数 名 称:AS608_Device_Check
* 函 数 说 明:模块检查
* 函 数 形 参:无
* 函 数 返 回:RT_ERROR:未检测到模块或者模块异常 RT_EOK:检测到模块并且通信成功
* 作 者:LC
* 备 注:
******************************************************************/
int AS608_Device_Check(void)
{
rt_kprintf("AS608_Device_Check run.....\n");
FPM10A_RECEICE_BUFFER[9] = 1; //串口数组第九位可判断是否通信正常
FPM10A_Cmd_Check(); //单片机向指纹模块发送校对命令
FPM10A_Receive_Data(12); //将串口接收到的数据转存
if(FPM10A_RECEICE_BUFFER[9] == 0) //判断数据低第9位是否接收到0
{
rt_kprintf("AS608_Device_Check successful !!!\n");
return RT_EOK; // 检测成功
}
rt_kprintf("Failed to [AS608_Device_Check] !!!\n");
return RT_ERROR; // 检测失败
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
bsp_as608.h
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_AS608_H__
#define __BSP_AS608_H__
#include <getopt.h>
#include <string.h>
#include <rtthread.h>
#include <aic_core.h>
int AS608_Init(void); // 模块初始化
int AS608_DeInit(void); // 清除模块的初始化
int AS608_Device_Check(void); // 模块检测
int AS608_Delete_All_Fingerprint(void); // 删除全部指纹
int AS608_Add_Fingerprint(void); // 添加指纹
int AS608_Find_Fingerprint(void); // 指纹查找匹配
int serial_send_byte(uint8_t dat);
char get_as608_touch(void); // 手指触摸
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Kconfig
这个是一个menuconfig中的选项,如果在菜单中选中该选项,就会在rtconfig.h
中定义一个语句,用来if判断条件编译之类的。
config LCKFB_FINGERPRINT_RECOGNITION_SENSOR
bool "USE Fingerprint identification sensor (AS608)"
select AIC_USING_UART3
default n
help
More information is available at: https://wiki.lckfb.com/
2
3
4
5
6
7
SConscript
自动化构建文件,如果定义了 LCKFB_FINGERPRINT_RECOGNITION_SENSOR
和 USING_LCKFB_TRANSPLANT_CODE
就自动编译当前目录下的文件!!
Import('RTT_ROOT')
Import('rtconfig')
import rtconfig
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd]
src = []
if GetDepend('LCKFB_FINGERPRINT_RECOGNITION_SENSOR') and GetDepend('USING_LCKFB_TRANSPLANT_CODE'):
src = Glob(os.path.join(cwd, '*.c'))
group = DefineGroup('lckfb-fingerprint-recognition-sensor', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
test_fingerprint_recognition_sensor.c
这个文件定义了一个用于处理AS608指纹识别传感器的线程,初始化了AS608传感器,并设置了线程的优先级、栈大小和时间片。
线程的主要任务是管理指纹的录入、删除和识别过程。它会周期性地检查是否有手指按下,并进行指纹匹配。用户可以通过设置标志来指示线程添加或删除指纹。通过命令行接口,用户可以启动这个线程来测试AS608指纹传感器的功能。
线程入口函数逻辑
- 初始化AS608设备,并检查设备是否正常。
- 删除所有已存储的指纹,为新的指纹录入做准备。
- 在一个无限循环中,线程将执行以下任务:
- 检查线程退出标志,如果设置则退出循环。
- 检测手指是否按下,如果按下则尝试匹配指纹,并将结果打印到控制台。
- 根据添加指纹标志,如果设置则录入新的指纹。
- 根据删除指纹标志,如果设置则删除所有指纹。
- 线程将周期性地休眠一段时间,以避免过高的CPU占用。
AS608启动函数逻辑
创建名为"uart_thread"的线程,入口函数为uart_thread_entry
,无参数,设置栈大小、优先级和时间片。 如果线程创建成功,启动线程,并进行一些基本的串口通信测试。
提示
MSH_CMD_EXPORT
宏将test_fingerprint_recognition_sensor
、test_exit_AS608
、test_add_AS608_fingerprint
和test_delete_AS608_fingerprint
函数导出为RT-Thread命令行接口的命令,这样用户可以在RT-Thread的命令行中直接运行以下命令来控制指纹识别传感器的行为:
fingerprint recognition sensor -AS608- test
启动指纹识别传感器测试。exit AS608
停止指纹识别线程。add fingerprint AS608
添加新的指纹。delete all fingerprint AS608
删除所有指纹。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>
#include <rtthread.h>
#include "rtdevice.h"
#include "aic_core.h"
#include "aic_hal_gpio.h"
#include "bsp_as608.h"
#define THREAD_PRIORITY 25 // 线程优先级
#define THREAD_STACK_SIZE 4096 // 线程大小
#define THREAD_TIMESLICE 20 // 时间片
static rt_thread_t uart_thread = RT_NULL; // 线程控制块
static int thread_exit_flag = 1; // 线程退出标志
static int add_fingerprint_flag = 0; // 指纹添加标志
static int delete_fingerprint_flag = 0; // 指纹删除标志
// 线程入口函数
static void uart_thread_entry(void *param)
{
int ret = 0;
rt_kprintf("Stat uart_thread_entry......\n");
ret = AS608_Device_Check(); // 模块检测
if(ret != RT_EOK)
{
LOG_E("AS608_Device_Check failed");
goto exit;
}
// rt_kprintf("AS608_Device_Check run END!!\n");
ret = AS608_Delete_All_Fingerprint(); // 删除全部指纹
if(ret != RT_EOK)
{
LOG_E("AS608_Delete_All_Fingerprint failed");
goto exit;
}
// rt_kprintf("AS608_Delete_All_Fingerprint run END!!\n");
ret = AS608_Add_Fingerprint(); // 添加指纹
if(ret != RT_EOK)
{
LOG_E("AS608_Add_Fingerprint failed");
goto exit;
}
while(1) // 退出标志未被设置则一直循环
{
if(thread_exit_flag == 1)
{
rt_kprintf("\n=====The thread EXIT !!=====\n");
break;
}
if(get_as608_touch() == 1) // 如果手指按压识别区域
{
int ret_find = AS608_Find_Fingerprint(); // 从指纹库中寻找指纹进行匹配
if( ret_find == -1 )
{
rt_kprintf("\nNo Find!!\n");
}
else
{
rt_kprintf("\nID = [%d]\n",ret_find);
}
rt_kprintf("Lift up your fingers!!!\n");
// 确保手指已经抬起
while(get_as608_touch() == 1){ delay_ms(10); }
rt_thread_mdelay(200); // 检测延时防止粘连
}
if(add_fingerprint_flag == 1) // 如果条件符合则添加指纹
{
rt_kprintf("add_fingerprint_flag == 1\n");
AS608_Add_Fingerprint();
add_fingerprint_flag = 0;
}
if(delete_fingerprint_flag == 1) // 如果条件符合则删除指纹
{
rt_kprintf("delete_fingerprint_flag == 1\n");
AS608_Delete_All_Fingerprint();
delete_fingerprint_flag = 0;
}
rt_thread_mdelay(100);
}
exit:
AS608_DeInit();
rt_kprintf("thread EXIT successful !!\n");
}
static void test_fingerprint_recognition_sensor(int argc, char **argv)
{
add_fingerprint_flag = 0; // 指纹添加标志
delete_fingerprint_flag = 0; // 指纹删除标志
if(thread_exit_flag == 0)
{
rt_kprintf("\n=====The thread is already running !!=====\n");
return;
}
thread_exit_flag = 0;
int ret = AS608_Init(); // 模块初始化
if(ret != RT_EOK)
{
LOG_E("Failed to [AS608_Init] !!!");
LOG_E("file: %s line: %s", __FILE__, __LINE__);
return;
}
rt_kprintf("AS608_Init run END!!\n");
/* 创建线程,名称是 uart_thread,入口是 uart_thread_entry */
uart_thread = rt_thread_create("uart_thread",
uart_thread_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (uart_thread != RT_NULL)
rt_thread_startup(uart_thread);
ret = serial_send_byte(0x01);
if(ret == 1)
{
rt_kprintf("serial_send_byte TEST successful!!\n");
}
rt_kprintf("test_fingerprint_recognition_sensor run END!!\n");
}
// 导出函数为命令
MSH_CMD_EXPORT(test_fingerprint_recognition_sensor, fingerprint recognition sensor -AS608- test);
static void test_exit_AS608(void){ thread_exit_flag = 1; } // 退出测试线程
MSH_CMD_EXPORT(test_exit_AS608, exit AS608); // 导出函数为命令
static void test_add_AS608_fingerprint(void){ add_fingerprint_flag = 1; } // 添加指纹
MSH_CMD_EXPORT(test_add_AS608_fingerprint, add fingerprint AS608); // 导出函数为命令
static void test_delete_AS608_fingerprint(void){ delete_fingerprint_flag = 1; } // 删除所有指纹命令
MSH_CMD_EXPORT(test_delete_AS608_fingerprint, delete all fingerprint AS608); // 导出函数为命令
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
移植验证
我们使用串口调试,将 USB转TTL模块 连接到衡山派开发板上面!!
具体的教程查看:串口调试(点击跳转🚀)
串口波特率默认为
115200
我们在输入下面的命令运行该模块的线程:
输入的时候按下
TAB键
会进行命令补全!!
test_fingerprint_recognition_sensor
模块上电效果: