编程技术分享

分享编程知识,探讨技术创新

0%

简介:这是一款能够在宿舍使用的指纹锁,在不破坏原本结构的基础上加装指纹解锁开门,APP遥控开门功能。软件后期整理完成后开源!!可加群:894010968

好的,作为一名高级嵌入式软件开发工程师,很高兴能和你一起探讨宿舍指纹锁项目的设计与实现。这个项目确实是一个非常好的实践案例,涵盖了嵌入式系统开发的完整流程。为了构建一个可靠、高效、可扩展的系统平台,我将从代码设计架构、具体C代码实现、项目中采用的技术和方法等方面进行详细说明,确保内容超过3000字,并基于实践验证的经验。
关注微信公众号,提前获取相关推文

一、系统需求分析与架构设计

1. 需求分析

宿舍指纹锁的核心需求可以归纳为以下几点:

  • 指纹解锁: 这是最核心的功能,用户可以通过指纹识别解锁门锁。需要快速、准确地识别指纹,并具备一定的安全性和防伪能力。
  • APP 遥控开门: 用户可以通过手机 APP 在一定范围内(例如蓝牙或 Wi-Fi 范围)远程控制门锁的开关。这增加了使用的便利性。
  • 非破坏性安装: 指纹锁的安装不能破坏宿舍原有的门锁结构,需要采用附加安装的方式,方便安装和拆卸,不影响宿舍门的原始功能。
  • 安全性: 系统需要具备一定的安全性,防止非法开锁,包括指纹识别的安全性、通信的安全性(APP 遥控)、以及物理安全。
  • 低功耗: 作为电池供电的嵌入式设备,低功耗设计至关重要,以延长电池寿命。
  • 易用性: 操作界面应简洁明了,用户容易上手。APP 界面也需要友好,操作流畅。
  • 可维护性和可升级性: 系统设计应考虑后期的维护和升级,例如固件升级、功能扩展等。
  • 开源: 项目完成后需要开源,这意味着代码需要具有良好的可读性、可维护性和文档。

2. 系统架构设计

为了满足上述需求,并构建一个可靠、高效、可扩展的系统平台,我建议采用分层模块化架构。这种架构将系统划分为不同的层次和模块,每个模块负责特定的功能,模块之间通过清晰定义的接口进行通信。这种架构具有以下优点:

  • 模块化: 功能模块化,易于开发、测试、维护和升级。
  • 高内聚低耦合: 模块内部功能高度相关,模块之间依赖性低,降低了模块间的相互影响,提高了系统的稳定性和可维护性。
  • 可扩展性: 可以方便地添加新的功能模块,例如增加密码解锁、NFC 解锁等。
  • 可移植性: 通过抽象硬件层,可以更容易地将系统移植到不同的硬件平台。

基于分层模块化思想,我将系统架构设计为以下几个层次:

  • 硬件层 (Hardware Layer): 包括指纹传感器、微控制器 (MCU)、蓝牙/Wi-Fi 模块、电机驱动模块、电源管理模块、指示灯、按键等硬件组件。
  • 硬件抽象层 (HAL - Hardware Abstraction Layer): 提供对底层硬件的抽象接口,向上层屏蔽硬件差异。例如,定义通用的 GPIO、SPI、UART、I2C 等接口,使得上层模块可以不关心具体的硬件细节,直接调用 HAL 提供的接口操作硬件。
  • 板级支持包 (BSP - Board Support Package): 针对具体的硬件平台,提供硬件初始化、时钟配置、中断管理、内存管理等底层支持。BSP 通常基于 HAL 构建,为操作系统或裸机应用提供运行环境。
  • 设备驱动层 (Device Driver Layer): 为各种硬件设备提供驱动程序,例如指纹传感器驱动、蓝牙/Wi-Fi 模块驱动、电机驱动、LED 驱动等。驱动程序负责与硬件设备进行交互,提供上层模块可以调用的 API。
  • 核心服务层 (Core Service Layer): 实现系统的核心业务逻辑,包括:
    • 指纹识别服务 (Fingerprint Recognition Service): 负责指纹数据的采集、特征提取、模板存储、指纹比对等核心功能。
    • 通信服务 (Communication Service): 处理与 APP 的通信,包括数据接收、命令解析、数据发送等。
    • 安全服务 (Security Service): 负责系统安全相关的操作,例如数据加密、身份认证等。
    • 电机控制服务 (Motor Control Service): 控制电机驱动模块,实现门锁的开关动作。
    • 状态管理服务 (State Management Service): 管理系统的各种状态,例如锁定状态、解锁状态、网络连接状态、电池电量等。
  • 应用层 (Application Layer): 提供用户交互界面和应用逻辑,例如:
    • 主应用程序 (Main Application): 负责系统初始化、任务调度、用户交互逻辑等。
    • APP 接口 (APP Interface): 定义与手机 APP 交互的接口,例如命令协议、数据格式等。

系统架构图示:

1
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
+---------------------+
| 应用层 (Application Layer) |
+---------------------+
| 核心服务层 (Core Service Layer) |
| ------------------- |
| | 指纹识别服务 | |
| | 通信服务 | |
| | 安全服务 | |
| | 电机控制服务 | |
| | 状态管理服务 | |
| ------------------- |
+---------------------+
| 设备驱动层 (Device Driver Layer) |
| ------------------- |
| | 指纹传感器驱动 | |
| | 蓝牙/Wi-Fi 驱动 | |
| | 电机驱动 | |
| | LED 驱动 | |
| | 按键驱动 | |
| ------------------- |
+---------------------+
| 板级支持包 (BSP - Board Support Package) |
+---------------------+
| 硬件抽象层 (HAL - Hardware Abstraction Layer) |
+---------------------+
| 硬件层 (Hardware Layer) |
+---------------------+

