前言:什麼是 8×8 LED Matrix 點陣屏?
在 Arduino 專案中,8×8 LED Matrix(點陣屏) 是學習 多維陣列(Multi-dimensional Arrays) 與 動態掃描(Multiplexing) 最經典的顯示元件。
一個 8×8 點陣屏內部包含 64 顆 LED。如果每顆 LED 都需要獨立接線,將會消耗大量的腳位;但透過 列(Row)與行(Column)交叉矩陣結構,只需要 16 支引腳(上排 8 腳、下排 8 腳) 就能控制整組 64 顆 LED 的亮滅!
一、 8×8 LED 點陣屏工作原理與矩陣掃描
1. 矩陣網格(Row & Column)
8×8 點陣屏由 8 條「列線(Row)」與 8 條「行線(Column)」相交而成:
當某個交叉點的 列(Row)給予高電位(HIGH) 且 行(Column)給予低電位(LOW) 時,該位置的 LED 就會被點亮!
2. 視覺暫留與動態掃描(Multiplexing)
因為行列交叉會相互影響,我們無法一次性把不規則的圖形全部點亮。實務上是透過程式進行 「高速逐列掃描」:
每次只點亮第 1 列需要的點 熄滅 點亮第 2 列 熄滅 … 直到第 8 列。
只要掃描速度高於每秒 30 次(利用人眼視覺暫留 POV 特性),看起來就像是一個完整的靜止圖案或動畫!
二、 實驗材料與電路接線圖
🛠️ 所需材料清單
Arduino Uno R3 開發板 × 1
8×8 LED Matrix 點陣屏(16 Pin 裸件) × 1
實驗麵包板 × 1~2 塊
單芯線 / 杜邦線 × 16 根
🛍️ 準備好你的硬體工具了嗎?
推薦選購:米羅科技 – Arduino 程式學習爆款套件組(包含 8×8 點陣屏、各式基礎與進階電子元件)
🔌 精確引腳對照表 (1088AS 點陣屏 Arduino)
🛠️ 前置準備:安裝 FrequencyTimer2 程式庫
在本實作中,我們需要透過 FrequencyTimer2 函式庫 來驅動 Arduino 內部的硬體計時器(Timer2),以實現背景自動掃描點陣屏的功能。請先完成以下程式庫安裝步驟:
下載 FrequencyTimer2 函式庫
點擊前往下載 .ZIP 程式庫壓縮檔
將 FrequencyTimer2 匯入 Arduino IDE
打開 Arduino IDE 整合開發環境。
在上方功能表點選:
草稿碼匯入程式庫加入 .ZIP 程式庫...選擇剛下載的
FrequencyTimer2.zip檔案即可完成安裝。
三、 多維陣列與動態掃描動畫程式實作
在本範例中,我們利用 FrequencyTimer2 函式庫 的硬體定時器中斷(Timer Interrupt)技術,讓 Arduino 在背景自動進行 8×8 點陣屏的高速動態掃描;而主程式 loop() 則專心處理動畫頁面的切換邏輯,實現流暢且無殘影的非阻塞式(Non-blocking)動畫顯示。
1. 完整標準排版程式碼(帶詳細註解)
#include <FrequencyTimer2.h>
#define SPACE { \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
#define H { \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 1, 1, 1, 1, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0}, \
{0, 1, 0, 0, 0, 0, 1, 0} \
}
#define I { \
{0, 1, 1, 1, 1, 1, 1, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 1, 1, 1, 1, 1, 1, 0} \
}
#define heart1 { \
{0, 1, 1, 0, 0, 1, 1, 0}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{0, 1, 1, 1, 1, 1, 1, 0}, \
{0, 0, 1, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
#define heart2 { \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 1, 1, 0, 0, 1, 1, 0}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{0, 1, 1, 1, 1, 1, 1, 0}, \
{0, 0, 1, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
#define heart3 { \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 1, 1, 0, 0, 1, 1, 0}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{1, 1, 1, 1, 1, 1, 1, 1}, \
{0, 1, 1, 1, 1, 1, 1, 0}, \
{0, 0, 1, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 0, 0, 0} \
}
#define Arrow { \
{0, 0, 0, 0, 1, 0, 0, 0}, \
{0, 0, 0, 1, 1, 1, 0, 0}, \
{0, 0, 1, 1, 1, 1, 1, 0}, \
{0, 1, 1, 1, 1, 1, 1, 1}, \
{0, 0, 0, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 1, 0, 0}, \
{0, 0, 0, 1, 1, 1, 0, 0} \
}
byte col = 0;
byte leds[8][8];
// pin[xx] on led matrix connected to nn on Arduino (-1 is dummy to make array start at pos 1)
int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6};
// col[xx] of leds = pin yy on led matrix
int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]};
// row[xx] of leds = pin yy on led matrix
int rows[8] = {pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]};
const int numPatterns = 8;
byte patterns[numPatterns][8][8] = {
H,I,heart1,heart2,heart3,Arrow,SPACE
};
int pattern = 0;
void setup() {
// sets the pins as output
for (int i = 1; i <= 16; i++) {
pinMode(pins[i], OUTPUT);
}
// set up cols and rows
for (int i = 1; i <= 8; i++) {
digitalWrite(cols[i - 1], LOW);
}
for (int i = 1; i <= 8; i++) {
digitalWrite(rows[i - 1], LOW);
}
clearLeds();
// Turn off toggling of pin 11
FrequencyTimer2::disable();
// Set refresh rate (interrupt timeout period)
FrequencyTimer2::setPeriod(2000);
// Set interrupt routine to be called
FrequencyTimer2::setOnOverflow(display);
}
void loop() {
for (int i = 0; i < numPatterns; i++) {
setPattern(i);
delay(1000);
}
}
void clearLeds() {
// Clear display array
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
leds[i][j] = 1;
}
}
}
void setPattern(int pattern) {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
leds[i][j] = patterns[pattern][i][j];
}
}
}
// Interrupt routine
void display() {
digitalWrite(cols[col], LOW);
col++;
if (col == 8) {
col = 0;
}
for (int row = 0; row < 8; row++) {
if (leds[col][7 - row] == 1) {
digitalWrite(rows[row], LOW);
}
else {
digitalWrite(rows[row], HIGH);
}
}
digitalWrite(cols[col], HIGH);
}
💡 核心技術剖析與亮點解讀
1. 三維陣列 patterns[numPatterns][8][8] 的結構
第一維
[numPatterns](頁碼):代表動畫總共有多少張連續畫面(動畫幀)。本範例共有 8 幀(H,I,heart1,heart2,heart3,Arrow,SPACE)。第二維與第三維
[8][8](點陣圖案):每一幀都是由 8 列 8 行的0與1矩陣組成。1:代表亮點(或熄滅,取決於邏輯判斷)。0:代表背景。
2. 為什麼要使用 FrequencyTimer2 中斷掃描?
在傳統掃描程式中,我們常會在 loop() 裡面寫 for 迴圈搭配 delay()。但這會導致兩個致命缺點:
畫面閃爍 (Flicker):如果
loop()中有複雜的邏輯計算或delay(1000),掃描就會停頓。CPU 被死綁:為了維護掃描,微控制器無法處理其他任務(例如讀取按鈕、感測器)。
FrequencyTimer2::setOnOverflow(display) 解決了這個問題!它利用晶片內部的Timer2,每隔 2000 微秒(2 毫秒)就會硬體強制暫停 loop(),自動進去執行 display() 掃描一格 Column,執行完後秒返回 loop()。這意味著:
掃描頻率:,完全超越人眼視覺暫留極限,絕無閃爍!
主程式解套:
loop()裡面的delay(1000)只影響「動畫換頁的速度」,完全不會卡到「畫面點亮與掃描」!
3. 1088AS 點陣屏腳位映射陣列
程式中的 pins[17]、cols[8] 與 rows[8] 巧妙地將 1088AS 的腳位(1~16)轉換為 Arduino 的 GPIO,讓複雜的交叉接線在程式庫內輕鬆實現軟體定序。
四、 常見問題與除錯 (FAQ)
Q1:點陣屏顯示圖案上下或左右顛倒?
解答: 1088AS 有方向性。請確認 Pin 1 位置,或直接在
display()程式碼中將7 - row改為row即可修正。
Q2:編譯時出現
FrequencyTimer2.h找不到的錯誤?
解答: 代表尚未安裝函式庫。請至 Arduino IDE 「工具」「管理函式庫」 搜尋
FrequencyTimer2並點擊安裝。
Q3:畫面出現殘影(Ghosting)或亮度太暗?
解答: 請確認
FrequencyTimer2::setPeriod()設定在1000~3000微秒之間(刷新率過低會閃爍),並確保切換 Column 前有先將前一列關閉。
🔗 延伸閱讀與推薦課程
📟 進階顯示模組控制:
🎛️ 類比輸入與動態控制:
🔊 聲音與頻率控制:
👈 上一篇教學:
📘 教學總索引:




