AS608 光學指紋模組教學 :從採集到辨識完整實作
介紹如何使用 AS608 光學指紋模組搭配 Arduino,實作從採集到辨識的完整指紋門禁系統,涵蓋矩陣鍵盤輸入 ID、LCD 顯示結果、蜂鳴器音效回饋,附完整程式碼與接線說明。
你有沒有想過,要怎麼幫自己的 Arduino 專題加上指紋辨識功能?今天傑森要帶大家實作一個完整的指紋辨識系統,從「採集指紋」到「驗證身份」全部搞定,還會接上 LCD 顯示畫面和矩陣鍵盤,做出一個相當實用的門禁雛形。
你會學到什麼
- AS608 光學指紋模組的接線方式
- 用鍵盤輸入 ID,採集並儲存指紋
- 即時比對指紋,顯示通過 / 拒絕訊息
- 搭配 LCD I2C 顯示器和蜂鳴器音效
材料清單
| 材料 | 數量 |
|---|---|
| Arduino UNO(或相容板) | 1 |
| AS608 光學指紋模組 | 1 |
| I2C LCD 16x2(PCF8574 介面) | 1 |
| 4x3 矩陣鍵盤 | 1 |
| 蜂鳴器(主動或被動皆可) | 1 |
| 麵包板 + 杜邦線 | 若干 |
完整套件購買連結:傑森創工指紋辨識套件

函式庫安裝
本教學需要安裝三個函式庫,請在 Arduino IDE 的「程式庫管理員」搜尋並安裝:
- Adafruit Fingerprint Sensor Library
- LiquidCrystal_PCF8574
- Adafruit Keypad
接線方式
AS608 指紋模組
AS608 模組使用 UART 序列通訊。這裡我們用 SoftwareSerial,把 PIN 2 / PIN 3 模擬成 RX / TX。

| AS608 腳位 | Arduino 腳位 |
|---|---|
| VCC | 3.3V 或 5V(依模組規格) |
| GND | GND |
| TX | PIN 2(Arduino RX) |
| RX | PIN 3(Arduino TX) |
注意: AS608 的 TX 接到 Arduino 的 RX(PIN 2),RX 接到 Arduino 的 TX(PIN 3),別接反了。
I2C LCD
LCD 使用 I2C 介面,只需要 4 條線:
| LCD 腳位 | Arduino 腳位 |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
LCD 的 I2C 位址通常是0x27或0x3F,可以用 I2C Scanner 草稿碼確認。程式裡預設是0x3F,如果 LCD 沒有顯示,請改成0x27再試。
矩陣鍵盤(採集程式使用)
| 鍵盤腳位 | Arduino 腳位 |
|---|---|
| R1 | PIN 11 |
| R2 | PIN 10 |
| R3 | PIN 9 |
| R4 | PIN 8 |
| C1 | PIN 7 |
| C2 | PIN 6 |
| C3 | PIN 5 |
蜂鳴器
| 蜂鳴器腳位 | Arduino 腳位 |
|---|---|
| 正極 | PIN 4 |
| 負極 | GND |