3. 技术选型

  • 微控制器 (MCU): 选择低功耗、高性能的 ARM Cortex-M 系列 MCU,例如 STM32L4 系列或 ESP32 系列。STM32L4 系列以低功耗著称,ESP32 系列则集成了 Wi-Fi 和蓝牙功能,可以根据具体需求选择。
  • 指纹传感器: 选择电容式指纹传感器,具有较高的识别精度和速度,并且体积小巧,功耗低。例如 FPC1020AP 或 ZFM-20 等。
  • 蓝牙/Wi-Fi 模块: 如果选择 STM32L4 系列 MCU,可以外接蓝牙模块(例如 HC-05 或 BLE 模块)或 Wi-Fi 模块(例如 ESP8266)。如果选择 ESP32 系列 MCU,则自带 Wi-Fi 和蓝牙功能。
  • 电机驱动模块: 选择小型的直流电机或步进电机,配合相应的驱动芯片(例如 L298N 或 DRV8833)控制门锁的开关。
  • 电源管理: 采用锂电池供电,配合低功耗电源管理芯片(例如 TPS63001 或 MCP73831)进行电源管理和充电控制。
  • 操作系统: 对于简单的应用,可以使用裸机开发。对于复杂的应用,可以考虑使用实时操作系统 (RTOS),例如 FreeRTOS 或 uC/OS-III,以提高系统的实时性和可靠性,方便任务管理和调度。

二、具体 C 代码实现 (核心模块示例)

为了演示代码架构和关键功能,我将提供一些核心模块的 C 代码示例。由于代码量庞大,这里只给出关键模块的框架和核心逻辑,并进行详细解释。

1. HAL 层 (GPIO 初始化示例 - hal_gpio.hhal_gpio.c)

  • hal_gpio.h (头文件,定义 GPIO 相关接口)
1
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
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
GPIO_PIN_2,
// ... more pins
GPIO_PIN_MAX
} gpio_pin_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_AF // Alternate Function
} gpio_mode_t;

typedef enum {
GPIO_PULL_NONE,
GPIO_PULL_UP,
GPIO_PULL_DOWN
} gpio_pull_t;

typedef enum {
GPIO_LEVEL_LOW,
GPIO_LEVEL_HIGH
} gpio_level_t;

// 初始化 GPIO 引脚
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode, gpio_pull_t pull);

// 设置 GPIO 引脚输出电平
void hal_gpio_set_level(gpio_pin_t pin, gpio_level_t level);

// 读取 GPIO 引脚输入电平
gpio_level_t hal_gpio_get_level(gpio_pin_t pin);

#endif // HAL_GPIO_H
  • hal_gpio.c (源文件,实现 GPIO 相关接口,以 STM32 为例)
1
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
#include "hal_gpio.h"
#include "stm32l4xx_hal.h" // STM32 HAL 库头文件

void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode, gpio_pull_t pull) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_TypeDef *gpio_port;
uint16_t gpio_pin_num;

// 根据 pin 编号映射到具体的 GPIO 端口和引脚
// (这里只是示例,实际需要根据硬件连接进行映射)
if (pin == GPIO_PIN_0) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_0;
} else if (pin == GPIO_PIN_1) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_1;
} // ... more pin mappings

// 使能 GPIO 时钟 (根据实际使用的 GPIO 端口使能相应的时钟)
__HAL_RCC_GPIOA_CLK_ENABLE();

// 配置 GPIO 模式
if (mode == GPIO_MODE_INPUT) {
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
} else if (mode == GPIO_MODE_OUTPUT) {
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
} else if (mode == GPIO_MODE_AF) {
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
}

// 配置 GPIO 上拉/下拉
if (pull == GPIO_PULL_NONE) {
GPIO_InitStruct.Pull = GPIO_NOPULL;
} else if (pull == GPIO_PULL_UP) {
GPIO_InitStruct.Pull = GPIO_PULLUP;
} else if (pull == GPIO_PULL_DOWN) {
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
}

GPIO_InitStruct.Pin = gpio_pin_num;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
HAL_GPIO_Init(gpio_port, &GPIO_InitStruct);
}

void hal_gpio_set_level(gpio_pin_t pin, gpio_level_t level) {
GPIO_TypeDef *gpio_port;
uint16_t gpio_pin_num;

// Pin mapping (same as in hal_gpio_init)
if (pin == GPIO_PIN_0) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_0;
} else if (pin == GPIO_PIN_1) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_1;
} // ... more pin mappings

HAL_GPIO_WritePin(gpio_port, gpio_pin_num, (level == GPIO_LEVEL_HIGH) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

gpio_level_t hal_gpio_get_level(gpio_pin_t pin) {
GPIO_TypeDef *gpio_port;
uint16_t gpio_pin_num;

// Pin mapping (same as in hal_gpio_init)
if (pin == GPIO_PIN_0) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_0;
} else if (pin == GPIO_PIN_1) {
gpio_port = GPIOA;
gpio_pin_num = GPIO_PIN_1;
} // ... more pin mappings

return (HAL_GPIO_ReadPin(gpio_port, gpio_pin_num) == GPIO_PIN_SET) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW;
}

