ESP32 入門》用程式控制 LED超簡單!
用 ESP32 NodeMCU-32S 控制 LED。教學包含歐姆定律計算限流電阻、GPIO 腳位選擇、LED 閃爍程式,以及 LEDC 硬體 PWM 模組的詳細介紹與呼吸燈效果實作。
這篇我們從「歐姆定律(Ohm's law)」談起,為 LED 加上適當的電阻,讓它發亮;再來我們撰寫 Arduino 程式,讓麵包板上的 LED 閃爍起來!本篇以 ESP32 NodeMCU-32S 開發板為範例。
LED 基本知識
LED 燈(LED lamp)是利用發光二極體(LED)作為光源的燈具,一般使用半導體 LED 製成。LED 燈的壽命和發光效率可達白熾燈的數倍。

每種顏色的 LED 所需的順向電壓(Forward Voltage)都不太一樣:
| 顏色 | 順向電壓 |
|---|---|
| 紅色 | 1.8 – 2.2V |
| 綠色 | 2.0 – 3.5V |
| 藍色 | 3.0 – 3.5V |
| 白色 | 3.0 – 3.5V |
⚠️ 重要差異: Arduino Uno 的 GPIO 輸出是 5V,而 ESP32 的 GPIO 輸出是 3.3V。這代表 ESP32 所需的限流電阻值會跟 Arduino Uno 不同,而且 ESP32 的 GPIO 不能接受超過 3.3V 的輸入,千萬不要把 5V 直接接到 ESP32 的 GPIO 腳位!
歐姆定律計算電阻值
為了避免 LED 燒掉,我們必須加上限流電阻。需要多大的電阻呢?這可以透過「歐姆定律(Ohm's law)」算出來。

歐姆定律公式:
V = I R,電壓 = 電流x電阻
- V = 電壓(伏特,V)
- I = 電流(安培,A)
- R = 電阻(歐姆,Ω)
計算所需電阻值:
R= V / I,電阻 = 電壓 / 電流
以 ESP32 的 GPIO 輸出電壓 3.3V,紅色 LED 順向電壓以 2V 估算,5mm LED 需要的電流約 20mA(0.02A):
R = (3.3-2) / 0.02 = 65
計算結果是 65Ω,但一般套件中常見的電阻最小是 220Ω,用大一點的電阻是完全沒問題的(LED 只是稍微暗一些,但更安全)。所以我們就使用 220Ω 的電阻。
💡 小知識: 如果用 5V 算出來需要 150Ω ,用 3.3V 只需要 65Ω。但實務上都用 220Ω 就對了,安全又方便!
先把 LED 點亮(不寫程式)
在寫程式之前,我們先用 ESP32 開發板的 3.3V 電源,把 LED 直接點亮,練習一下接線。
所需材料
| 材料 | 數量 |
|---|---|
| ESP32 NodeMCU-32S 開發板 | 1 |
| 麵包板 | 1 |
| 5mm LED(任意顏色) | 1 |
| 220Ω 電阻 | 1 |
| 公對公杜邦線 | 2 條 |
| USB 傳輸線(Micro USB) | 1 |





接線方式
- 把 LED 插到麵包板上。LED 長腳是正極(+),短腳是負極(−),別接錯了!
- 用杜邦線把 ESP32 的 GND 接到 LED 的負極(短腳)。
- 電阻不分正負極,一腳接到 LED 的正極(長腳),另一腳接到 ESP32 的 3V3(3.3V 電源腳位)。
電流路徑:3V3 → 電阻 → LED 正極 → LED 負極 → GND

如果你的 ESP32 已經接上 USB 線供電,這時你就會看到 LED 亮起來囉!

用程式控制 LED 閃爍
接下來我們要寫程式,透過 ESP32 的 GPIO 腳位來控制 LED 的開關。
選擇 GPIO 腳位
ESP32 的 GPIO 腳位選擇比 Arduino Uno 複雜一些,有些腳位有特殊用途,不適合拿來做一般的數位輸出。以下是建議:
推薦使用的 GPIO: GPIO 2、4、5、16、17、18、19、21、22、23、25、26、27、32、33
避免使用的 GPIO:
- GPIO 6–11:連接內部 Flash 記憶體,不可使用
- GPIO 34、35、36、39:僅能作為輸入(input only),不能輸出
- GPIO 0、12、15:啟動時有特殊功能,建議避免
本篇教學我們使用 GPIO 27 來控制 LED。

修改接線
把原本接在 3V3 的那條杜邦線(連接電阻的那端),改接到 ESP32 的 GPIO 23。
ESP32 NodeMCU-32S
┌─────────────┐
│ │
│ GPIO 23 ●──┼──→ 電阻(220Ω) ──→ LED(+) ──→ LED(−) ──→ GND ●
│ │
│ GND ●──────┼─────────────────────────────────────────────┘
│ │
└─────────────┘
程式碼
在 Arduino IDE 中建立新檔案(或修改 Blink 範例),輸入以下程式碼:
// ESP32 LED 閃爍範例
// 使用 GPIO 27 控制外接 LED
const int LED_PIN = 27; // 定義 LED 連接的 GPIO 腳位
// setup() 函式:開機或重置時執行一次
void setup() {
pinMode(LED_PIN, OUTPUT); // 設定 GPIO 27 為輸出模式
}
// loop() 函式:重複執行
void loop() {
digitalWrite(LED_PIN, HIGH); // 點亮 LED(輸出 HIGH = 3.3V)
delay(1000); // 等待 1 秒
digitalWrite(LED_PIN, LOW); // 熄滅 LED(輸出 LOW = 0V)
delay(1000); // 等待 1 秒
}

Arduino IDE 設定
上傳程式前,請先確認 Arduino IDE 的設定已完成,這部份請看我們另一篇教學哦!

設定完成後,點選左上角的「上傳(Upload)」按鈕,把程式上傳到 ESP32。
💡 提示: 部分 ESP32 開發板在上傳時需要按住板子上的 BOOT 按鈕,等到 IDE 顯示「Connecting...」時按住,出現上傳進度後就可以放開。NodeMCU-32S 通常不需要手動按,因為它有自動下載電路。
上傳成功後,你就會看到 LED 開始一秒亮、一秒滅地閃爍了!
進階:用 PWM 控制 LED 亮度
ESP32 比 Arduino Uno 強大的地方之一,就是擁有硬體 LEDC(LED Control) 模組,可以用 PWM(脈波寬度調變)來精細控制 LED 的亮度,不只是開跟關而已。
什麼是 PWM?
PWM(Pulse Width Modulation,脈波寬度調變)是一種透過快速切換「開」和「關」來模擬類比輸出的技術。想像你在快速開關電燈開關——如果開的時間長、關的時間短,燈看起來就很亮;反之則看起來很暗。只要切換的速度夠快(超過人眼可辨識的頻率),我們就會感覺亮度是「連續」變化的。
PWM 訊號有兩個關鍵參數:
- 頻率(Frequency): 每秒切換開關的次數,單位是 Hz。頻率越高,閃爍越不明顯。控制 LED 亮度時,通常設定在 1000Hz 以上就夠了。
- 工作週期or占空比(Duty Cycle): 在一個週期中,訊號處於「HIGH」狀態的時間比例,通常以百分比或解析度數值表示。占空比 0% 代表全暗,100% 代表全亮。
占空比 25%(暗) 占空比 75%(亮)
┌──┐ ┌──────┐
│ │ │ │
─┘ └────────── ───┘ └──什麼是 LEDC?
LEDC 是 ESP32 內建的「LED 控制器」硬體模組,全名是 LED Control (LEDC)。雖然名字裡有 LED,但它本質上是一個功能強大的硬體 PWM 產生器,不只能控制 LED,也能驅動馬達、蜂鳴器等需要 PWM 訊號的裝置。
為什麼不直接用 analogWrite()?
在 Arduino Uno 上,我們習慣用 analogWrite() 來產生 PWM,但那其實是靠軟體模擬的,頻率固定在約 490Hz,解析度固定 8-bit,而且只有特定腳位(標有 ~ 符號)才能使用。
ESP32 的 LEDC 則完全不同,它是硬體層級的 PWM 控制器,有以下優勢:
| 特性 | Arduino Uno(軟體 PWM) | ESP32 LEDC(硬體 PWM) |
|---|---|---|
| 通道數 | 6 個(特定腳位) | 16 個獨立通道 |
| 頻率範圍 | 固定 ~490Hz | 10Hz ~ 40MHz(可調) |
| 解析度 | 固定 8-bit(0~255) | 1-bit ~ 16-bit(可調) |
| 硬體淡入淡出 | ❌ 無 | ✅ 支援自動漸變 |
| 可用腳位 | 僅限標有 ~ 的腳位 | 幾乎所有可輸出的 GPIO |
LEDC 的架構:Timer 與 Channel
LEDC 內部由 Timer(計時器) 和 Channel(通道) 兩層組成:
Timer 0 ──┬── Channel 0 ──→ GPIO 23(LED 1)
└── Channel 1 ──→ GPIO 25(LED 2)
Timer 1 ──┬── Channel 2 ──→ GPIO 26(馬達)
└── Channel 3 ──→ GPIO 27(蜂鳴器)- Timer 決定 PWM 的頻率和解析度。ESP32 有 4 個 Timer,每個 Timer 可以被 2 個 Channel 共用。
- Channel 決定 PWM 的占空比,並綁定到指定的 GPIO 腳位。共享同一個 Timer 的 Channel 頻率相同,但占空比可以各自不同。
也就是說,ESP32 最多可以同時輸出 16 組獨立的 PWM 訊號,其中可以有 8 種不同的頻率。
不過要注意的是,不同型號的 ESP32 晶片,LEDC 的通道數量和支援的模式不同:
| 晶片型號 | LEDC 通道數 | 速度模式 |
|---|---|---|
| ESP32(經典款) | 16 | 高速 + 低速各 8 個 |
| ESP32-S2 | 8 | 僅低速 |
| ESP32-S3 | 8 | 僅低速 |
| ESP32-C3 | 6 | 僅低速 |
| ESP32-C6 | 6 | 僅低速 |
| ESP32-H2 | 6 | 僅低速 |
只有經典 ESP32 支援高速模式,好處是改變 PWM 設定時,硬體會在下一個週期自動無縫切換,不會產生毛刺(glitch)。其他型號僅有低速模式,但 Arduino 函式庫已經在背後處理好了軟體觸發更新的細節,一般使用上完全不需要擔心。
頻率與解析度的取捨
頻率和解析度之間存在互相制約的關係:頻率越高,可用的解析度越低。這是因為 LEDC 的時脈(clock)資源有限,要在一個 PWM 週期內切出越多段(高解析度),週期就不能太短(低頻率)。
以下是幾組常見的搭配:
| 頻率 | 最大解析度 | 占空比階數 | 適用場景 |
|---|---|---|---|
| 1 kHz | 16-bit | 65,536 階 | 超精細亮度控制 |
| 5 kHz | 13-bit | 8,192 階 | LED 亮度控制(推薦) |
| 40 kHz | 10-bit | 1,024 階 | 馬達 PWM 控制 |
| 1 MHz | 6-bit | 64 階 | 高速訊號產生 |
| 40 MHz | 1-bit | 2 階 | 時脈訊號(僅開/關) |
對於 LED 亮度控制,5kHz + 8-bit(256 階) 是非常實用的組合,人眼完全感覺不到閃爍,256 階的亮度變化也足夠平滑。
Arduino Core 3.x 的 LEDC API
在 ESP32 Arduino Core 3.x 版本中,LEDC 的 API 做了大幅簡化,不再需要手動管理 channel 編號,系統會自動分配:
| 函式 | 說明 |
|---|---|
ledcAttach(pin, freq, resolution) | 設定 GPIO 腳位的 PWM 頻率與解析度(自動分配 channel) |
ledcAttachChannel(pin, freq, resolution, channel) | 手動指定 channel(進階用法) |
ledcWrite(pin, duty) | 設定指定腳位的占空比 |
ledcWriteTone(pin, freq) | 輸出指定頻率的方波(50% 占空比),適合蜂鳴器 |
ledcWriteNote(pin, note, octave) | 輸出音符頻率,例如 ledcWriteNote(pin, NOTE_C, 4) |
ledcDetach(pin) | 解除腳位的 LEDC 綁定 |
ledcChangeFrequency(pin, freq, resolution) | 動態修改頻率與解析度 |
ledcFade(pin, startDuty, endDuty, duration) | 硬體自動淡入淡出 |
⚠️ 注意: 如果你用的是舊版 Arduino Core 2.x,API 不同,需要使用ledcSetup(channel, freq, resolution)+ledcAttachPin(pin, channel)+ledcWrite(channel, duty)的寫法。3.x 已經移除了這些舊函式。
呼吸燈效果
以下程式讓 LED 產生漸亮漸暗的「呼吸燈」效果:
// ESP32 呼吸燈範例
// 使用 LEDC PWM 控制 LED 亮度
// 適用於 ESP32 Arduino Core 3.x 版本
const int LED_PIN = 27; // LED 連接的 GPIO 腳位
const int PWM_FREQ = 5000; // PWM 頻率 5000Hz
const int PWM_RESOLUTION = 8; // 解析度 8-bit(0~255)
void setup() {
// 設定 LEDC:直接綁定 GPIO,指定頻率與解析度
ledcAttach(LED_PIN, PWM_FREQ, PWM_RESOLUTION);
}
void loop() {
// 漸亮
for (int duty = 0; duty <= 255; duty++) {
ledcWrite(LED_PIN, duty); // 直接對 GPIO 腳位寫入 duty
delay(10);
}
// 漸暗
for (int duty = 255; duty >= 0; duty--) {
ledcWrite(LED_PIN, duty);
delay(10);
}
}
⚠️ 注意: 如果你使用的是 ESP32 Arduino Core 3.x 版本,LEDC API 有變動。上面的寫法適用於 2.x 版。3.x 版請改用ledcAttach(LED_PIN, PWM_FREQ, PWM_RESOLUTION)和ledcWrite(LED_PIN, duty)的新語法。
ESP32 vs Arduino Uno 差異整理
| 項目 | Arduino Uno | ESP32 NodeMCU-32S |
|---|---|---|
| GPIO 輸出電壓 | 5V | 3.3V |
| 建議限流電阻 | 150Ω(實用 220Ω) | 65Ω(實用 220Ω) |
| GPIO 腳位數量 | 14 個數位 + 6 個類比 | 多達 34 個 GPIO |
| PWM 功能 | 軟體模擬(analogWrite) | 硬體 LEDC 模組(16 通道) |
| 特殊限制 | 較少 | 部分 GPIO 有限制(僅輸入、啟動用途等) |
| 上傳設定 | 選板即可 | 需另外安裝 ESP32 開發板套件 |
| 板載 LED 腳位 | Pin 13(LED_BUILTIN) | GPIO 2(多數開發板) |
小結
這篇我們學會了:
- 用歐姆定律計算 ESP32 所需的限流電阻值
- 在麵包板上接線,用 ESP32 的 3.3V 電源直接點亮 LED
- 透過程式控制 GPIO 腳位,讓 LED 閃爍
- 用 ESP32 的 LEDC PWM 功能製作呼吸燈效果
下一篇我們會繼續探索更多 ESP32 的功能,敬請期待!





