This website requires JavaScript.
優惠券 應用程式下載
寄往
部落格

Arduino LED 多工控制教學:用更少腳位控制更多 LED

最初發布於 Jun 30, 2026, 更新於 Jun 30, 2026

4 分鐘

目錄
  • 什麼是 Arduino LED 多工控制?
  • Arduino LED 多工控制技術比較
  • 如何製作 Arduino 8x8 LED 矩陣
  • 如何實作 Arduino LED Charlieplexing
  • Arduino LED 多工控制故障排除
  • 實用 Arduino LED 多工控制專案
  • 結論
  • Arduino LED 多工控制常見問題

Arduino Uno 是一款強大的原型開發工具,但如果直接驅動多顆 LED,很快就會耗盡它的 20 個 GPIO 腳位,以及 200 mA 的封裝總電流絕對最大限制。為了繞過這些硬體瓶頸,工程師與創客會使用 LED 多工控制,以更有效率地擴展顯示輸出,而不需要升級微控制器。

在本指南中,你將學到 LED 矩陣掃描、Charlieplexing、刷新時序、鬼影修正,以及實用 Arduino 程式碼的核心原理,而且不需要依賴任何外部驅動 IC 或擴充 IC。

什麼是 Arduino LED 多工控制?

Arduino Uno GPIO 限制說明

每一個基於 ATmega328P 的 Arduino Uno GPIO 腳位都有嚴格的電氣限制。

  • 絕對最大值:單一 GPIO 腳位在峰值、非連續條件下,最高可 source 或 sink 40 mA。
  • 建議限制:連續輸出的安全工作限制為每個腳位 20 mA 或更低。
  • 封裝總電流限制:關鍵在於,通過晶片 VCC 與 GND 腳位的總合電流不得超過 200 mA。

如果嘗試直接驅動 4x4 的 16 顆 LED 陣列,且每顆 LED 為 15 mA,總需求將達到 240 mA,可能造成矽晶片永久性熱損壞。

警告:

絕對不要在沒有電流限制電阻的情況下,將 LED 直接連接到微控制器腳位。這會造成過大的電流消耗,可能立即燒壞 LED 或 Arduino 本身。

LED 多工控制中的視覺暫留

LED 多工控制依賴一種稱為 視覺暫留(Persistence of Vision,PoV) 的生理現象。人眼無法察覺大約快於 50 至 100 Hz 的光強變化,也就是週期約 10 至 20 毫秒。

如果一顆 LED 亮起 1 毫秒,接著熄滅 9 毫秒,並且這個循環持續重複,人眼會把這些光脈衝整合起來。與其看到閃爍的光,我們會感知到連續但稍微較暗的光。透過高速依序循環一系列 LED,它們看起來就像同時亮起,形成穩定的顯示效果。

直接驅動 LED 與多工陣列

使用微控制器原生腳位直接驅動 LED,主要有兩種方式:

  • 直接驅動:透過限流電阻,將一顆 LED 連接到一個專用 GPIO 腳位。雖然程式簡單,但擴展性很差,因為每個光源都會消耗一整個腳位,而且很快就會碰到晶片封裝總電流限制。
  • 多工掃描:將 LED 排列成電氣網格,或使用特殊配置,例如 Charlieplexing。像素會共用實體連線,代表微控制器會在時間上快速切換特定線路,用較少腳位來定位個別座標。

Arduino LED 多工控制技術比較

下表整理了直接使用腳位擴展 LED 的核心取捨。

技術 所需腳位數量(64 顆 LED) CPU 負載 硬體複雜度 峰值電流壓力 最佳使用情境
直接驅動 64(Uno 無法實現) 非常低 少量狀態指示燈
列欄矩陣掃描 16(8 列 + 8 欄) 中等 高(共用腳位供電) 標準網格顯示、符號顯示
Charlieplexing 陣列 9 腳位(N x (N-1)) 非常高 低功耗穿戴裝置、徽章

列欄矩陣掃描:16 個腳位驅動 64 顆 LED

矩陣掃描會將 LED 排列成交錯的列與欄。透過將 64 顆 LED 組成 8x8 網格,我們可以將每一列的陽極連接在一起,並將每一欄的陰極連接在一起。這樣只需要 16 個腳位,就能單獨定位每一個像素,將實體腳位需求降低 75%,並簡化 Arduino LED 矩陣掃描邏輯。

Arduino LED Charlieplexing

Charlieplexing 是一種進階多工方法,利用微控制器 GPIO 腳位的三態邏輯(HIGH、LOW 與高阻抗 INPUT)。透過將 LED 以反向並聯成對放置,Charlieplexing 能有效擴展,讓 N 個腳位驅動 N * (N - 1) 顆 LED。