代码解释:

  • hal_gpio.h 定义了 GPIO 相关的类型定义和函数接口,例如 gpio_pin_t 定义 GPIO 引脚枚举,gpio_mode_t 定义 GPIO 模式,hal_gpio_init 初始化 GPIO 引脚,hal_gpio_set_level 设置 GPIO 输出电平,hal_gpio_get_level 读取 GPIO 输入电平。
  • hal_gpio.c 实现了 hal_gpio.h 中定义的接口,使用了 STM32 HAL 库来操作 GPIO。代码中通过 if-else if 结构根据 gpio_pin_t 枚举值映射到具体的 GPIO 端口和引脚号。实际项目中需要根据硬件连接关系进行正确的映射。
  • HAL 层的目的是将硬件操作细节封装起来,上层模块只需要调用 hal_gpio_inithal_gpio_set_levelhal_gpio_get_level 等接口,而无需关心具体的硬件寄存器操作,提高了代码的可移植性和可维护性。

2. 设备驱动层 (指纹传感器驱动示例 - driver_fingerprint.hdriver_fingerprint.c)

假设我们使用的指纹传感器是通过 SPI 接口与 MCU 通信的,例如 FPC1020AP。

  • driver_fingerprint.h (头文件,定义指纹传感器驱动接口)
1
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
#ifndef DRIVER_FINGERPRINT_H
#define DRIVER_FINGERPRINT_H

#include "hal_gpio.h" // 假设指纹传感器需要 GPIO 控制
#include "hal_spi.h" // 假设指纹传感器使用 SPI 通信

typedef enum {
FINGERPRINT_STATUS_OK,
FINGERPRINT_STATUS_ERROR,
FINGERPRINT_STATUS_NO_FINGER,
FINGERPRINT_STATUS_TIMEOUT,
// ... more status codes
} fingerprint_status_t;

// 初始化指纹传感器
fingerprint_status_t fingerprint_init(void);

// 采集指纹图像
fingerprint_status_t fingerprint_capture_image(uint8_t *image_buffer, uint32_t buffer_size);

// 提取指纹特征
fingerprint_status_t fingerprint_extract_feature(const uint8_t *image_buffer, uint32_t buffer_size, uint8_t *feature_buffer, uint32_t *feature_size);

// 比对指纹特征
fingerprint_status_t fingerprint_match_feature(const uint8_t *feature_buffer1, uint32_t feature_size1, const uint8_t *feature_buffer2, uint32_t feature_size2, uint8_t *score);

// 注册指纹模板 (将特征模板保存到传感器或外部存储器)
fingerprint_status_t fingerprint_enroll_template(uint8_t template_id, const uint8_t *feature_buffer, uint32_t feature_size);

// 验证指纹 (比对采集的指纹与已注册的模板)
fingerprint_status_t fingerprint_verify(uint8_t template_id, uint8_t *score);

// 清空所有指纹模板
fingerprint_status_t fingerprint_clear_templates(void);

#endif // DRIVER_FINGERPRINT_H
  • driver_fingerprint.c (源文件,实现指纹传感器驱动接口,示例代码框架)
1
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
#include "driver_fingerprint.h"
#include "hal_delay.h" // 假设需要延时函数
#include "string.h" // memset

// 指纹传感器 SPI 片选引脚 (根据实际硬件连接配置)
#define FINGERPRINT_CS_PIN GPIO_PIN_2

// 指纹传感器复位引脚 (根据实际硬件连接配置)
#define FINGERPRINT_RST_PIN GPIO_PIN_3

// 指纹传感器电源引脚 (根据实际硬件连接配置)
#define FINGERPRINT_PWR_PIN GPIO_PIN_4

// 指纹图像缓冲区大小 (根据传感器规格和需求配置)
#define FINGERPRINT_IMAGE_BUFFER_SIZE 1024

// 指纹特征缓冲区大小 (根据传感器规格和需求配置)
#define FINGERPRINT_FEATURE_BUFFER_SIZE 256

// 内部缓冲区
static uint8_t s_image_buffer[FINGERPRINT_IMAGE_BUFFER_SIZE];
static uint8_t s_feature_buffer[FINGERPRINT_FEATURE_BUFFER_SIZE];

fingerprint_status_t fingerprint_init(void) {
// 初始化 GPIO 引脚 (CS, RST, PWR)
hal_gpio_init(FINGERPRINT_CS_PIN, GPIO_MODE_OUTPUT, GPIO_PULL_UP);
hal_gpio_init(FINGERPRINT_RST_PIN, GPIO_MODE_OUTPUT, GPIO_PULL_UP);
hal_gpio_init(FINGERPRINT_PWR_PIN, GPIO_MODE_OUTPUT, GPIO_PULL_UP);

// 初始化 SPI 接口 (根据实际使用的 SPI 接口配置)
hal_spi_init(SPI_CHANNEL_1, SPI_MODE_MASTER, SPI_BAUDRATE_DIV_8, SPI_CPOL_LOW, SPI_CPHA_1EDGE);

// 指纹传感器上电
hal_gpio_set_level(FINGERPRINT_PWR_PIN, GPIO_LEVEL_HIGH);
hal_delay_ms(10); // 延时等待传感器稳定

// 指纹传感器复位 (低电平复位)
hal_gpio_set_level(FINGERPRINT_RST_PIN, GPIO_LEVEL_LOW);
hal_delay_ms(10);
hal_gpio_set_level(FINGERPRINT_RST_PIN, GPIO_LEVEL_HIGH);
hal_delay_ms(50); // 延时等待传感器初始化完成

// 检测传感器是否初始化成功 (例如发送命令并检查响应)
// ... (具体实现根据传感器通信协议)

return FINGERPRINT_STATUS_OK; // 假设初始化成功
}