範例一:採集指紋(enroll_test)
這支程式的功能是:透過矩陣鍵盤輸入 ID 編號(1~127),然後掃描手指兩次,把指紋特徵值儲存到 AS608 模組的內建快閃記憶體。
完整程式碼
#include <Adafruit_Fingerprint.h>
#include <LiquidCrystal_PCF8574.h>
#include "Adafruit_Keypad.h"
LiquidCrystal_PCF8574 lcd(0x3F); // 設定LCD的I2C位址
// 用 SoftwareSerial 設定 RX、TX
// PIN2 是 RX,接到 AS608 的 TX
// PIN3 是 TX,接到 AS608 的 RX
SoftwareSerial mySerial(2, 3);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
// 採集成功的旋律
int melody[] = { 262, 233, 415 };
int noteDurations[] = { 8, 4, 2 };
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {11, 10, 9, 8};
byte colPins[COLS] = {7, 6, 5};
Adafruit_Keypad customKeypad = Adafruit_Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
uint8_t id = 0;
int digits = 0;
int inputOK = 0;
char enterNumber[3];
void setup() {
Serial.begin(9600);
delay(100);
Serial.println("Fingerprint sensor enrollment");
finger.begin(57600); // AS608 的 Baud Rate
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1) { delay(1); }
}
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.clear();
customKeypad.begin();
}
void loop() {
lcd.setCursor(0, 0);
lcd.print("Enter ID Number:");
lcd.setCursor(digits, 1);
lcd.cursor();
lcd.blink();
customKeypad.tick();
while (customKeypad.available()) {
keypadEvent e = customKeypad.read();
if (e.bit.EVENT == KEY_JUST_RELEASED) {
if ((char)e.bit.KEY == '#') {
// # = 確認輸入
digits = 3;
if (id > 0 && id < 128) {
inputOK = 1;
Serial.println(id);
} else {
// ID 超出範圍,顯示錯誤
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error Number!");
lcd.setCursor(0, 1);
lcd.print("Try Again!");
delay(2000);
lcd.clear();
lcd.setCursor(0, 1);
lcd.cursor();
lcd.blink();
memset(enterNumber, 0, sizeof(enterNumber));
id = 0;
digits = 0;
}
} else if ((char)e.bit.KEY == '*') {
// * = 清除,重新輸入
lcd.clear();
lcd.setCursor(0, 1);
lcd.cursor();
lcd.blink();
memset(enterNumber, 0, sizeof(enterNumber));
id = 0;
digits = 0;
} else {
// 數字鍵,最多輸入 3 位
if (digits < 3) {
lcd.setCursor(digits, 1);
lcd.print((char)e.bit.KEY);
enterNumber[digits] = (char)e.bit.KEY;
id = atoi(enterNumber);
digits++;
}
}
}
}
delay(10);
if (inputOK == 1) {
inputOK = 0;
lcd.setCursor(0, 0);
lcd.print("Place You Finger");
lcd.noCursor();
lcd.noBlink();
while (!getFingerprintEnroll());
}
}
uint8_t getFingerprintEnroll() {
int p = -1;
Serial.print("Waiting for valid finger to enroll as #");
Serial.println(id);
// 第一次掃描
while (p != FINGERPRINT_OK) {
p = finger.getImage();
switch (p) {
case FINGERPRINT_OK: Serial.println("Image taken"); break;
case FINGERPRINT_NOFINGER: Serial.println("."); break;
default: break;
}
}
p = finger.image2Tz(1); // 轉換成特徵值,存到緩衝區 1
if (p != FINGERPRINT_OK) return p;
// 提示移開手指
Serial.println("Remove finger");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Remove finger");
delay(2000);
p = 0;
while (p != FINGERPRINT_NOFINGER) { p = finger.getImage(); }
// 第二次掃描(確認比對)
p = -1;
Serial.println("Place same finger again");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Place the same");
lcd.setCursor(0, 1);
lcd.print("finger again");
while (p != FINGERPRINT_OK) {
p = finger.getImage();
}
p = finger.image2Tz(2); // 轉換成特徵值,存到緩衝區 2
if (p != FINGERPRINT_OK) return p;
// 比對兩次特徵值,建立模型
p = finger.createModel();
if (p == FINGERPRINT_ENROLLMISMATCH) {
Serial.println("Fingerprints did not match");
return p;
} else if (p != FINGERPRINT_OK) return p;
// 儲存到指定 ID 的位置
p = finger.storeModel(id);
if (p == FINGERPRINT_OK) {
Serial.println("Stored!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Finger Stored!");
digits = 0;
id = 0;
playMusic();
delay(3000);
}
return p;
}
void playMusic() {
for (int thisNote = 0; thisNote < 3; thisNote++) {
int noteDuration = 1000 / noteDurations[thisNote];
tone(4, melody[thisNote], noteDuration);
delay(noteDuration * 1.30);
noTone(4);
}
}
操作流程說明 (很重要!)
- 接電後,LCD 顯示「Enter ID Number:」
- 用鍵盤輸入 1~127 之間的 ID,按
#確認(*可清除重輸) - LCD 顯示「Place You Finger」,把手指放上去
- LCD 顯示「Remove finger」,移開手指
- LCD 顯示「Place the same finger again」,再放一次同一根手指
- 兩次比對成功後,LCD 顯示「Finger Stored!」,蜂鳴器響三聲
ID 的有效範圍是 1~127,AS608 模組最多可以存 127 組指紋。
範例二:辨識指紋(fingerprint_test)
這支程式用來驗證手指是否已在資料庫中,並根據比對結果顯示對應人名(ACCESS GRANTED)或拒絕(ACCESS DENIED)。
完整程式碼
#include <Adafruit_Fingerprint.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x3F);
SoftwareSerial mySerial(2, 3);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
// 驗證通過的旋律
int melody[] = { 262, 233, 415 };
int noteDurations[] = { 8, 4, 2 };
// 驗證失敗的旋律
int melodyFail[] = { 110, 55 };
int noteDurationsFail[] = { 12, 2 };
void setup() {
Serial.begin(9600);
delay(100);
Serial.println("Fingerprint detect test");
finger.begin(57600);
delay(5);
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1) { delay(1); }
}
// 顯示目前模組內已有幾組指紋
finger.getTemplateCount();
Serial.print("Sensor contains ");
Serial.print(finger.templateCount);
Serial.println(" templates");
Serial.println("Waiting for valid finger...");
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Put your finger");
lcd.setCursor(0, 1);
lcd.print("for indentify..");
lcd.setCursor(15, 1);
lcd.blink(); // 右下角游標閃動,表示等待中
}
void loop() {
getFingerprintIDez();
delay(50);
}
int getFingerprintIDez() {
uint8_t p = finger.getImage();
if (p != FINGERPRINT_OK) return -1;
p = finger.image2Tz();
if (p != FINGERPRINT_OK) return -1;
p = finger.fingerFastSearch(); // 快速比對資料庫所有指紋
if (p != FINGERPRINT_OK) {
// 比對失敗
lcd.noBlink();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ACCESS DENIED!");
playMusicFail();
delay(3000);
// 回到等待畫面
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Put your finger");
lcd.setCursor(0, 1);
lcd.print("for indentify..");
lcd.setCursor(15, 1);
lcd.blink();
return -1;
}
// 比對成功,取得 ID 和信心分數
Serial.print("Found ID #");
Serial.print(finger.fingerID);
Serial.print(" with confidence of ");
Serial.println(finger.confidence);
// 信心分數 > 100 才算真正通過
if (finger.confidence > 100) {
// 設定每個 ID 對應的人名(請依實際情況修改)
// 注意:ID 沒有 0,所以 index 0 隨意填
char idname[][16] = {"Nobody", "Peter Chen", "Amy Wang", "Kelly Lee", "Jessica Wu"};
lcd.noBlink();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(idname[finger.fingerID]); // 顯示對應人名
lcd.setCursor(0, 1);
lcd.print("ACCESS GRANTED!");
playMusic();
delay(3000);
// 回到等待畫面
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Put your finger");
lcd.setCursor(0, 1);
lcd.print("for indentify..");
lcd.setCursor(15, 1);
lcd.blink();
}
return finger.fingerID;
}
void playMusic() {
for (int thisNote = 0; thisNote < 3; thisNote++) {
int noteDuration = 1000 / noteDurations[thisNote];
tone(4, melody[thisNote], noteDuration);
delay(noteDuration * 1.30);
noTone(4);
}
}
void playMusicFail() {
for (int thisNote = 0; thisNote < 2; thisNote++) {
int noteDuration = 1000 / noteDurationsFail[thisNote];
tone(4, melodyFail[thisNote], noteDuration);
delay(noteDuration * 1.30);
noTone(4);
}
}
操作流程說明
- 接LCD 顯示「Put your finger for indentify..」,右下角游標閃動
- 把手指放到模組上,程式自動開始比對
- 比對成功:LCD 第一行顯示對應人名,第二行顯示「ACCESS GRANTED!」,蜂鳴器播放三聲上揚旋律
- 比對失敗:LCD 顯示「ACCESS DENIED!」,蜂鳴器播放兩聲下降旋律
- 3 秒後自動回到等待畫面
關鍵程式解析
為什麼採集要掃兩次?
p = finger.image2Tz(1); // 第一次,存到緩衝區 1
// ... 等使用者移開手指、再放上去 ...
p = finger.image2Tz(2); // 第二次,存到緩衝區 2
p = finger.createModel(); // 比對兩個緩衝區,建立最終模型
AS608 採集指紋的流程需要掃描兩次,目的是確保特徵值夠穩定。兩次掃描結果會分別存進內部緩衝區 1 和緩衝區 2,再由 createModel() 合併建立最終的指紋模型,最後 storeModel(id) 才把模型存到指定 ID 的位置。
信心分數是什麼?
if (finger.confidence > 100) { ... }
finger.confidence 是比對的相似度分數,範圍 0~255,分數越高表示越吻合。程式設定大於 100 才算通過,這個門檻值可以依需求調整:
- 分數越高(例如 > 150),安全性更高,但比較容易被誤判為失敗
- 分數越低(例如 > 50),通過率高,但也比較容易被相似指紋騙過
人名對照表的設定
char idname[][16] = {"Nobody", "Peter Chen", "Amy Wang", "Kelly Lee", "Jessica Wu"};
lcd.print(idname[finger.fingerID]);
這個陣列的 index 對應的就是採集時設定的 ID。因為 AS608 的 ID 從 1 開始,所以 idname[0] 填 "Nobody" 佔位,idname[1] 對應 ID 1 的人,以此類推。
常見問題
Q:LCD 沒有顯示任何文字? A:先確認 I2C 位址。把 LCD 的位址從 0x3F 改成 0x27 試試,或是跑 I2C Scanner 確認實際位址。
Q:序列監控顯示「Did not find fingerprint sensor」? A:檢查 TX / RX 接線有沒有接反,以及 AS608 的電源是否正常(部分模組需要 3.3V,不可接 5V)。
Q:採集時顯示「Fingerprints did not match」? A:兩次掃描放的手指角度不同,導致特徵值差異太大。建議每次都盡量用相同的方式、相同的力道放上去。
Q:辨識時信心分數不到 100? A:先試著重新採集同一根手指,放手指的角度盡量保持一致,採集品質會影響後續辨識的分數。
如果覺得這篇教學有幫助,歡迎分享給同樣在玩 Arduino 的朋友!
套件購買:傑森創工 — 指紋辨識套件
