发帖
22 1 0

【电子DIY作品】指纹保险箱?姑且叫它保险箱吧

WT_0213
论坛元老

105

主题

1440

回帖

1万

积分

论坛元老

积分
13206
电子DIY 218 22 3 天前
[i=s] 本帖最后由 WT_0213 于 2025-3-27 20:18 编辑 [/i]

在当下快节奏的现代生活中,电子 DIY 早已不单单局限于技术层面的探索,更是一种能为生活增添无限乐趣的独特生活态度。留意到此次活动提交作品的截止时间为 4 月 1 日,此前就一直想着给小朋友做一个小盒子,正好借这个机会忙里偷闲参与到活动当中,再体验一下电子 DIY 的乐趣。

活动地址:

第四期电子DIY | 实用至上,点亮便利生活

https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45819&_dsign=c374dce6

我制作了一个稍微实用价值的指纹开锁小盒子,旨在为日常生活中的物品收纳提供更安全、便捷的解决方案。

一、设计思路

考虑到日常小物件收纳时,常担心隐私物品被他人随意翻看,便决定打造一个通过指纹识别控制开合的小盒子。利用指纹识别的唯一性,实现精准的开锁权限管理,让只有授权指纹的使用者能够打开盒子,极大提升了收纳物品的安全性。这个小盒子不仅是收纳小物件的容器,更是守护孩子隐私与专属空间的好帮手,能有效避免小朋友的宝贝被随意翻动。

二、设计理念

小朋友都有自己珍视的小玩意儿,像心爱的贴纸、秘密小纸条等,他们渴望有个安全的小天地存放这些宝贝。考虑到孩子对新奇事物的好奇心,传统锁具操作复杂,而指纹识别既有趣又便捷,凭借独一无二的指纹特征,能精准识别孩子身份,为控制盒子开合提供绝佳方式。基于此,我决心制作这款指纹开锁小盒子,给孩子打造专属且安全的收纳空间,让他们享受自主管理物品的乐趣。

三、制作流程

硬件选型

IMG_20250327_010248.jpg

选用之前购买的 FPM383C 指纹模块,它识别精度高、响应快,小朋友轻轻一按手指,就能快速准确采集指纹信息。主控芯片选用 [主控芯片型号],其主要负责处理 FPM383C 指纹模块传来的数据,并依据结果向电机驱动模块以及其他硬件下达精准指令。

此次主控制器使用的是M61-32SU开发板,它在整个系统里扮演着重要角色。M61-32SU开发板能够高效协调主控芯片与各个模块间的信息交互,进一步优化系统运行的稳定性与流畅度,保障指纹识别、指令传输等环节有序进行。

另外,选用了一个 9g 舵机来作为盒子锁扣的直接执行者。9g 舵机体积小巧,动力输出却较为稳定,通过接收主控芯片的指令后,能精准控制锁扣的开合动作。当接收到开锁指令,舵机迅速转动,打开锁扣;锁定指令下达时,舵机反向转动,紧闭锁扣,为小盒子的开合提供了可靠的机械动力支持。

原本计划用 3D 打印技术制作盒子外壳,精心设计好了模型,满心期待能打印出一个造型酷炫、结构精巧的外壳。但在准备打印时,却发现耗材不够,无奈之下,我决定改用纸盒来制作盒子外壳。挑选了厚实且有一定韧性的纸盒,虽然没有 3D 打印外壳那样精致,但纸盒可塑性强。我用剪刀、胶水等工具,按照预先设计好的尺寸,将纸盒裁剪、折叠、粘贴,为内部电子元件搭建了一个简易却实用的 “家”。使用的是带彩色纸皮的纸盒【鞋盒titter 】,让小盒子看起来好看点,也弥补了没有 3D 打印外壳的遗憾。

IMG_20250327_005943.jpg

四、功能呈现

当孩子把录入指纹的手指放在 FPM383C 识别模块上,系统瞬间就能完成识别,主控芯片通过控制 9g 舵机,迅速打开锁扣,孩子可以轻松拿取自己的宝贝。要是不小心按错指纹,系统立刻启动锁定程序,9g 舵机反向转动紧闭锁扣,防止其他人未经允许打开盒子。由于盒子做的不是那么精密,透光有缝隙,导致盒子内部的彩灯透过缝隙扩散出来,不过这样感觉反而增加了趣味性。FPM383C模块当成功开锁时,自动会闪烁灯光,指纹验证通过绿色灯光,指纹不通过红色灯光,反馈比较明显减少了代码工作量。