fingerprint_status_t fingerprint_capture_image(uint8_t *image_buffer, uint32_t buffer_size) {
if (buffer_size < FINGERPRINT_IMAGE_BUFFER_SIZE) {
return FINGERPRINT_STATUS_ERROR; // 缓冲区太小
}

// 发送采集图像命令给指纹传感器
// ... (具体实现根据传感器通信协议)

// 读取指纹图像数据 (从 SPI 接口接收)
// ... (具体实现根据传感器通信协议)
// 示例:假设使用 hal_spi_transfer 函数进行 SPI 数据传输
memset(s_image_buffer, 0, FINGERPRINT_IMAGE_BUFFER_SIZE);
hal_spi_transfer(SPI_CHANNEL_1, NULL, s_image_buffer, FINGERPRINT_IMAGE_BUFFER_SIZE);
memcpy(image_buffer, s_image_buffer, FINGERPRINT_IMAGE_BUFFER_SIZE); // 复制到用户缓冲区

// 检查采集结果 (例如检查传感器返回的状态码)
// ... (具体实现根据传感器通信协议)

// 检查是否检测到手指
// ... (具体实现根据传感器通信协议)
if (/* 没有检测到手指 */) {
return FINGERPRINT_STATUS_NO_FINGER;
}

return FINGERPRINT_STATUS_OK; // 假设采集成功
}

fingerprint_status_t fingerprint_extract_feature(const uint8_t *image_buffer, uint32_t buffer_size, uint8_t *feature_buffer, uint32_t *feature_size) {
if (buffer_size < FINGERPRINT_IMAGE_BUFFER_SIZE || *feature_size < FINGERPRINT_FEATURE_BUFFER_SIZE) {
return FINGERPRINT_STATUS_ERROR; // 缓冲区太小
}

// 发送提取特征命令给指纹传感器
// ... (具体实现根据传感器通信协议)

// 发送指纹图像数据给指纹传感器
// ... (具体实现根据传感器通信协议)
hal_spi_transfer(SPI_CHANNEL_1, (uint8_t*)image_buffer, NULL, FINGERPRINT_IMAGE_BUFFER_SIZE);

// 读取指纹特征数据 (从 SPI 接口接收)
// ... (具体实现根据传感器通信协议)
memset(s_feature_buffer, 0, FINGERPRINT_FEATURE_BUFFER_SIZE);
hal_spi_transfer(SPI_CHANNEL_1, NULL, s_feature_buffer, FINGERPRINT_FEATURE_BUFFER_SIZE);
memcpy(feature_buffer, s_feature_buffer, FINGERPRINT_FEATURE_BUFFER_SIZE); // 复制到用户缓冲区
*feature_size = FINGERPRINT_FEATURE_BUFFER_SIZE;

// 检查提取特征结果 (例如检查传感器返回的状态码)
// ... (具体实现根据传感器通信协议)

return FINGERPRINT_STATUS_OK; // 假设提取特征成功
}

fingerprint_status_t fingerprint_match_feature(const uint8_t *feature_buffer1, uint32_t feature_size1, const uint8_t *feature_buffer2, uint32_t feature_size2, uint8_t *score) {
// 在 MCU 端进行指纹特征比对 (软件比对,效率较低,但简单)
// 实际项目中,通常指纹传感器会自带硬件比对功能,效率更高
// 这里仅提供软件比对的示例框架

if (feature_size1 != feature_size2 || feature_size1 != FINGERPRINT_FEATURE_BUFFER_SIZE) {
return FINGERPRINT_STATUS_ERROR; // 特征数据大小不一致
}

uint32_t diff_count = 0;
for (uint32_t i = 0; i < feature_size1; ++i) {
if (feature_buffer1[i] != feature_buffer2[i]) {
diff_count++;
}
}

// 计算匹配得分 (简单示例:差异字节数越少,得分越高)
*score = (uint8_t)(100 - (diff_count * 100 / feature_size1));

// 设置匹配阈值 (根据实际测试调整)
uint8_t match_threshold = 80;
if (*score >= match_threshold) {
return FINGERPRINT_STATUS_OK; // 匹配成功
} else {
return FINGERPRINT_STATUS_ERROR; // 匹配失败
}
}

// ... (其他指纹传感器驱动函数的实现,例如 fingerprint_enroll_template, fingerprint_verify, fingerprint_clear_templates)

代码解释:

  • driver_fingerprint.h 定义了指纹传感器驱动的接口,例如 fingerprint_init 初始化传感器,fingerprint_capture_image 采集指纹图像,fingerprint_extract_feature 提取指纹特征,fingerprint_match_feature 比对指纹特征,fingerprint_enroll_template 注册指纹模板,fingerprint_verify 验证指纹,fingerprint_clear_templates 清空模板。
  • driver_fingerprint.c 实现了 driver_fingerprint.h 中定义的接口。代码中使用了 HAL 层的 GPIO 和 SPI 接口来控制指纹传感器和进行数据通信。
  • fingerprint_init 函数初始化 GPIO 引脚、SPI 接口,并对指纹传感器进行上电、复位等初始化操作。
  • fingerprint_capture_image 函数发送命令给指纹传感器采集图像,并通过 SPI 接口接收图像数据。
  • fingerprint_extract_feature 函数发送命令给指纹传感器提取特征,并将采集到的图像数据发送给传感器,然后通过 SPI 接口接收特征数据。
  • fingerprint_match_feature 函数演示了在 MCU 端进行软件指纹特征比对的简单实现。实际项目中,建议使用指纹传感器自带的硬件比对功能,效率更高。
  • 注意: 上述代码只是示例框架,实际指纹传感器驱动的实现需要根据具体的传感器型号和通信协议进行编写。需要查阅传感器的数据手册,了解其命令格式、数据格式、通信时序等细节。

