介绍
AS608 光学指纹传感器模块,内置DSP指纹算法,支持指纹录入/比对/搜索/删除,UART通信接口,512枚指纹模板容量,3.3V供电,适用于门禁、考勤等安防应用
AS608 光学指纹传感器模块,内置DSP指纹算法,支持指纹录入/比对/搜索/删除,UART通信接口,512枚指纹模板容量,3.3V供电,适用于门禁、考勤等安防应用
| 参数 | 值 |
|---|---|
| 主控芯片 | AS608 DSP |
| 工作温度 | -20℃~+60℃ |
| 工作电压 | 3.3V DC |
| 指纹容量 | 512枚 |
| 模块尺寸 | 46×21×24mm |
| 窗口尺寸 | 14×18mm |
| 识别速度 | <0.5秒 |
| 通信接口 | UART (TTL, 默认57600bps) |
| 传感器类型 | 光学指纹传感器 |
| 像素分辨率 | 500dpi |
# AS608 光学指纹传感器 — 代码例程
## 一、STM32 HAL 库驱动
```c
// as608.h
#ifndef __AS608_H__
#define __AS608_H__
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include <string.h>
/* ========== 配置 ========== */
#define AS608_UART huart2 // 更换为你的UART句柄
#define AS608_ADDR 0xFFFFFFFF
#define AS608_DEFAULT_PWD 0x00000000
#define AS608_MAX_TEMPLATES 512
/* ========== 指令码 ========== */
#define CMD_HANDSHAKE 0x01
#define CMD_GET_IMAGE 0x10
#define CMD_GEN_CHAR 0x20
#define CMD_MATCH 0x0B
#define CMD_SEARCH 0x04
#define CMD_MERGE 0x08 // 组合用 0x20 | 0x08
#define CMD_STORE 0x06
#define CMD_DELETE 0x0C // 配合 0x04
#define CMD_EMPTY 0x0D
#define CMD_TEMPLATE_COUNT 0x1A
/* ========== 应答包 ========== */
typedef struct {
uint8_t head[2];
uint32_t addr;
uint8_t identifier;
uint16_t length;
uint8_t confirm;
uint8_t data[256];
uint16_t checksum;
} AS608_Response;
/* ========== API ========== */
uint8_t AS608_Handshake(void);
uint8_t AS608_GetImage(void);
uint8_t AS608_GenChar(uint8_t bufID);
uint8_t AS608_MergeChar(void);
uint8_t AS608_StoreTemplate(uint16_t id);
uint8_t AS608_SearchFinger(uint16_t startID, uint16_t count, uint16_t *foundID, uint16_t *score);
uint8_t AS608_DeleteTemplate(uint16_t id);
uint8_t AS608_EmptyLibrary(void);
uint8_t AS608_GetTemplateCount(uint16_t *count);
uint8_t AS608_MatchFinger(uint16_t id, uint16_t *score);
#endif
```
```c
// as608.c
#include "as608.h"
static UART_HandleTypeDef *as608_uart = &AS608_UART;
static uint8_t rx_buf[256];
static AS608_Response response;
/* -------- 底层收发 -------- */
static uint16_t calc_checksum(uint8_t *pkt, uint16_t len) {
uint16_t sum = 0;
for (uint16_t i = 0; i < len; i++) sum += pkt[i];
return sum;
}
static void send_packet(uint8_t cmd, uint8_t *data, uint16_t dataLen) {
uint8_t pkt[256];
uint16_t pktLen = dataLen + 2; // cmd + data
uint8_t idx = 0;
pkt[idx++] = 0xEF; // 包头
pkt[idx++] = 0x01;
pkt[idx++] = (AS608_ADDR >> 24) & 0xFF; // 地址
pkt[idx++] = (AS608_ADDR >> 16) & 0xFF;
pkt[idx++] = (AS608_ADDR >> 8) & 0xFF;
pkt[idx++] = (AS608_ADDR) & 0xFF;
pkt[idx++] = 0x01; // 包标识
pkt[idx++] = (pktLen >> 8) & 0xFF;
pkt[idx++] = pktLen & 0xFF;
pkt[idx++] = cmd;
memcpy(pkt + idx, data, dataLen);
idx += dataLen;
uint16_t sum = calc_checksum(pkt + 6, idx - 6);
pkt[idx++] = (sum >> 8) & 0xFF;
pkt[idx++] = sum & 0xFF;
HAL_UART_Transmit(as608_uart, pkt, idx, 500);
}
static uint8_t recv_packet(void) {
memset(&response, 0, sizeof(response));
memset(rx_buf, 0, sizeof(rx_buf));
// 等待包头 0xEF01
uint8_t byte;
while (1) {
if (HAL_UART_Receive(as608_uart, &byte, 1, 1000) != HAL_OK) return 0;
if (byte == 0xEF) {
if (HAL_UART_Receive(as608_uart, &byte, 1, 100) != HAL_OK) continue;
if (byte == 0x01) break;
}
}
response.head[0] = 0xEF; response.head[1] = 0x01;
HAL_UART_Receive(as608_uart, rx_buf, 6, 500);
response.addr = ((uint32_t)rx_buf[0] << 24) | ((uint32_t)rx_buf[1] << 16) |
((uint32_t)rx_buf[2] << 8) | rx_buf[3];
response.identifier = rx_buf[4];
response.length = ((uint16_t)rx_buf[5] << 8) | rx_buf[6];
uint16_t dataLen = response.length - 2;
if (dataLen > 0) {
HAL_UART_Receive(as608_uart, response.data + 1, dataLen, 500);
response.confirm = response.data[1]; // 第一个字节是确认码
}
HAL_UART_Receive(as608_uart, rx_buf, 2, 500);
response.checksum = ((uint16_t)rx_buf[0] << 8) | rx_buf[1];
return 1;
}
/* -------- 握手 -------- */
uint8_t AS608_Handshake(void) {
uint8_t data[4];
data[0] = (AS608_DEFAULT_PWD >> 24) & 0xFF;
data[1] = (AS608_DEFAULT_PWD >> 16) & 0xFF;
data[2] = (AS608_DEFAULT_PWD >> 8) & 0xFF;
data[3] = AS608_DEFAULT_PWD & 0xFF;
send_packet(CMD_HANDSHAKE, data, 4);
if (!recv_packet()) return 0;
return (response.confirm == 0x00); // 0x00=ACK
}
/* -------- 获取图像 -------- */
uint8_t AS608_GetImage(void) {
send_packet(CMD_GET_IMAGE, NULL, 0);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 生成特征码 -------- */
uint8_t AS608_GenChar(uint8_t bufID) {
send_packet(CMD_GEN_CHAR, &bufID, 1);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 合并特征(注册用) -------- */
uint8_t AS608_MergeChar(void) {
send_packet(CMD_MERGE, NULL, 0);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 存储模板 -------- */
uint8_t AS608_StoreTemplate(uint16_t id) {
uint8_t data[3];
data[0] = 0x01; // Buffer ID(合并后存于Buffer1)
data[1] = (id >> 8) & 0xFF;
data[2] = id & 0xFF;
send_packet(CMD_STORE, data, 3);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 搜索指纹(1:N) -------- */
uint8_t AS608_SearchFinger(uint16_t startID, uint16_t count, uint16_t *foundID, uint16_t *score) {
uint8_t data[5];
data[0] = 0x01; // Buffer1
data[1] = (startID >> 8) & 0xFF;
data[2] = startID & 0xFF;
data[3] = (count >> 8) & 0xFF;
data[4] = count & 0xFF;
send_packet(CMD_SEARCH, data, 5);
if (!recv_packet()) return 0;
if (response.confirm == 0x00) {
*foundID = ((uint16_t)response.data[2] << 8) | response.data[3];
*score = ((uint16_t)response.data[4] << 8) | response.data[5];
return 1;
}
return 0; // 未找到
}
/* -------- 1:1比对 -------- */
uint8_t AS608_MatchFinger(uint16_t id, uint16_t *score) {
uint8_t data[3];
data[0] = 0x01;
data[1] = (id >> 8) & 0xFF;
data[2] = id & 0xFF;
send_packet(CMD_MATCH, data, 3);
if (!recv_packet()) return 0;
if (response.confirm == 0x00) {
*score = ((uint16_t)response.data[2] << 8) | response.data[3];
return 1;
}
return 0;
}
/* -------- 删除模板 -------- */
uint8_t AS608_DeleteTemplate(uint16_t id) {
uint8_t data[4];
data[0] = (id >> 8) & 0xFF;
data[1] = id & 0xFF;
data[2] = 0x00;
data[3] = 0x01; // 删除单个模板
send_packet(CMD_DELETE, data, 4);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 清空指纹库 -------- */
uint8_t AS608_EmptyLibrary(void) {
send_packet(CMD_EMPTY, NULL, 0);
if (!recv_packet()) return 0;
return (response.confirm == 0x00);
}
/* -------- 获取已注册模板数 -------- */
uint8_t AS608_GetTemplateCount(uint16_t *count) {
send_packet(CMD_TEMPLATE_COUNT, NULL, 0);
if (!recv_packet()) return 0;
if (response.confirm == 0x00) {
*count = ((uint16_t)response.data[2] << 8) | response.data[3];
return 1;
}
return 0;
}
```
### 完整应用:指纹录入+识别
```c
// main.c (STM32 指纹门禁示例)
#include "as608.h"
#include "stdio.h"
void SystemClock_Config(void);
static void MX_USART2_UART_Init(void);
char msg[64];
int main(void) {
HAL_Init();
SystemClock_Config();
MX_USART2_UART_Init();
uint16_t id, score;
// 1. 握手
if (AS608_Handshake()) {
printf("AS608 握手成功!\r\n");
} else {
printf("AS608 握手失败,请检查连接!\r\n");
while(1);
}
// 2. 查询已注册指纹数
uint16_t count;
AS608_GetTemplateCount(&count);
printf("已注册指纹: %d 枚\r\n", count);
// 3. 注册新指纹(录入到 ID=10)
printf("请按手指...\r\n");
HAL_Delay(2000);
if (AS608_GetImage()) {
printf("第一次图像采集成功\r\n");
if (AS608_GenChar(1)) {
printf("请再次按同一手指...\r\n");
HAL_Delay(2000);
if (AS608_GetImage()) {
if (AS608_GenChar(2)) {
if (AS608_MergeChar()) {
if (AS608_StoreTemplate(10)) {
printf("指纹注册成功! ID=10\r\n");
}
}
}
}
}
}
// 4. 循环识别
while (1) {
printf("请按手指识别...\r\n");
HAL_Delay(2000);
if (AS608_GetImage()) {
if (AS608_GenChar(1)) {
if (AS608_SearchFinger(1, 512, &id, &score)) {
sprintf(msg, "识别成功! ID=%d, 匹配度=%d\r\n", id, score);
printf("%s", msg);
// 此处可控制开门继电器
} else {
printf("未识别,请重试!\r\n");
}
}
}
HAL_Delay(500);
}
}
```
---
## 二、Arduino 平台例程
```cpp
// AS608_Arduino.ino
#include <SoftwareSerial.h>
SoftwareSerial as608Serial(10, 11); // RX=10, TX=11
#define AS608_ADDR 0xFFFFFFFF
#define AS608_DEFAULT_PWD 0x00000000
#define CMD_HANDSHAKE 0x01
#define CMD_GET_IMAGE 0x10
#define CMD_GEN_CHAR 0x20
#define CMD_MERGE 0x08
#define CMD_STORE 0x06
#define CMD_SEARCH 0x04
#define CMD_DELETE 0x0C
#define CMD_EMPTY 0x0D
uint8_t rxBuf[256];
void sendPacket(uint8_t cmd, uint8_t *data, uint16_t len) {
uint16_t pktLen = len + 2;
as608Serial.write(0xEF);
as608Serial.write(0x01);
as608Serial.write((AS608_ADDR >> 24) & 0xFF);
as608Serial.write((AS608_ADDR >> 16) & 0xFF);
as608Serial.write((AS608_ADDR >> 8) & 0xFF);
as608Serial.write(AS608_ADDR & 0xFF);
as608Serial.write(0x01);
as608Serial.write((pktLen >> 8) & 0xFF);
as608Serial.write(pktLen & 0xFF);
as608Serial.write(cmd);
uint16_t sum = 0x01 + ((pktLen >> 8) & 0xFF) + (pktLen & 0xFF) + cmd;
for (uint16_t i = 0; i < len; i++) {
as608Serial.write(data[i]);
sum += data[i];
}
as608Serial.write((sum >> 8) & 0xFF);
as608Serial.write(sum & 0xFF);
}
uint8_t recvPacket(uint8_t *confirm) {
unsigned long t = millis();
while (as608Serial.available() < 12) {
if (millis() - t > 1000) return 0;
}
uint8_t b;
while (as608Serial.available()) {
b = as608Serial.read();
if (b == 0xEF) break;
}
if (b != 0xEF) return 0;
if (as608Serial.read() != 0x01) return 0;
// 读取余下 10 字节头部
for (int i = 0; i < 6; i++) rxBuf[i] = as608Serial.read();
uint16_t dataLen = ((uint16_t)rxBuf[4] << 8 | rxBuf[5]) - 2;
for (uint16_t i = 0; i < dataLen; i++) rxBuf[i] = as608Serial.read();
*confirm = rxBuf[0];
// 丢弃校验和
while (as608Serial.available()) as608Serial.read();
return 1;
}
bool handshake() {
uint8_t data[4];
data[0] = (AS608_DEFAULT_PWD >> 24) & 0xFF;
data[1] = (AS608_DEFAULT_PWD >> 16) & 0xFF;
data[2] = (AS608_DEFAULT_PWD >> 8) & 0xFF;
data[3] = AS608_DEFAULT_PWD & 0xFF;
sendPacket(CMD_HANDSHAKE, data, 4);
uint8_t confirm;
if (recvPacket(&confirm)) return (confirm == 0x00);
return false;
}
bool getImage() {
sendPacket(CMD_GET_IMAGE, NULL, 0);
uint8_t confirm;
if (recvPacket(&confirm)) return (confirm == 0x00);
return false;
}
bool genChar(uint8_t bufID) {
sendPacket(CMD_GEN_CHAR, &bufID, 1);
uint8_t confirm;
if (recvPacket(&confirm)) return (confirm == 0x00);
return false;
}
bool mergeChar() {
sendPacket(CMD_MERGE, NULL, 0);
uint8_t confirm;
if (recvPacket(&confirm)) return (confirm == 0x00);
return false;
}
bool storeTemplate(uint16_t id) {
uint8_t data[3];
data[0] = 0x01;
data[1] = (id >> 8) & 0xFF;
data[2] = id & 0xFF;
sendPacket(CMD_STORE, data, 3);
uint8_t confirm;
if (recvPacket(&confirm)) return (confirm == 0x00);
return false;
}
bool searchFinger(uint16_t *foundID, uint16_t *score) {
uint8_t data[5] = {0x01, 0x00, 0x01, 0x02, 0x00}; // Buffer1, Start=1, Count=512
sendPacket(CMD_SEARCH, data, 5);
uint8_t confirm;
if (recvPacket(&confirm) && confirm == 0x00) {
*foundID = ((uint16_t)rxBuf[1] << 8) | rxBuf[2];
*score = ((uint16_t)rxBuf[3] << 8) | rxBuf[4];
return true;
}
return false;
}
void enrollFinger(uint16_t id) {
Serial.println("请按手指...");
delay(2000);
if (!getImage()) { Serial.println("采集失败!"); return; }
Serial.println("第一次采集 OK");
if (!genChar(1)) { Serial.println("特征提取失败!"); return; }
Serial.println("请再次按同一手指...");
delay(2000);
if (!getImage()) { Serial.println("采集失败!"); return; }
if (!genChar(2)) { Serial.println("特征提取失败!"); return; }
if (!mergeChar()) { Serial.println("合并失败!"); return; }
if (!storeTemplate(id)) { Serial.println("存储失败!"); return; }
Serial.print("指纹注册成功! ID=");
Serial.println(id);
}
void setup() {
Serial.begin(9600);
as608Serial.begin(57600);
delay(500);
if (handshake()) {
Serial.println("AS608 就绪!");
} else {
Serial.println("AS608 连接失败!");
while(1);
}
}
void loop() {
uint16_t id, score;
if (Serial.available()) {
char cmd = Serial.read();
if (cmd == 'e') {
Serial.print("输入注册ID(1-512): ");
while (!Serial.available());
uint16_t eid = Serial.parseInt();
enrollFinger(eid);
}
if (cmd == 's') {
Serial.println("请按手指识别...");
delay(2000);
if (getImage() && genChar(1)) {
if (searchFinger(&id, &score)) {
Serial.print("识别! ID=");
Serial.print(id);
Serial.print(", 匹配度=");
Serial.println(score);
} else {
Serial.println("未识别!");
}
}
}
}
}
```
---
## 三、使用说明
| 功能 | Arduino 串口命令 |
|------|------------------|
| 注册指纹 | 发送 `e` → 输入 ID → 录入两次 |
| 识别指纹 | 发送 `s` → 按手指 |
> **注意**:AS608 模块 RXD 为 3.3V 电平,Arduino Uno (5V) 需在 RXD 端串联 1kΩ 电阻并加 2kΩ 到 GND 做分压保护。
暂无参考文献