IMG_20250327_010051.jpg

IMG_20250327_010015.jpg

五、接线方式

Ai-M61-32s FPM383C 舵机
3v3 Pin3
GND PIN6
IO23 PIN5
IO24 PIN4
IO19 信号线
5V 电源正
GND 电源负

资料参考:

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

https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43963

【外设移植】SG90舵机Ai-M61开发板

https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=44405

代码:

#include "FPM383C.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "bflb_mtimer.h"
#include "bflb_dma.h"
#include "bflb_uart.h"
#include "log.h"
#include "bflb_servo.h"
#include "bflb_gpio.h"           //gpio头文件
#include "bflb_mtimer.h"        //mtimer定时器头文件
#include "bflb_pwm_v2.h"      //pwm_v2头文件
#include "bflb_clock.h"           //系统时钟头文件

//控制模块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的外设句柄,用来执行串口指令的发送
struct bflb_device_s *fpm383c_uart;

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

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

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

struct bflb_servo_attr servo;

// 锁状态
uint8_t lock_state = 0;

/**
 * @brief 获取状态
 * 
 * @param Timeout 
 */
void FPM383C_ReceiveData(uint16_t Timeout)
{
  uint8_t i = 0;
  // 检测缓冲区是否有数据
  while(bflb_uart_rxavailable(fpm383c_uart) == 0 && (--Timeout))
  {
    bflb_mtimer_delay_ms(1);
  }
  // 轮询fpm383c_uart接收到的字符
  while(bflb_uart_rxavailable(fpm383c_uart) > 0)
  {
    bflb_mtimer_delay_ms(2);
	// 获取数据并放入缓冲数组
    USART_ReceiveBuf[i++] = bflb_uart_getchar(fpm383c_uart);
    if(i > 15) break; 
  }
}

/// @brief 初始化FPM383C指纹模块
void FPM383C_Init(){

	// 声明 gpio句柄
    struct bflb_device_s* gpio;
	// FPM383C 模块默认波特率为 57600 
    struct bflb_uart_config_s cfg = {
        .baudrate = 57600,
        .data_bits = UART_DATA_BITS_8,
        .stop_bits = UART_STOP_BITS_1,
        .parity = UART_PARITY_NONE,
       	.flow_ctrl = UART_FLOWCTRL_NONE,
        .rx_fifo_threshold = 7,
        .tx_fifo_threshold = 7
    };

	// 初始化FPM383C指纹模块UART
    gpio = bflb_device_get_by_name("gpio");
    fpm383c_uart = bflb_device_get_by_name("uart1");

    //将GPIO_23和GPIO_24设置为TX和RX
    bflb_gpio_uart_init(gpio, GPIO_PIN_23, GPIO_UART_FUNC_UART1_TX);
    bflb_gpio_uart_init(gpio, GPIO_PIN_24, GPIO_UART_FUNC_UART1_RX);

    bflb_uart_init(fpm383c_uart, &cfg);
}

/// @brief USART串口发送数据
/// @param length 发送数组长度
/// @param FPM383C_DataBuf 需要发送的功能数组
void FPM383C_SendData(int length,uint8_t FPM383C_DataBuf[])
{

	for(int i = 0;i<length;i++)
	{
        bflb_uart_put(fpm383c_uart,(uint8_t *)&FPM383C_DataBuf[i], 1);
	}
}

/// @brief 发送休眠指令 确认码=00H 表示休眠设置成功。确认码=01H 表示休眠设置失败。
/// @param  
void FPM383C_Sleep(void)
{
	FPM383C_SendData(12,PS_SleepBuf);
}