3. 核心服务层 (指纹识别服务示例 - service_fingerprint_recognition.hservice_fingerprint_recognition.c)

  • service_fingerprint_recognition.h (头文件,定义指纹识别服务接口)
1
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
#ifndef SERVICE_FINGERPRINT_RECOGNITION_H
#define SERVICE_FINGERPRINT_RECOGNITION_H

#include "driver_fingerprint.h" // 引入指纹传感器驱动

typedef enum {
FINGERPRINT_RECOGNITION_STATUS_OK,
FINGERPRINT_RECOGNITION_STATUS_ERROR,
FINGERPRINT_RECOGNITION_STATUS_NO_FINGER,
FINGERPRINT_RECOGNITION_STATUS_MATCH_FAILED,
FINGERPRINT_RECOGNITION_STATUS_TIMEOUT,
// ... more status codes
} fingerprint_recognition_status_t;

// 初始化指纹识别服务
fingerprint_recognition_status_t fingerprint_recognition_init(void);

// 指纹注册 (用户录入指纹,保存模板)
fingerprint_recognition_status_t fingerprint_enroll(uint8_t template_id);

// 指纹验证 (用户指纹解锁)
fingerprint_recognition_status_t fingerprint_authentication(uint8_t *score);

// 清空所有指纹模板
fingerprint_recognition_status_t fingerprint_recognition_clear_templates(void);

#endif // SERVICE_FINGERPRINT_RECOGNITION_H
  • service_fingerprint_recognition.c (源文件,实现指纹识别服务接口,示例代码框架)
1
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
#include "service_fingerprint_recognition.h"
#include "stdio.h" // printf for debug

// 指纹模板存储位置 (例如 Flash 存储)
#define FINGERPRINT_TEMPLATE_STORAGE_ADDRESS 0x08080000 // Flash 起始地址
#define FINGERPRINT_TEMPLATE_SIZE 256 // 假设每个模板大小为 256 字节
#define MAX_FINGERPRINT_TEMPLATES 10 // 最大支持注册 10 个指纹模板

// 内部模板缓冲区 (用于临时存储从传感器读取的模板)
static uint8_t s_template_buffer[FINGERPRINT_TEMPLATE_SIZE];

fingerprint_recognition_status_t fingerprint_recognition_init(void) {
// 初始化指纹传感器驱动
fingerprint_status_t status = fingerprint_init();
if (status != FINGERPRINT_STATUS_OK) {
printf("Fingerprint sensor init failed!\r\n");
return FINGERPRINT_RECOGNITION_STATUS_ERROR;
}

printf("Fingerprint recognition service initialized.\r\n");
return FINGERPRINT_RECOGNITION_STATUS_OK;
}

fingerprint_recognition_status_t fingerprint_enroll(uint8_t template_id) {
if (template_id >= MAX_FINGERPRINT_TEMPLATES) {
printf("Invalid template ID!\r\n");
return FINGERPRINT_RECOGNITION_STATUS_ERROR;
}

printf("Start fingerprint enrollment for template ID: %d\r\n", template_id);

// 采集指纹图像 (多次采集,提高注册质量)
for (uint8_t i = 0; i < 3; ++i) {
printf("Place finger for %d time...\r\n", i + 1);
fingerprint_status_t capture_status = fingerprint_capture_image(s_template_buffer, FINGERPRINT_TEMPLATE_SIZE);
if (capture_status != FINGERPRINT_STATUS_OK) {
printf("Fingerprint capture failed, status: %d\r\n", capture_status);
return FINGERPRINT_RECOGNITION_STATUS_ERROR; // 注册失败
}
printf("Fingerprint captured successfully.\r\n");
hal_delay_ms(1000); // 延时 1 秒,提示用户移开手指
}

// 提取指纹特征
uint32_t feature_size = FINGERPRINT_TEMPLATE_SIZE; // 假设特征大小与模板大小相同
fingerprint_status_t extract_status = fingerprint_extract_feature(s_template_buffer, FINGERPRINT_TEMPLATE_SIZE, s_template_buffer, &feature_size);
if (extract_status != FINGERPRINT_STATUS_OK) {
printf("Feature extraction failed, status: %d\r\n", extract_status);
return FINGERPRINT_RECOGNITION_STATUS_ERROR; // 注册失败
}
printf("Feature extracted successfully.\r\n");

// 将指纹模板保存到 Flash 存储器
uint32_t template_address = FINGERPRINT_TEMPLATE_STORAGE_ADDRESS + template_id * FINGERPRINT_TEMPLATE_SIZE;
// ... (调用 Flash 驱动函数将 s_template_buffer 写入到 template_address)
// 示例:假设使用 flash_write 函数
// flash_write(template_address, s_template_buffer, FINGERPRINT_TEMPLATE_SIZE);
printf("Fingerprint template saved to Flash address: 0x%X\r\n", template_address);

printf("Fingerprint enrollment completed for template ID: %d\r\n", template_id);
return FINGERPRINT_RECOGNITION_STATUS_OK; // 注册成功
}