LED 矩陣與 Charlieplexing 比較

  • 腳位效率:Charlieplexing 的腳位效率明顯更高。8x8 列欄矩陣需要 16 個腳位才能驅動 64 顆 LED,而 Charlieplexing 只需要 9 個腳位就能達到類似容量,最多可驅動 72 顆 LED。
  • 韌體複雜度:標準列欄掃描只需要在二進位 HIGH 與 LOW 狀態之間切換腳位。Charlieplexing 則需要在核心執行迴圈中,動態切換腳位方向,在輸出與高阻抗輸入之間切換。

選擇正確的多工方法

如果你需要一致亮度、較簡單的佈線,以及標準網格排列,請選擇列欄矩陣掃描。如果你的專案有非常嚴格的實體腳位限制,例如小型穿戴式設計,且可以接受較低的整體顯示工作週期,則可選擇 Charlieplexing。

如何製作 Arduino 8x8 LED 矩陣

8x8 矩陣是學習網格控制的理想起點。

共陽極與共陰極 LED 矩陣

由於 8x8 LED 矩陣是由交錯二極體組成的網格,因此每個矩陣在物理上同時具備共陽極與共陰極特性,取決於你分析的是哪一個軸。製造商的零售標示通常是指「列」的極性配置:

  • 列共陽極(欄共陰極):同一列中的所有 LED 共用陽極(正極),而欄連接到共用陰極(負極)。若要點亮某個像素,例如第 1 列第 1 欄,必須將第 1 列拉 HIGH(source),並將第 1 欄拉 LOW(sink)。
  • 列共陰極(欄共陽極):同一列中的所有 LED 共用陰極(負極),而欄連接到共用陽極(正極)。若要點亮像素,必須將第 1 列拉 LOW(sink),並將第 1 欄拉 HIGH(source)。

Arduino LED 矩陣接線圖

以下是標準列共陽極(欄共陰極)8x8 Arduino LED 矩陣的概念接線方式,由 Arduino 直接驅動。

8x8 列共陽極矩陣示意圖

圖:連接到 Arduino Uno 的 8x8 列共陽極(欄共陰極)LED 矩陣示意圖,顯示列腳位連接到陽極,欄腳位則透過電阻連接到陰極。

LED 矩陣電阻放置位置

你必須將限流電阻放在欄上,而不是列上;反之亦然,取決於正在掃描的軸。

  • 為什麼重要:如果你將電阻放在列上並以列掃描,該列中 LED 的亮度會根據同一列中有多少 LED 被點亮而改變。如果只有 1 顆 LED 亮起,它會很亮;如果 8 顆全亮,電流會被分配,導致它們非常暗。
  • 解法:每一條獨立驅動的列線或欄線配置一顆電阻。依掃描軸而定,例如列掃描或欄掃描,這能確保電流分布一致,並避免亮度不均,因為可用電流會在已啟用的 LED 之間共享。

可使用以下基本公式計算電阻值:

計算電阻值的公式

以標準 5V 電源來說,可參考下表快速計算:

LED 顏色 典型 V_forward 5V 下建議電阻(約 15 mA)
紅色 2.0V 220 ohms
綠色 2.2V 220 ohms
藍色 3.2V 120 ohms
黃色 2.1V 220 ohms

警告:

脈衝電流必須嚴格保持在 LED 資料表限制範圍內。雖然脈衝工作週期允許較高峰值電流,但如果程式錯誤導致掃描停止,而高電流仍維持啟用,LED 很快就會燒毀。

Arduino LED 矩陣刷新率計算

為了達到穩定顯示並消除可見閃爍,矩陣必須每秒至少完整掃描 60 次(60 Hz)。若要得到順暢刷新效果,建議使用 100 Hz 至 200 Hz。若要避免智慧型手機相機的 rolling-shutter 閃爍,可能還需要更高刷新率。

矩陣尺寸 掃描方法 最低刷新率 目標刷新率 每列/欄啟用時間
4x4
逐列掃描
(4 個步驟)
60 Hz 100 Hz 2.50 ms
8x8
逐列掃描
(8 個步驟)
60 Hz 100 Hz 1.25 ms(1250 us)
16x16
逐列掃描
(16 個步驟)
80 Hz 200 Hz 0.31 ms(312 us)

以一個 8 列矩陣為例,若以 100 Hz 一次掃描一列:

總畫面週期 = 1 / 100 Hz = 10 ms

每列啟用時間 = 10 ms / 8 列 = 1.25 ms(1250 微秒)

Arduino 必須每 1.25 毫秒切換一次列。

