AS608

元器件
传感器
库存 350

介绍

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 + Arduino).md

# 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 做分压保护。

参考资料

暂无参考文献