fingerprint_recognition_status_t fingerprint_authentication(uint8_t *score) {
printf("Start fingerprint authentication...\r\n");

// 采集指纹图像
fingerprint_status_t capture_status = fingerprint_capture_image(s_template_buffer, FINGERPRINT_TEMPLATE_SIZE);
if (capture_status != FINGERPRINT_STATUS_OK) {
if (capture_status == FINGERPRINT_STATUS_NO_FINGER) {
printf("No finger detected.\r\n");
return FINGERPRINT_RECOGNITION_STATUS_NO_FINGER; // 没有手指
} else {
printf("Fingerprint capture failed, status: %d\r\n", capture_status);
return FINGERPRINT_RECOGNITION_STATUS_ERROR; // 验证失败
}
}
printf("Fingerprint captured for authentication.\r\n");

// 提取指纹特征
uint32_t feature_size = FINGERPRINT_TEMPLATE_SIZE;
fingerprint_status_t extract_status = fingerprint_extract_feature(s_template_buffer, FINGERPRINT_TEMPLATE_SIZE, s_template_buffer, &feature_size);
if (extract_status != FINGERPRINT_STATUS_OK) {
printf("Feature extraction failed, status: %d\r\n", extract_status);
return FINGERPRINT_RECOGNITION_STATUS_ERROR; // 验证失败
}
printf("Feature extracted for authentication.\r\n");

// 遍历已注册的指纹模板,进行比对
for (uint8_t template_id = 0; template_id < MAX_FINGERPRINT_TEMPLATES; ++template_id) {
uint32_t template_address = FINGERPRINT_TEMPLATE_STORAGE_ADDRESS + template_id * FINGERPRINT_TEMPLATE_SIZE;
// ... (从 Flash 读取已注册的指纹模板到 s_template_buffer)
// 示例:假设使用 flash_read 函数
// flash_read(template_address, s_template_buffer, FINGERPRINT_TEMPLATE_SIZE);

// 比对指纹特征
uint8_t current_score = 0;
fingerprint_status_t match_status = fingerprint_match_feature(s_template_buffer, feature_size, s_template_buffer, feature_size, &current_score); // 注意:这里复用了 s_template_buffer,实际应用中需要使用不同的缓冲区
if (match_status == FINGERPRINT_STATUS_OK) {
printf("Fingerprint matched with template ID: %d, score: %d\r\n", template_id, current_score);
*score = current_score;
return FINGERPRINT_RECOGNITION_STATUS_OK; // 验证成功
} else {
printf("Fingerprint match failed with template ID: %d, status: %d\r\n", template_id, match_status);
}
}

printf("Fingerprint authentication failed.\r\n");
return FINGERPRINT_RECOGNITION_STATUS_MATCH_FAILED; // 验证失败,未找到匹配的模板
}

fingerprint_recognition_status_t fingerprint_recognition_clear_templates(void) {
printf("Clear all fingerprint templates...\r\n");
fingerprint_status_t status = fingerprint_clear_templates(); // 清空传感器内部模板 (如果传感器支持)
if (status != FINGERPRINT_STATUS_OK) {
printf("Fingerprint sensor clear templates failed, status: %d\r\n", status);
return FINGERPRINT_RECOGNITION_STATUS_ERROR;
}

// 清空 Flash 存储器中的模板数据
for (uint8_t template_id = 0; template_id < MAX_FINGERPRINT_TEMPLATES; ++template_id) {
uint32_t template_address = FINGERPRINT_TEMPLATE_STORAGE_ADDRESS + template_id * FINGERPRINT_TEMPLATE_SIZE;
// ... (调用 Flash 驱动函数擦除 template_address 区域)
// 示例:假设使用 flash_erase 函数
// flash_erase(template_address, FINGERPRINT_TEMPLATE_SIZE);
}

printf("All fingerprint templates cleared.\r\n");
return FINGERPRINT_RECOGNITION_STATUS_OK;
}

代码解释:

  • service_fingerprint_recognition.h 定义了指纹识别服务的接口,例如 fingerprint_recognition_init 初始化服务,fingerprint_enroll 指纹注册,fingerprint_authentication 指纹验证,fingerprint_recognition_clear_templates 清空模板。
  • service_fingerprint_recognition.c 实现了指纹识别服务的核心逻辑。它调用了底层的指纹传感器驱动程序 (driver_fingerprint.h) 来完成指纹采集、特征提取、比对等操作。
  • fingerprint_recognition_enroll 函数实现了指纹注册流程,包括多次采集指纹图像、提取特征、并将特征模板保存到 Flash 存储器中。
  • fingerprint_recognition_authentication 函数实现了指纹验证流程,包括采集指纹图像、提取特征、并与 Flash 存储器中已注册的模板进行比对,返回匹配得分。
  • fingerprint_recognition_clear_templates 函数清空指纹传感器内部和 Flash 存储器中的所有模板数据。
  • 注意: 代码中使用了 Flash 存储器来保存指纹模板。实际项目中,需要根据具体的 Flash 芯片和驱动程序进行 Flash 操作的实现(例如 Flash 的读写、擦除等)。代码中使用了 printf 函数进行调试信息输出,实际发布版本中应该移除或替换为更合适的日志记录机制。

4. 核心服务层 (电机控制服务示例 - service_motor_control.hservice_motor_control.c)

  • service_motor_control.h (头文件,定义电机控制服务接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef SERVICE_MOTOR_CONTROL_H
#define SERVICE_MOTOR_CONTROL_H

#include "hal_gpio.h" // 假设电机控制需要 GPIO 控制

typedef enum {
MOTOR_CONTROL_STATUS_OK,
MOTOR_CONTROL_STATUS_ERROR,
// ... more status codes
} motor_control_status_t;

// 初始化电机控制服务
motor_control_status_t motor_control_init(void);

// 开锁
motor_control_status_t motor_lock_open(void);

// 锁门
motor_control_status_t motor_lock_close(void);

#endif // SERVICE_MOTOR_CONTROL_H
  • service_motor_control.c (源文件,实现电机控制服务接口,示例代码框架)
1
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
#include "service_motor_control.h"
#include "hal_delay.h" // 假设需要延时函数

// 电机控制引脚 (根据实际硬件连接配置)
#define MOTOR_PIN_1 GPIO_PIN_5
#define MOTOR_PIN_2 GPIO_PIN_6

motor_control_status_t motor_control_init(void) {
// 初始化电机控制 GPIO 引脚 (输出模式)
hal_gpio_init(MOTOR_PIN_1, GPIO_MODE_OUTPUT, GPIO_PULL_NONE);
hal_gpio_init(MOTOR_PIN_2, GPIO_MODE_OUTPUT, GPIO_PULL_NONE);

// 初始状态:电机停止
hal_gpio_set_level(MOTOR_PIN_1, GPIO_LEVEL_LOW);
hal_gpio_set_level(MOTOR_PIN_2, GPIO_LEVEL_LOW);

return MOTOR_CONTROL_STATUS_OK;
}

motor_control_status_t motor_lock_open(void) {
printf("Opening lock...\r\n");
// 控制电机正转,开锁动作
hal_gpio_set_level(MOTOR_PIN_1, GPIO_LEVEL_HIGH);
hal_gpio_set_level(MOTOR_PIN_2, GPIO_LEVEL_LOW);
hal_delay_ms(500); // 延时 500ms (根据实际电机运行时间调整)

// 停止电机
hal_gpio_set_level(MOTOR_PIN_1, GPIO_LEVEL_LOW);
hal_gpio_set_level(MOTOR_PIN_2, GPIO_LEVEL_LOW);
printf("Lock opened.\r\n");
return MOTOR_CONTROL_STATUS_OK;
}

motor_control_status_t motor_lock_close(void) {
printf("Closing lock...\r\n");
// 控制电机反转,锁门动作
hal_gpio_set_level(MOTOR_PIN_1, GPIO_LEVEL_LOW);
hal_gpio_set_level(MOTOR_PIN_2, GPIO_LEVEL_HIGH);
hal_delay_ms(500); // 延时 500ms (根据实际电机运行时间调整)

// 停止电机
hal_gpio_set_level(MOTOR_PIN_1, GPIO_LEVEL_LOW);
hal_gpio_set_level(MOTOR_PIN_2, GPIO_LEVEL_LOW);
printf("Lock closed.\r\n");
return MOTOR_CONTROL_STATUS_OK;
}

代码解释:

  • service_motor_control.h 定义了电机控制服务的接口,例如 motor_control_init 初始化服务,motor_lock_open 开锁,motor_lock_close 锁门。
  • service_motor_control.c 实现了电机控制服务的逻辑。代码中使用了 HAL 层的 GPIO 接口来控制电机驱动模块。
  • motor_control_init 函数初始化电机控制 GPIO 引脚,并设置电机初始状态为停止。
  • motor_lock_open 函数控制电机正转,实现开锁动作,并延时一段时间后停止电机。
  • motor_lock_close 函数控制电机反转,实现锁门动作,并延时一段时间后停止电机。
  • 注意: 上述代码只是简单的直流电机控制示例,实际项目中,可能需要使用更复杂的电机驱动电路和控制算法,例如步进电机控制、PID 控制等,以实现更精确的门锁控制。电机运行时间需要根据实际的电机和门锁机构进行调整。

5. 应用层 (主应用程序示例 - main.c)

  • main.c (主应用程序,示例代码框架,基于裸机开发)
1
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
#include "hal_init.h" // 假设 HAL 初始化函数
#include "service_fingerprint_recognition.h"
#include "service_motor_control.h"
#include "stdio.h" // printf for debug

int main(void) {
// HAL 初始化 (时钟、外设等)
hal_system_init();

// 初始化指纹识别服务
fingerprint_recognition_init();

// 初始化电机控制服务
motor_control_init();

printf("System initialized.\r\n");

while (1) {
// 主循环

// 模拟指纹验证流程 (实际应用中需要按键触发或传感器检测到手指)
uint8_t score = 0;
fingerprint_recognition_status_t auth_status = fingerprint_authentication(&score);
if (auth_status == FINGERPRINT_RECOGNITION_STATUS_OK) {
printf("Fingerprint authentication successful, score: %d\r\n", score);
motor_control_lock_open(); // 开锁
hal_delay_ms(5000); // 保持开锁状态 5 秒
motor_control_lock_close(); // 锁门
printf("Lock closed.\r\n");
} else if (auth_status == FINGERPRINT_RECOGNITION_STATUS_NO_FINGER) {
// 没有检测到手指,忽略
} else {
printf("Fingerprint authentication failed, status: %d\r\n", auth_status);
}

hal_delay_ms(100); // 循环延时
}
}

代码解释:

  • main.c 是主应用程序的入口点。
  • hal_system_init() 函数负责 HAL 层的初始化,例如时钟配置、外设初始化等(需要根据具体的硬件平台和 HAL 库进行实现)。
  • fingerprint_recognition_init() 初始化指纹识别服务。
  • motor_control_init() 初始化电机控制服务。
  • while(1) 循环是主循环,程序在此循环中不断运行。
  • 在主循环中,模拟指纹验证流程:调用 fingerprint_authentication 函数进行指纹验证,如果验证成功,则调用 motor_control_lock_open 开锁,延时一段时间后调用 motor_control_lock_close 锁门。
  • hal_delay_ms() 函数提供延时功能(需要 HAL 层实现)。
  • 注意: 上述 main.c 代码只是一个简单的示例,实际应用中需要根据具体的需求添加更多的功能和逻辑,例如 APP 遥控开门、状态指示、错误处理、低功耗管理等。

三、项目中采用的技术和方法 (实践验证)

  1. 分层模块化架构: 前面已经详细说明,这种架构是构建复杂嵌入式系统的有效方法,提高了代码的可维护性、可扩展性和可移植性。

  2. 硬件抽象层 (HAL): HAL 层屏蔽了底层硬件的差异,使得上层代码可以独立于具体的硬件平台进行开发。这提高了代码的可移植性,方便将系统移植到不同的 MCU 平台。

  3. 设备驱动程序: 针对不同的硬件设备编写独立的驱动程序,例如指纹传感器驱动、蓝牙/Wi-Fi 驱动、电机驱动等。驱动程序负责与硬件设备进行交互,提供上层模块可以调用的 API。这种方式使得设备管理更加清晰和模块化。

  4. 状态机 (State Machine): 可以使用状态机来管理系统的各种状态和状态转换,例如锁定状态、解锁状态、指纹注册状态、联网状态等。状态机可以使系统逻辑更加清晰和易于理解,方便状态管理和事件处理。

  5. 事件驱动编程 (Event-Driven Programming): 对于需要响应外部事件的系统,例如按键事件、传感器事件、网络事件等,可以采用事件驱动编程模型。系统在空闲时等待事件发生,当事件发生时,触发相应的事件处理函数。这种方式可以提高系统的实时性和响应速度。

  6. 中断处理 (Interrupt Handling): 对于需要快速响应的外部事件,可以使用中断机制。例如,指纹传感器检测到手指触摸时,可以触发中断,MCU 在中断服务例程中快速响应,采集指纹数据。中断处理需要注意实时性和优先级管理。

  7. 低功耗设计 (Low Power Design): 对于电池供电的嵌入式设备,低功耗设计至关重要。可以采用以下技术:

    • 选择低功耗 MCU: 例如 STM32L4 系列、ESP32-S2/S3 等。
    • 电源管理模式: 利用 MCU 的低功耗模式,例如睡眠模式、停机模式等,在系统空闲时降低功耗。
    • 外设时钟管理: 只使能需要使用的外设时钟,关闭不使用的外设时钟。
    • 降低工作频率: 在满足性能需求的前提下,尽可能降低 MCU 的工作频率。
    • 优化代码: 避免不必要的运算和操作,减少 CPU 和外设的活动时间。
    • 使用低功耗外设: 选择低功耗的指纹传感器、蓝牙/Wi-Fi 模块等。
  8. 安全设计 (Security Design): 为了保障指纹锁的安全性,需要考虑以下方面:

    • 指纹数据加密: 对指纹模板数据进行加密存储,防止泄露。
    • 通信加密: APP 与指纹锁之间的通信数据进行加密,防止中间人攻击。
    • 身份认证: APP 遥控开门需要进行身份认证,防止非法用户控制门锁。
    • 防重放攻击: 通信协议中需要加入防重放机制,防止攻击者截获并重放开锁命令。
    • 物理安全: 指纹锁的硬件设计需要考虑物理安全,例如防止暴力拆卸、防止通过外部接口非法访问系统等。
  9. 测试与验证 (Testing and Validation): 在系统开发过程中,需要进行充分的测试和验证,确保系统的功能、性能和可靠性满足需求。测试包括:

    • 单元测试 (Unit Testing): 对每个模块进行独立测试,验证模块的功能是否正确。
    • 集成测试 (Integration Testing): 测试模块之间的集成和交互,验证模块之间是否能正确协同工作。
    • 系统测试 (System Testing): 对整个系统进行全面测试,验证系统的整体功能、性能、安全性、稳定性等是否满足需求。
    • 用户测试 (User Testing): 邀请用户进行实际使用测试,收集用户反馈,改进系统易用性。
    • 性能测试 (Performance Testing): 测试系统的响应速度、功耗、资源占用等性能指标是否满足要求。
    • 安全测试 (Security Testing): 进行安全漏洞扫描和渗透测试,评估系统的安全性。
  10. 维护与升级 (Maintenance and Upgrade): 系统设计需要考虑后期的维护和升级:

    • 固件升级 (Firmware Upgrade): 支持固件在线升级 (OTA - Over-The-Air),方便修复 Bug、添加新功能。
    • 远程诊断: 支持远程诊断功能,方便排查和解决用户遇到的问题。
    • 模块化设计: 模块化设计使得系统更容易维护和升级,可以独立地修改和替换某个模块,而不会影响其他模块。
    • 日志记录: 系统需要具备日志记录功能,方便排查错误和分析问题。

四、总结

宿舍指纹锁项目是一个典型的嵌入式系统开发案例,涵盖了需求分析、架构设计、代码实现、测试验证和维护升级等完整流程。通过采用分层模块化架构、HAL 抽象、设备驱动、状态机、事件驱动、低功耗设计、安全设计等一系列实践验证的技术和方法,可以构建一个可靠、高效、可扩展的指纹锁系统平台。

提供的 C 代码示例只是核心模块的框架和关键逻辑,实际项目中需要根据具体的硬件平台、指纹传感器型号、蓝牙/Wi-Fi 模块型号等进行详细的开发和调试。同时,还需要根据实际需求添加更多的功能和完善代码细节,例如 APP 遥控开门、状态指示、错误处理、低功耗管理、安全加密等。

希望这份详细的说明和代码示例能帮助你理解嵌入式指纹锁系统的设计和实现,并为你的项目开发提供参考。开源项目是一个很好的学习和交流平台,期待你的项目开源,并欢迎加入技术交流群共同进步!

欢迎关注我的其它发布渠道