Arduino 8x8 LED 矩陣 millis() 程式碼

使用非阻塞式 millis() 或 micros() 計時非常重要,這樣 Arduino 才能在更新顯示器的同時處理其他任務,例如讀取感測器或序列通訊。

程式碼重點:

  • 初始化列與欄:在 setup() 中設定腳位方向與基準關閉狀態。
  • 使用非阻塞 micros():執行低負載排程器,根據經過時間觸發刷新狀態,而不是使用阻塞式 delay()。
  • 每個掃描週期更新一列:選擇性將列拉 HIGH,並將啟用欄拉 LOW,每個 tick 逐列切換。
C/C++
// 全域變數與圖案定義
const int rowPins[8] = {13, 12, 11, 10, 9, 8, 7, 6};
const int colPins[8] = {5, 4, 3, 2, A5, A4, A3, A2};

byte heartPattern[8] = {
  B00000000,
  B01100110,
  B11111111,
  B11111111,
  B11111111,
  B01111110,
  B00111100,
  B00000000
};

unsigned long lastScanTime = 0;
const unsigned long scanInterval = 1250;
int currentRow = 0;
C/C++
// Setup 函式
void setup() {
  for (int i = 0; i < 8; i++) {
    pinMode(rowPins[i], OUTPUT);
    pinMode(colPins[i], OUTPUT);
    digitalWrite(rowPins[i], LOW);
    digitalWrite(colPins[i], HIGH);
  }
}
C/C++
// 主迴圈
void loop() {
  unsigned long currentMicros = micros();
  if (currentMicros - lastScanTime >= scanInterval) {
    lastScanTime = currentMicros;
    digitalWrite(rowPins[currentRow], LOW);
    for (int col = 0; col < 8; col++) {
      digitalWrite(colPins[col], HIGH);
    }
    currentRow = (currentRow + 1) % 8;
    for (int col = 0; col < 8; col++) {
      if (bitRead(heartPattern[currentRow], 7 - col) == 1) {
        digitalWrite(colPins[col], LOW);
      }
    }
    digitalWrite(rowPins[currentRow], HIGH);
  }
}

上方使用的標準 digitalWrite() 函式簡單且非常適合教學清楚呈現,但速度相對較慢。每次呼叫 digitalWrite() 都會執行許多執行期間安全檢查,例如檢查腳位是否支援 PWM、解析連接埠暫存器查找表等,可能消耗最多 4 微秒的處理時間。

進階且對效能要求高的專案,常會透過直接連接埠操作來繞過這個限制,例如寫入 PORTD |= B00000100;,這可在單一時脈週期內執行,在 16 MHz 微控制器上只需 62.5 奈秒;或使用硬體計時器中斷,以達到最佳掃描效率。

Arduino LED 矩陣電流消耗

設計多工顯示器時,必須在峰值電流與平均電流之間取得平衡。

  • 峰值電流:當某一列或欄完全啟用時所抽取的最大電流。如果同一欄中有 8 顆 LED 同時亮起,驅動電路必須承受這個累積突波。
  • 平均電流:由於存在啟用工作週期,例如 8x8 矩陣中每一畫面的 1/8,單顆 LED 的平均功耗會比連續驅動低很多。
  • USB 電流限制:標準電腦 USB 2.0 連接埠供電電流限制為 500 mA。大型 Arduino LED 矩陣專案經常超出 USB 供電限制。若直接透過 USB 為多工陣列供電,請確保合併峰值電流,包括 Arduino 內部額外消耗約 50 mA,遠低於此門檻,以避免連接埠重置。

如何實作 Arduino LED Charlieplexing

Charlieplexing 是一種用最少腳位控制大量 LED 的高效率方法,但它需要精準控制腳位狀態。

Charlieplexing 的三態 GPIO 邏輯

標準微控制器腳位有三種狀態:HIGH(5V)、LOW(0V)與 INPUT。當設定為 INPUT 時,腳位會進入高阻抗(Hi-Z)狀態,作用如同開路。Charlieplexing 利用這個狀態來隔離特定 LED 對。任何沒有主動驅動當前畫面的腳位,都會被設定為輸入狀態,以阻斷電流流動。

Charlieplexing LED 數量公式

使用 N 個腳位最多可驅動的 LED 數量計算如下:

Charlieplexing LED 數量公式

這種數學擴展非常有效率。例如,3 個腳位只能控制 6 顆 LED,但只要增加到 6 個腳位,就可以驅動最多 30 顆 LED。

下表顯示隨著腳位增加,輸出規模如何快速提升:

控制腳位數(N) 最大 LED 數量 處於 High-Z 狀態的未使用腳位
3 6 1
4 12 2
5 20 3
6 30 4
10 90 8