/// @brief 验证用获取图像
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_GetImage(uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(12,PS_GetImageBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

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

/// @brief 发送搜索指纹指令
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_Search(uint32_t timeout)
{
	FPM383C_SendData(17,PS_SearchBuf);
	FPM383C_ReceiveData(timeout);
	return (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
}

/// @brief 删除指定指纹指令
/// @param pageID 需要删除的指纹ID号
/// @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);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 清空指纹库
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_Empty(uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(12,PS_EmptyBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 发送控制灯光指令
/// @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);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 验证指纹是否注册
/// @param  
void FPM383C_Identify(void)
{
	if(FPM383C_GetImage(2000) == 0x00)
	{
		if(FPM383C_GenChar(2000) == 0x00)
		{
			struct bflb_device_s *led = bflb_device_get_by_name("gpio");
			if(FPM383C_Search(2000) == 0x00)
			{
				score = (int)((USART_ReceiveBuf[10] << 8) + USART_ReceiveBuf[11]);
				LOG_E("解锁成功 指纹ID:%d\r\n",(int)score);
				FPM383C_ControlLED(PS_GreenLEDBuf,1000);
	
				bflb_gpio_init(led, GPIO_PIN_14, GPIO_OUTPUT);
				bflb_gpio_set(led, GPIO_PIN_14);
				bflb_mtimer_delay_ms(1000);
				bflb_gpio_reset(led, GPIO_PIN_14);
				// 重置接收数据缓存
				memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
				if(!lock_state){
					lock_state = 1;
					servo = bflb_servo_attach(GPIO_PIN_19, PWM_CH3);
					bflb_servo_write(&servo, 80);
					bflb_mtimer_delay_ms(800);
					bflb_servo_stop(&servo);
				}
				return;
			}else{
				LOG_E("解锁失败\r\n");
				bflb_gpio_init(led, GPIO_PIN_12, GPIO_OUTPUT);
				bflb_gpio_set(led, GPIO_PIN_12);
				bflb_mtimer_delay_ms(1000);
				bflb_gpio_reset(led, GPIO_PIN_12);
				// 重置接收数据缓存
				memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
				if(lock_state){
					lock_state = 0;
					servo = bflb_servo_attach(GPIO_PIN_19, PWM_CH3);
					bflb_servo_write(&servo, 10);
					bflb_mtimer_delay_ms(800);
					bflb_servo_stop(&servo);
				}
				return;
			}
		}
	}
}

/// @brief 自动注册
/// @param pageID 输入需要注册的指纹ID号,取值范围0—59
/// @param timeout 设置注册指纹超时时间,因为需要按压四次手指,建议大于10000(即10s)
void FPM383C_Enroll(uint16_t pageID,uint16_t timeout)
{
	LOG_E("注册指纹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);
	if(USART_ReceiveBuf[9] == 0x00)
	{
		LOG_E("指纹注册完成\r\n");
		// 亮绿灯2秒
		FPM383C_ControlLED(PS_GreenLEDBuf,2000);
		// 重置接收数据缓存
		memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
		return;
	}
	else if(timeout == 0)
	{
		// 超时取消注册
		FPM383C_SendData(12,PS_CancelBuf);
		bflb_mtimer_delay_ms(50);
		// 重置接收数据缓存
		memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	}
	// 亮红灯2秒
	FPM383C_ControlLED(PS_RedLEDBuf,2000);
}

upload 附件:fpm383c_lock.zip

保险箱3D图用freeCAD做的,源文件在最下面。

8.JPG

7.JPG

捕获.JPG

3.JPG

4.JPG

6.JPG

5.JPG

2.JPG

upload 附件:BOX.zip

──── 1人觉得很赞 ────

使用道具 举报

这个指纹模块带灯好酷
幸福哥的3D打印机呢?给他造一个漂亮的盒子呀
围观
3 天前
bzhou830 发表于 2025-3-27 08:33
幸福哥的3D打印机呢?给他造一个漂亮的盒子呀

耗材都给小朋友打玩具了,没好耗材了。昨天买了个白色PETG估计这两天就到了
WT_0213 发表于 2025-3-27 09:37
耗材都给小朋友打玩具了,没好耗材了。昨天买了个白色PETG估计这两天就到了  ...

我现在直接买那种20多一公斤的PETG, 没啥大问题。
学习了
3 天前
bzhou830 发表于 2025-3-27 09:43
我现在直接买那种20多一公斤的PETG, 没啥大问题。

玛丽哥哪儿的呀,我都是买的拓竹的那个。开始打印还行后来打印总是被头粘起来总是打不好。PLA没出现过这种情况。
这个活儿整得挺有创意,让我想起了植物大战僵尸里的百宝箱,666
您需要登录后才可以回帖 立即登录
高级模式
123下一页
统计信息
  • 会员数: 28202 个
  • 话题数: 40102 篇