Charlieplexing 接線圖

要理解 Charlieplexing 如何運作,將反向並聯 LED 配置的電路圖視覺化會很有幫助。以下是三個腳位控制六顆 LED 的 Charlieplexed 節點示意圖:

3 個 Arduino 腳位控制 6 顆 LED 的 Charlieplexing 圖

圖:Charlieplexing 電路圖,顯示 3 個 Arduino 腳位透過反向並聯 LED 對控制 6 顆 LED,並在每個腳位分支上配置電阻。

Arduino Charlieplexing pinMode() 程式碼

驅動單顆 LED 時,需要將 source 腳位設為 OUTPUT HIGH,將 sink 腳位設為 OUTPUT LOW,並將所有其他腳位設為 INPUT(Hi-Z)。

程式碼重點:

  • 清除先前啟用腳位:迭代所有腳位並將其重設為 INPUT,以確保沒有殘留路徑保持啟用。
  • 動態設定 source 與 sink:使用與目標 LED 對應的 switch-case 狀態機,重新配置腳位方向與狀態。
C/C++
// 腳位定義
const int pins[3] = {9, 10, 11};
C/C++
// turnOnLED() 輔助函式
void turnOnLED(int ledIndex) {
  for (int i = 0; i < 3; i++) {
    pinMode(pins[i], INPUT);
    digitalWrite(pins[i], LOW);
  }
  switch(ledIndex) {
    case 1:
      pinMode(pins[0], OUTPUT); digitalWrite(pins[0], HIGH);
      pinMode(pins[1], OUTPUT); digitalWrite(pins[1], LOW);
      break;
    case 2:
      pinMode(pins[1], OUTPUT); digitalWrite(pins[1], HIGH);
      pinMode(pins[0], OUTPUT); digitalWrite(pins[0], LOW);
      break;
    case 3:
      pinMode(pins[1], OUTPUT); digitalWrite(pins[1], HIGH);
      pinMode(pins[2], OUTPUT); digitalWrite(pins[2], LOW);
      break;
  }
}
C/C++
// Setup
void setup() {}
C/C++
// 主迴圈
void loop() {
  for (int i = 1; i <= 3; i++) {
    turnOnLED(i);
    delay(5);
  }
}

Charlieplexing 亮度限制

由於標準 Charlieplexing 實作一次只能點亮一顆 LED,隨著你加入更多 LED,任何單顆 LED 的工作週期都會顯著下降。如果你正在驅動 30 顆 LED,每顆 LED 最多只會在掃描畫面的 1/30 時間內亮起。這種低工作週期會讓顯示看起來明顯變暗。

Charlieplexing 鬼影修正

當漏電流經由替代二極體路徑流動,讓未啟用 LED 微微亮起時,就會產生鬼影。這通常是因為腳位狀態切換太慢,或使用了不匹配的 LED。請務必透過在切換啟用狀態之間加入極短的 blanking delay 來解決,例如將所有腳位設定為 INPUT 50 微秒。

Arduino LED 多工控制故障排除

#1 LED 閃爍修正:提高掃描速率

如果你看到明顯脈動,代表掃描速率太慢。提高計時器或中斷頻率,讓完整畫面刷新率超過 80–100 Hz。請保持 ISR(中斷服務常式)程式碼輕量,並避免使用 analogRead() 或 delay() 這類慢速函式。

#2 LED 過暗修正:降低工作週期損失

多工顯示器的亮度會是標準連續亮度的一小部分。為了補償,你可以讓 LED 以高於連續額定值的電流進行脈衝驅動。有些 LED 在低工作週期下支援較高脈衝電流。請先查閱 LED 資料表中的峰值脈衝限制,再降低電阻以提升亮度。

#3 多工顯示中的 LED 鬼影修正

如果啟用像素滲入鄰近欄位,原因通常是驅動腳位中的殘留電荷。在將啟用列拉高之前:

  1. 關閉所有欄,將其設定為高電位/非啟用狀態。
  2. 切換列。
  3. 重新開啟欄。

這個順序稱為 blanking,可防止狀態轉換期間出現漏電流。

#4 LED 整列或整欄不亮修正

如果整列或整欄無法亮起,通常很少是單顆 LED 燒壞造成。接線錯誤、短路或二極體方向錯誤,都可能讓整列或整欄失效。請使用萬用表的二極體測試模式檢查系統。如果你使用表面黏著元件(SMD),請在放大倍率下檢查電路板是否存在冷焊或焊點微裂。確保 PCB 上有正確的焊盤設計,可避免這些組裝問題。

#5 Charlieplexing 漏電流問題

Charlieplexing 對 LED 順向電壓差異非常敏感。如果你在同一组三態線路上混用紅色 LED(2.0V)與藍色 LED(3.2V),當腳位處於高阻抗模式時,電流會經由較低電壓 LED 洩漏,造成嚴重鬼影。請務必在 Charlieplexed 網路中使用順向電壓一致且匹配的相同 LED。

實用 Arduino LED 多工控制專案

#1 8x8 LED 矩陣動畫

使用直接 GPIO 矩陣掃描,你可以撰寫自訂陣列依序播放畫面,製作簡單的 8x8 像素藝術動畫、復古遊戲素材或狀態圖示,不需要額外硬體元件。

#2 4x4x4 LED 立方體多工控制

3D LED 立方體使用空間多工控制。透過將 16 個垂直欄的陽極直接連接到 16 個 Arduino GPIO 腳位,並使用 4 個獨立腳位依序切換 4 個共陰極水平平面,你就能在 3D 空間中個別定位所有 64 顆 LED。

#3 Charlieplexed LED 徽章

由於 Charlieplexing 完全不需要外部輔助 IC,因此非常適合小型、超輕量的穿戴式胸針與徽章。它能讓你只用 5 條細走線連接到微型微控制器,就運行 20 顆互動式狀態燈陣列。

#4 LED 矩陣專案的客製化 PCB

雖然麵包板非常適合原型開發,但多工 LED 電路很快就會變成一團雜亂跳線,導致連接鬆動、寄生電容與高電阻問題。

客製化 Arduino Uno Shield PCB 設計

圖:客製化 Arduino Uno Shield PCB 的 3D 渲染圖,顯示乾淨的走線、SMT 元件與 8x8 LED 矩陣。

準備好不再停留在麵包板原型了嗎?

客製化 PCB 可改善訊號完整性、簡化接線,並提高 LED 多工控制專案的長期可靠性。

你可以在 KiCad 或 EasyEDA 中設計乾淨的 Shield 佈局,匯出 Gerber 檔案,並上傳到 JLCPCB 報價頁面,取得高品質 PCB 製造服務。

取得免費報價

對於包含大量 SMD LED、電阻或驅動 IC 的設計,JLCPCB 也提供元件採購PCB 組裝服務。專業 SMT 組裝與回流焊可減少手工組裝工作,同時確保一致的製造品質。

結論

直接軟體式 LED 多工控制,讓小型微控制器能透過仔細的掃描時序與共用接線架構控制大型顯示器。雖然直接 GPIO 矩陣掃描與 Charlieplexing 對軟體處理要求較高,但它們提供了一種極低成本、極簡且非常具教育意義的方式,可繞過硬體腳位限制。

設計客製化佈局、匯出標準 Gerber,並使用像 JLCPCB PCB 組裝這樣的專業 SMT 製造服務,可確保完美 PCB 焊接與可靠顯示運作,讓你的電子專案達到商用品質完成度。

Arduino LED 多工控制常見問題

Q:Arduino 在沒有外部 IC 的情況下可以控制多少顆 LED?

使用標準直接驅動時,Arduino Uno 大約可以驅動 15–20 顆 LED。若使用 16 個腳位進行 8x8 直接矩陣掃描,可驅動 64 顆 LED。如果使用 18 個可用腳位實作 Charlieplexing,理論上最多可直接驅動 306 顆 LED(18 x 17)。

Q:Multiplexing 與 Charlieplexing 有什麼差異?

標準列欄多工控制使用網格,腳位會嚴格設定為二進位輸出(HIGH 或 LOW)。Charlieplexing 則利用微控制器腳位的三態邏輯,將未使用腳位設定為 INPUT(高阻抗),以隔離特定反向並聯二極體對,從而大幅降低腳位需求。

Q:LED 矩陣需要每顆 LED 都配置電阻嗎?

不需要。你只需要在掃描軸上的每一條啟用線配置一顆電阻,例如 8 條欄線上配置 8 顆電阻。這可確保在列掃描的任何瞬間,每一顆啟用 LED 都只會串接一顆電阻。

Q:為什麼多工 LED 會變暗?

因為多工 LED 是依序亮滅,它們的工作週期會下降。在 8 列掃描矩陣中,每顆 LED 只有 1/8 的時間處於啟用狀態,平均電流會大幅降低,因此在人眼看來會稍微變暗。

Q:避免閃爍的最低刷新率是多少?

要消除可見脈動,絕對最低刷新率為 60 Hz。若要舒適觀看且不造成眼睛疲勞,建議目標掃描率為 100 Hz 或更高。

持續學習