2026-01-05
Arduino 類比輸入與 PWM 調光教學:使用電位器控制 LED 亮度
前言
在上一篇(Arduino 數位輸出輸入教學),我們已經用 LM393 光敏模組練習了「數位輸入→判斷→數位輸出」:
用 digitalRead() 讀 HIGH/LOW,搭配 digitalWrite() 控制 LED 亮或滅,讓 Arduino 透過光敏模組來做出「有偵測到就開燈、沒偵測到就關燈」的開/關控制。
本篇,我們將介紹透過Arduino與類比輸入來設定「強弱程度」,讓 Arduino 從上一篇的「有沒有偵測到=開/關」推進到「偵測有多少=漸亮與漸暗」。
我們將會改用 電位器(旋鈕) 做為輸入,讓 Arduino 透過用類比輸入 analogRead() 讀到 0~1023 之間的數值,再用類比輸出analogWrite()(PWM)輸出 0~255 的亮度,完成「轉動旋鈕 → LED 連續變亮/變暗」的效果。
完成本篇後,你將能:理解「數位輸入 vs 類比輸入」的差別(0/1 與 0~1023 的不同)使用 analogRead() 讀取電位器旋鈕的數值使用 analogWrite()(PWM)控制 LED 亮度強弱使用 map() 把 0~1023 轉換成 0~255 的亮度範圍透過簡單延遲與數值處理,讓亮度變化看起來更平滑本篇會先帶你把電路接好、讓程式運作,看見「旋鈕→亮度」的對應關係 文章內容目錄從數位到類比:為什麼 Arduino 需要讀取連續變化的訊號?
Arduino類比輸入教學實作:電位器接線與 analogRead() 數值讀取
Arduino類比輸出教學實作:PWM 調光與 analogWrite() 應用
Arduino 專案實作:結合 map() 函數,打造電位器 LED 調光燈
Arduino PWM 進階觀念與延伸應用
小結與下一步:開啟你的自動化控制之路 從數位到類比:為什麼 Arduino 需要讀取連續變化的訊號?
Arduino 教學系列的上一篇內容,我們先接觸到的是數位數入與輸出 digitalRead() 與 digitalWrite() (延伸閱讀:Arduino 數位輸出輸入教學:以 LM393 光敏模組為例)。這類數位訊號就像家裡的電燈開關,只有「開(1)」與「關(0)」兩種狀態。對於簡單的感應報警或開關控制來說,數位訊號非常直覺且好用。然而,現實生活中的現象往往不是二選一的。如果你想製作出能根據環境「慢慢變亮」的氣氛燈、能夠調整風扇的「轉速快慢」,或是控制音量的「大聲小聲」。在這些情境下,只有開與關是不夠的,我們需要的是「強弱程度」的控制。接下來,我們要讓 Arduino 從只能判斷「有沒有」,進化到能感知「有多少」。透過下圖,我們可以直觀地看出數位(Digital)與類比(Analog)的差異:數位訊號:只有「開 (1)」與「關 (0)」兩種極端狀態,就像非黑即白的階梯。類比訊號:具有連續性的波動,可以停留在 0 到 1 之間的任何位置,就像平滑的斜坡。為了處理這種連續的「斜坡」訊號,Arduino 必須將類比訊號轉化為大腦(處理器)看得懂的數字,這就是我們接下來要學習的核心觀念。 類比訊號的輸入原理:Arduino 如何感知 0~1023 的變化? 類比訊號(Analog Signal)是一種連續變化的電壓,是讓 Arduino 可以讀到「強弱程度」的一種方式。為了讓處理器(Arduino)理解這些變化,Arduino 內建了「類比數位轉換器(ADC)」。它會將接收到的電壓(通常是 0V 到 5V)切分成 1024 個刻度,並對應成 0 到 1023 的數值。以我們最常用的「電位器(旋鈕)」為例,當你旋轉它時,電位器會改變內部電阻的大小,進而控制輸出的電壓強弱,送進 Arduino 的電壓會隨之改變,程式讀取到的數值也會跟著跳動:旋鈕轉到底(靠近 0V): 程式讀到的數值接近 0。旋鈕轉到中間(約 2.5V): 程式讀到的數值會在 512 左右。旋鈕轉到另一頭(靠近 5V): 程式讀到的數值接近 1023。
透過這種方式,Arduino 就能精準掌握旋鈕的位置或是感測器的強度。在接下來的章節中,我們將實際動手接線,並使用 analogRead() / analogWrite() 語法來觀察這些數字以及LED 亮度的平滑變化的變化。 補充說明:1.類比數位轉換器(ADC) ADC(Analog-to-Digital Converter)是 Arduino 內建的一種轉換機制,它就像是一把「數位量尺」。它會將接收到的連續電壓,依照高低細分成 1024 個小刻度,並對應成 0 到 1023 的數字。讓 Arduino 不只能判斷開或關,還能精確讀出訊號的「強弱程度」。 2. 電位器(Potentiometer)在本專案中扮演著「訊號來源」的角色。它本質上是一個可變電阻,你可以把它想像成一個「可以手動調整流量的水龍頭」。當旋轉旋鈕時,它會改變內部電阻的大小,進而控制輸出的電壓強弱。旋鈕轉到最左邊時輸出 0V;轉到最右邊時輸出 5V。這些變化會被 ADC 捕捉,轉換成我們程式中看到的數值。 3. 可變電阻(Variable Resistor)是電子電路中用來「控制電流大小」的零件。如果把電線比喻成水管,可變電阻就像是一個可以隨時調整鬆緊的夾子。我們最常看到的「電位器」就是可變電阻的一種,它讓我們能透過物理動作來改變電子訊號的強弱。當你調整可變電阻讓電阻變大時,電流就會變小(水流變慢);當電阻變小時,電流就會變大(水流變快)。
Arduino類比輸入教學實作:電位器接線與 analogRead() 數值讀取 接下來,我們實際操作 Arduino 的「類比輸入」。我們會使用在上一段提過,也是最常見的 電位器(可變電阻) 作為輸入源:透過轉動旋鈕,手動改變輸入到 Arduino 的電壓大小。前面提過 ADC 像一把「數位量尺」,現在我們將電位器接入類比腳位,並透過analogRead() 指令觀察這把量尺如何將 0~5V 的連續電壓,轉化為程式裡的 0~1023 整數。這個步驟,就是把「轉動旋鈕」這個物理動作,轉換成程式可以運算的數位數值。只要理解這一層:「類比輸入→ 數字 → 後續控制」,而這正是所有感測器控制的核心起點。 Arduino與電位器接線重點:如何連接 A0 腳位(VCC/GND/Signal)
在 Arduino 開發板上,類比輸入有專屬的區域,通常標示為 ANALOG IN (A0 到 A5)。接線時,電位器的三支腳位分別承擔不同的任務,請參考以下對應關係: 電位器接腳 (正面朝己)Arduino 腳位功能說明左側腳位GND接地,建立電壓參考點中間腳位 (訊號腳)A0輸出變動電壓給 Arduino 讀取右側腳位5V提供電力來源左側腳位: 連接到 Arduino 的 GND。右側腳位: 連接到 Arduino 的 5V。這兩根腳負責提供電壓環境,誰左誰右只會決定你旋轉時數值增加的方向不同(順時針變大或逆時針變大)。如果你發現旋鈕「往右轉數值反而變小」,只需要將 5V 與 GND 的兩根線對調即可,中間的 A0 訊號線保持不動。中間腳位(訊號輸出): 這是最關鍵的一根腳,請連接到 Arduino 的 A0 腳位。 總結來說,你可以用一個簡單比喻來理解:左右兩腳是「拉出一條 5V 到 GND 的斜坡」;中間接腳是「在斜坡上找一個位置,回報現在的高度」轉動旋鈕時,中間腳輸出的電壓就會在 0V 和 5V 之間變動,A0 腳位就是在量「這個中間點現在大概有多高」,會把它看成 0~1023 的數值。 小提醒: 如果發現序列埠監測器的數字在跳動,或是停在 0/1023 不動,通常是因為中間的訊號腳接觸不良,或是電位器與 Arduino 沒有「共地(GND)」所導致。如果有外接電源或其他模組,也要共享同一個 GND。沒共地時,讀出來的數值很容易亂跳,甚至會有數字看起來不合理的狀況。 序列埠監測器觀測:使用 analogRead() 驗證實測步驟 接線完成後,我們要做一件事:「確認 Arduino 真的有把旋鈕位置讀成數字」,方法就是用透過一段簡單 analogRead 程式碼讀出來,將讀取到的類比數值透過序列埠視窗顯示。流程上會是把 Arduino 用 USB 接到電腦後、在 Arduino IDE 開啟新的草稿、撰寫測試用核心程式(告訴 Arduino 要讀 A0、把讀到的值印出來’、每隔一小段時間再讀一次) 1. 測試程式:類比腳位(A0-A5)預設即為輸入模式,因此不需要在 setup() 裡撰寫 pinMode。請在程式中加入以下邏輯: // 類比輸入基礎實測:讀取電位器數值
void setup() {
Serial.begin(9600); // 啟動序列埠通訊,速率設為 9600
}
void loop() {
int sensorValue = analogRead(A0); // 讀取 A0 腳位的電壓並轉為數字 (0-1023)
Serial.println(sensorValue); // 將數值印在序列埠監測器上
delay(100); // 延遲 100 毫秒,避免數值跳動過快
} 這段程式的核心邏輯是: 設一個變數來存讀到的數值(例如 sensorValue)。 在 loop() 裡重複做: 用 analogRead(A0) 讀一次 用 Serial.println() 把這個數值印出來 等個幾100毫秒再讀下一次,不用太快。 2. 啟動序列埠監測器(Serial Monitor) 上傳程式後,點擊 Arduino IDE 右上角的放大鏡圖示(或按下 Ctrl+Shift+M)。 3. 觀察數值變化 當你慢慢旋轉電位器,你會看到螢幕上的數字在 0 到 1023 之間平滑變動。這代表 Arduino 已經成功將旋鈕的「物理旋轉角度」轉化為精確的「數位數據」了。 正常情況你會看到:旋鈕轉到靠近 GND 那側 → 數值接近 0旋鈕轉到中間 → 數值大約落在 400~700 中間某一段(不需要剛好)旋鈕轉到靠近 5V 那側 → 數值接近 1023 如果你轉動旋鈕,數值都不變,或一直是 0/1023:先檢查電位器三腳有沒有接對(VCC、GND、A0)。再確認 A0 腳是不是程式裡也寫成 A0(不是寫成 D0)。最後再檢查是否有共地問題(GND 有沒有接回 Arduino)。 經過這一步,我們就完成了:從轉動電位器 → Arduino 類比腳位量到電壓 → 轉成 0~1023 的數字 → 顯示在序列埠監控視窗。 接下來要進入「類比輸出」與 analogWrite() 的部分。我們會解決一個看起來有點矛盾的問題:Arduino 的腳位明明只能輸出 0V 或 5V 這兩種狀態,為什麼卻能讓 LED 呈現「半亮」「微亮」這種中間程度?既然前面已經用類比輸入讀到了「強度數字」,Arduino 又是怎麼透過輸出端(PWM),把這個數字變成對應的亮度強弱? 下面這一段,我們就來看 Arduino 怎麼在「只能開/關」的腳位上,做出一格一格不同亮度的效果。 Arduino類比輸出教學實作:PWM 調光與 analogWrite() 應用 上一段我們讓 Arduino 用 analogRead(A0) 讀到電位器的「強度數字」。接下來,我們要處理「輸出端」:讓 Arduino 把這個強度,變成 LED 的不同亮度等級。當我們讀取到電位器的數值後,最常見的應用就是控制 LED 的亮度。但在動手之前,我們必須先理解一個硬體上的真相:Arduino 的數位腳位其實只能輸出 0V 或 5V,它是如何做出「漸強、漸弱」效果的呢?。 類比輸出的真相:Arduino 如何用「快閃」模擬強弱? 首先有一件很重要的事:Arduino 的腳位本質上還是只有兩種狀態:HIGH(給電)或 LOW(不給電)。
它其實沒有真的輸出 2.3V、3.7V 這種中間電壓。那為什麼 LED 看起來可以「微亮」「半亮」「最亮」?Arduino 達成類比輸出效果的技術稱為 PWM(脈波寬度調變)。它的運作邏輯不是改變電壓大小,而是改變「開啟時間的佔比」。 想像你以極快的速度切換開關,眼睛會因為視覺暫留將這串快閃訊號看成穩定的亮度:「全關」:持續輸出 0V,LED 熄滅。「關關開開」(50% 時間開):切換速度快到肉眼看不見閃爍,感覺就像是「半亮」。「關開開開」(75% 時間開):看起來就像是「高亮度」。這種透過調整輸出時間長短來模擬強弱的方式,其中「亮著的比例」,我們稱為 Duty Cycle(佔空比)。 所以也可以這樣理解:腳位其實還是只有「開/關」兩種狀態,但 Arduino 透過「開關的時間比例」來做出不同亮度等級,這就是我們在這裡說的「類比輸出效果」。 PWM 腳位辨識與 analogWrite() 語法 並非所有數位腳位都支援 PWM 功能。在 Arduino 開發板上,請認明腳位編號旁帶有 「~」 符號的腳位(如 D3, D5, D6, D9, D10, D11,實際以你手上的板子絲印標示為主)。這些腳位就可以用來作「亮度/強弱」控制(支援 analogWrite())。如果用沒有「 ~ 」的腳位,則多半只會看到「開/關」,看不到平滑調光。 而在程式撰寫上,我們使用 analogWrite() 指令,呈現如 analogWrite(pin, value) 假設我們要D9的LED輸出的數值範圍為 0 到 255: analogWrite(9, 127); // 讓接在 D9 的 LED 以約一半的亮度發光。 pin:你要控制哪一個 PWM 腳位(範例就是已經接上 LED 的 D9腳位)value:這次要多亮,用一個「亮度等級」的數字表示 用更多的範例來說:假設數值範圍同樣是 0~255,大致可以這樣想: analogWrite(9, 0);
→ 亮度等級 0:LED 不亮(占空比接近 0%) analogWrite(9, 128);
→ 亮度等級大約中間值:LED 半亮(占空比約一半) analogWrite(9, 255);
→ 亮度等級最高:LED 最亮(占空比接近 100%) 而其實也不需要去背每一個數字代表幾%,只要記得這個原則:數值越小 → 亮著的時間越少 → 看起來越暗數值越大 → 亮著的時間越多 → 看起來越亮 實作前的驗證檢查:用固定亮度測試 PWM 效果,確保 LED 具備「調光」能力 在我們把電位器的輸入接進來連動之前,必須先確認硬體環境是否正確。這是一個好習慣:先確保輸出端(LED)能正常顯示不同亮度,避免待會出問題時分不清楚是「旋鈕沒接好」還是「LED 沒接對」。 1. 硬體檢查 確認 LED 這條路有接對。可以用下面這條路徑來檢查: Arduino D9(PWM 腳位) → 電阻 → LED 正極(長腳) → LED 負極(短腳) → Arduino GND出發點↓Arduino D9當 analogWrite() 輸出時,這裡提供電壓經過↓電阻 (220Ω ~ 1kΩ) 負責「擋住一部分電流」,避免 LED 被燒掉作用↓LED 正極 → LED 負極LED 發光接回:閉合迴路⤴Arduino GND回到共地,形成一個完整回路 記得要注意以下三個地方:確認腳位: LED 的正極(長腳)必須接在帶有 「~」符號 的 PWM 腳位(本例使用 D9)。保護電路: 在 D9 和 LED 之間(或 LED 和 GND 之間)串上一顆 220Ω~1kΩ 的限流電阻,是為了避免 LED 被電流衝過頭燒掉。共地:LED 負極(短腳)最後一定要確實接回 GND,讓整條路徑形成一個完整回路。 只要這三件事都確認無誤,D9 腳位在執行 analogWrite() 時,電流正常運行,在實驗時就可以看到的亮度變化就是正常、可預期的。 2. 撰寫「亮度階梯」測試程式 在把電位器接進來之前,我們先進行一個「亮度階梯」的測試,透過程式直接指定 Arduino 輸出四種不同的亮度等級(0 → 80 → 160 → 255),確認 analogWrite() 真的能控制 LED 的亮暗程度。 測試目標: 依序輸出 0 → 80 → 160 → 255 四種等級,觀察 LED 的亮度變化。 程式邏輯與運作說明腳位初始化:在 setup() 裡將 D9 設為輸出模式把Arduino D9 設定成輸出腳位(LED 已依前面步驟接在 D9 → 電阻 → LED → GND 上)。 階梯式輸出:在 loop() 裡利用 analogWrite() 依序發送 0、80、160、255 四種不同強度的 PWM 訊號。 節奏控制:每切換一次亮度,在輸出後加入 delay(1000),讓 LED 的亮度切換停頓一秒,確保我們的肉眼能清晰分辨出每一階的亮度差異。 // 亮度階梯測試:驗證 PWM 輸出是否正常
void setup() {
pinMode(9, OUTPUT);
}
void loop() {
analogWrite(9, 0); // 完全熄滅
delay(1000);
analogWrite(9, 80); // 微亮
delay(1000);
analogWrite(9, 160); // 中亮
delay(1000);
analogWrite(9, 255); // 最亮
delay(1000);
} 透過這個「0 → 80 → 160 → 255」的亮度階梯,可以很直觀地看到:雖然腳位本質上仍然只有開和關兩種狀態,但因為 analogWrite() 改變了「一段時間內亮著的比例」,眼睛看到的效果就變成一格一格不同的亮度。確認這個實驗沒問題後,我們再把前面用 analogRead(A0) 讀到的電位器數值,接到 analogWrite() 裡,讓旋鈕來決定要選哪一階亮度。 3. 實驗結果觀察: 上傳程式後,觀察 LED 的變化,你應該會看到以下四段明顯的亮度階梯: analogWrite(9, 0):LED 完全熄滅(輸出 0V)。analogWrite(9, 80):LED 微微亮起,呈現弱光。analogWrite(9, 160):亮度明顯提升,大約是中等亮度。analogWrite(9, 255):LED 呈現最亮狀態(100% 全開)。 這驗證檢查確保了兩件關鍵的事:硬體接線無誤:你的 LED 迴路(D9 → 電阻 → LED → GND)已正確閉合。PWM 成功運作:證實了 analogWrite() 確實能透過控制「開啟時間的比例」,讓只能輸出 0V 或 5V 的數位腳位,模擬出「有層次」的類比效果。當你確認 LED 能夠隨心所欲地控制亮度後,代表輸出端已經準備就緒!接下來,我們就要進入最後的重頭戲:將電位器的「旋鈕位置」與 LED 的「亮度」串聯起來,實作手動調光燈。 不過,實作到這邊你應該會發現:我們在前面電位器讀到的數值範圍是 0 ~ 1023,但 LED 亮度的範圍卻只有 0 到 255。為了讓這兩個不同規格的數據能順利溝通,我們將會用到一個非常有用的數學小工具 —— map() 函數。它能像比例尺一樣,自動幫我們把旋鈕的位置精準對應到最合適的亮度! Arduino 專案實作:結合 map() 函數,打造電位器 LED 調光燈 前一個階段,我們已經確認了兩件事: analogRead() 讀得到電位器數值,而且會跟著旋鈕變化(0~1023 一路變動)analogWrite() 真的能讓 LED 出現「亮度階梯」(0 → 80 → 160 → 255 看得出差別) 接下來,我們就是將兩者串聯起來。接下來,我們要把電位器讀到的「訊號強弱」精準轉化為 LED 的「亮度等級」,讓原本枯燥的數字真正變成手動控制的視覺效果。透過這個實作,你將學會如何讓 Arduino 成為溝通物理旋轉與燈光變化的橋樑。 解決數值範圍的落差:為什麼讀取的 1023 不能直接用於亮度控制? 在實作讀取端與輸出端連動時,我們會遇到一個很常見的「範圍不一致」現象,以我們這次電位器與LED的例子來說: 讀取端 (analogRead):讀回來的數值範圍是 0 到 1023(共有 1024 階)。輸出端 (analogWrite):接收的數值範圍則是 0 到 255(共有 256 階)。 如果直接將讀取到的analogRead()的結果(例如 700、900、1023)套用到 analogWrite(),效果會變得很不直覺。因為輸出端的最大值只到 255,這會導致你旋鈕轉不到四分之一圈時,亮度就已經達到極限,剩下的轉動過程幾乎沒有任何變化。因此,我們需要幫這兩個不同的範圍進行「換算」,將電位器的 0~1023 平滑地轉化為 0~255。而這種數值間的比例換算,在程式開發中我們更專業地稱之為『映射 (Mapping)』,意指將輸入數值精確地對應到目標範圍的特定位置。 為什麼兩端數值不統一?解鎖 1023 與 255 背後的位元邏輯 既然知道了必須進行「映射」,你可能會進一步好奇:為什麼電位器的最大值是 1023,而 LED 輸出的最大值卻是 255?這不是隨機設定的,而是源自於硬體的「解析度」差異: 輸入端(電位器訊號與 10-bit ADC):Arduino 內部負責將電位器的類比電壓轉為數位的零件稱為「類比數位轉換器 (ADC)」,其解析度為 10-bit。它能將電壓切分成 $2^{10} = 1024$ 份,從 0 開始數,範圍就是 0 ~ 1023。輸出端(LED 亮度與 8-bit PWM):負責控制 LED 亮度的 analogWrite() 則是 8-bit 的模擬輸出,只能呈現 $2^8 = 256$ 種變化,從 0 開始數,範圍就是 0 ~ 255。 正因為這兩端對訊號的「切分精度」不同,我們需要透過程式進行數據對接。這種精度差異,可以用兩把長度相同,但刻度密度不同的尺來理解: 電位器的尺(10-bit)是一把刻度極細的「公釐尺」,共有 1024 個小刻度,能感知極微小的轉動;而 LED 的尺(8-bit)則是一把較粗的「公分尺」,只有 256 個階層。因為兩把尺的「格子總數」完全不同,我們不能直接套用刻度編號(否則旋鈕轉不到四分之一圈,LED 的尺就走到底了)。因此,必須透過 map() 函數來幫忙「對齊比例」,確保當電位器轉到尺的一半時,LED 也能精準對應到自己尺的一半。 數值轉換的橋樑:map() 函數運作邏輯 面對數值範圍不一致的問題,Arduino 內建的 map() 函數就是最佳的解決方案。它的作用就像一把「比例尺」,能將一個數值範圍等比例地縮放到另一個範圍。 1. map() 的核心概念 簡單來說,map() 會幫你進行數學換算:如果輸入範圍的最大值 1023 對應到輸出的 255,那麼當前讀到的 512(範圍的中間點),應該對應到多少亮度?透過精密的計算,它會給出 127 這個精準的答案。而推薦使用 map() 是因為 map() 的語法邏輯非常清晰且通用性極強:未來如果你換成讀值範圍不同的感測器(例如光敏電阻),你只需要修改函數中的參數,就能立刻完成對應。 2. 語法結構拆解 為了存放轉換後的結果,我們需要建立一個新的變數(例如命名為 brightness),並將 map() 計算後的數值存入其中: int brightness = map(val, 0, 1023, 0, 255) 這行指令可以直覺地理解為:「看看旋鈕讀值 val 在 0~1023 的哪個位置,就把它同步映射到 0~255 的同一個相對位置,並把結果記在 brightness 裡」也就是「旋鈕從最小轉到最大,亮度就會從最暗一路對應到最亮,而且比例是線性的」 int brightness宣告一個整數變數,用來儲存映射後、準備給 LED 使用的「亮度等級」。val你目前讀到的原始數值(即從旋鈕 analogRead 得到的數字)。0, 1023定義「原本的輸入範圍」(從最小到最大)0, 255定義「目標的輸出範圍」(你希望轉換後的亮度等級)。 小補充:快速除法(直覺版) 其實也可以用另一種方式理解:因為1023 大約是 255 的 4 倍,所以可以用「除以 4」快速縮小範圍。也就是:讀到 0~1023 → 變成 0~255,就是將數值直接 除以 4。雖然這也能達成目標,但在撰寫程式時,使用 map() 函數是更標準且通用的做法。 完整範例程式碼:手動調光燈專案 最後,我們將所有邏輯結合在一起。請先確保硬體的電位器接在 A0,LED 接在 D9(帶有 ~ 符號的腳位)。 // 最終實作:手動調光燈 (結合類比輸入與 PWM 輸出)
const int potPin = A0; // 電位器接 A0
const int ledPin = 9; // LED 接 D9 (支援 PWM)
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
// 1. 讀取旋鈕值 (0~1023)
int val = analogRead(potPin);
// 2. 使用 map 函數進行範圍映射 (從 0~1023 轉為 0~255)
int brightness = map(val, 0, 1023, 0, 255);
// 3. 輸出 PWM 訊號控制亮度
analogWrite(ledPin, brightness);
// 同步在螢幕印出數值,方便觀察轉換邏輯
Serial.print("旋鈕值: "); Serial.print(val);
Serial.print(" -> 轉換亮度: "); Serial.println(brightness);
delay(50);
} 最終實驗觀察 上傳成功後,當你慢慢旋轉電位器,LED 將會呈現極為平滑的亮度變化。打開「序列埠監測器」,你會看到左邊的輸入數值(0~1023)與右邊轉換後的亮度等級(0~255)呈現完美的比例跳動。恭喜你已經掌握了 Arduino 類比控制中最核心的「類比輸入 > 換算 > 類比輸出」邏輯,這也是未來製作自動調光燈、溫控風扇等進階專案的基礎。 疑難排解:讀值跳動、LED 閃爍、接線未共地的常見錯誤 如果遇到「電位器調光」運作不如預期,別擔心,這通常是電路或程式中的小細節出了問題。下面這幾個狀況,是最常見的卡關點。你可以對照遇到的狀況來檢查排查錯誤。 狀況 1:旋鈕怎麼轉,數值都不變(固定在 0 或 1023) 腳位檢查:檢查電位器三腳有沒有接對,電位器中間的腳才是 Signal(訊號線),必須接在 A0。而兩側分別接 5V 和 GND。定義確認:檢查程式碼中的 analogRead(A0) 是否與實體接線一致,很多新手會把 A0 寫成 0 或 D0,讀到的就不是電位器。接觸不良:檢查電位器是不是插歪或接觸不良:麵包板沒插到底,會造成看起來「一直不動」。 狀況 2:讀值變動劇烈、不穩定(LED 亮度一直在抖動)最重要的「共地」:確認電位器的 GND 與 LED 的 GND 都有連回到 Arduino 的 GND 腳位。雜訊干擾:如果環境中電子設備過多,數值會輕微跳動。可以試將程式中 delay(20) 加大到 delay(50),讓數據輸出平滑一點,因為程式更新太快會看起來在抖動。麵包板軌道:部分大型麵包板中間的紅藍電源線是「斷開」的,請確認你的接線在同一區塊內,或有用跳線連接。 狀況 3:LED 只會亮或不亮,看不到漸亮漸暗PWM 腳位限制:LED 沒接在 PWM 腳位是最常見的錯誤!請確認 LED 的正極(長腳)接在有 「~」 符號的腳位(如 D3, D5, D6, D9, D10, D11)。注意:若你用的是不同板型或相容板:PWM 腳位標示可能不同,請以板子上的 ~ 為準。函式誤用:確認程式碼是用 analogWrite() 而不是 digitalWrite()、檢查 analogWrite() 的 pin 是否跟你接線一致:你接 D9,但程式寫 D6,就無法順利運行。 狀況 4:LED 完全不亮或亮度極微弱LED方向檢查:LED 是有極性的,長腳接到電阻那側(靠 PWM 腳位),短腳接回 GND。電阻值過大:如果用了過大的電阻(例如 10kΩ),電流會太小導致 LED 看不見亮光。建議使用 220Ω 到 1kΩ 之間的電阻。沒電阻可能燒 LED;電阻太大則會很暗。電壓不足:檢查 5V / 3.3V 供電是否一致,如果板子是 3.3V 系統,亮度與讀值會跟 5V 系統有差異,電壓不足但應該還是能正常變化,但LED 的亮度動態範圍會變窄。 到這邊我們已經完成了這個專案!雖然我們今天的目標是「電位器調光」,但這篇內容的真正的核心價值,在於你已經掌握了一套足以應付 80% Arduino 專案的通用控制流程:類比輸入(Input):從現實世界讀取一個代表「程度」的數字(如旋鈕位置、光線強弱、溫度高低)。數值轉換(Processing):利用 map() 函數,將讀到的數字精準翻譯成你需要的控制刻度。類比輸出(Output):利用 PWM 技術 與 analogWrite(),將結果轉化為實體的動作(如亮度、轉速或聲音)。只要掌握了這套「讀取、轉換、輸出」的邏輯,你就能隨意更換手邊的零件,變換出無數種組合。例如:將電位器換成光敏電阻,調光燈就變成了「自動感應小夜燈」! Arduino PWM 進階觀念與延伸應用 掌握了這套通用的控制流程後,我們可以進一步思考:除了控制 LED 亮度,PWM 還能應用在哪些地方?在 Arduino 的世界裡,只要涉及控制強弱、速度或頻率,幾乎都是 PWM 的守備範圍。不過,不同硬體裝置對訊號的「運作特性」與「訊號規範」其實都不太一樣,這也決定了我們在程式中會選用最合適的指令,例如: LED 看重「脈寬比例」:只需要知道一段時間內「開」與「關」的佔比(Duty Cycle),佔比越高燈就越亮。馬達看重「時序精確度」:需要極其精確的脈衝寬度(脈衝持續時間的長短)來決定轉動的精準位置。聲音看重「震盪頻率」:需要透過改變開關切換的「速度」(Frequency)來產生高低不同的音高。 為了讓開發流程更方便,Arduino 已經預先將這些複雜的物理計算封裝成了更直觀的專用函數。這就是為什麼在控制馬達或聲音時,我們會針對其控制邏輯切換指令,而不再僅僅使用 analogWrite()。 1. 直流馬達(DC Motor):控制轉速快慢 直流馬達與 LED 的原理相同,是利用 PWM 改變輸出的平均電壓來決定旋轉快慢。指令特色:使用 analogWrite(0-255)。 因為 LED 是控制「亮度的強弱」,而馬達則是控制「轉速的快慢」,兩者邏輯完全一致。應用場景:遙控車加減速、小風扇的風量調節。映射邏輯:因為旋鈕讀值是 0~1023,而馬達速度範圍是 0~255。所以映射公式為:map(val, 0, 1023, 0, 255)。 2. 伺服馬達(Servo Motor)的角度控制 伺服馬達屬於位置控制。它會解讀脈衝的持續時間,並轉向特定角度後停住。指令特色:analogWrite 給的是比例(0-255),但伺服馬達需要的是角度。為了方便操作,Arduino 準備了 write(角度) 指令,讓你直接指定 0 到 180 度。應用場景:機器手臂的關節、自動門的開關(轉 90 度開門,轉 0 度關門)、攝影機的旋轉底座。映射邏輯:因為旋鈕讀值是 0~1023,而馬達的旋轉範圍是 0~180 度。所以映射公式為:map(val, 0, 1023, 0, 180)。 3. 無源蜂鳴器(Passive Buzzer)的音高控制 蜂鳴器發聲是靠快速開關產生的震動。震動得越快,聲音就越高。指令特色:analogWrite 的震動速度(頻率)是固定的,聽起來音高不會改變。為了能彈奏音階,Arduino 準備了 tone(頻率) 指令,讓你直接指定每秒要震動幾次(Hz)。應用場景:警報器音效(由低音變高音)、電子琴、按鈕按下的提示音。映射邏輯:因為旋鈕讀值是 0~1023,而我們要控制的音階範圍(例如中央 C 到高音 C)是 262~523。所以映射公式為:map(val, 0, 1023, 262, 523)。 重點小結:三種輸出的換算對照表 無論硬體怎麼換,你只需要決定旋鈕轉到底時,你想要的是「最亮」、「最快」、「轉到幾度」還是「什麼音高」:裝置類型關鍵指令實體反應map() 映射目標LED 燈 / 直流馬達analogWrite()亮度 / 速度0, 255伺服馬達myServo.write()旋轉角度0, 180無源蜂鳴器tone()音高頻率262, 523 小結與下一步:開啟你的自動化控制之路 到這裡,你已經跨越了 Arduino 開發中最重要的一道門檻:從數位訊號(只有 0 與 1)進化到了類比訊號(連續變化的世界)。這篇教學的核心價值,不在於你做出了一個調光燈,而是你掌握能夠應對大多數專案的「通用控制邏輯」: 輸入 (Input):利用電位器(或感測器)擷取現實世界的連續變化。處理 (Processing):利用 map() 函數將讀值「映射」到你需要的範圍。輸出 (Output):利用 PWM 技術,精確控制亮度、轉速、角度或音頻。 只要邏輯不變,你就能隨意更換零件。例如把電位器換成光敏電阻,這座調光燈就變成了「自動感應小夜燈」;把 LED 換成馬達,就變成了「手動調速風扇」。 下一步練習建議:用 analogRead / map / analogWrite 做更多控制效果 在進入下一章之前,你可以嘗試以下練習來加深這次學到的觀念: 讓反應更平滑:嘗試調整程式中的 delay() 數值。觀察看看當延遲時間變長或變短時,LED 的亮度變化與 Serial Monitor 的數據刷新速度有什麼不同?改變映射範圍:試著修改 map() 函數的最後兩個參數(例如改為 0, 50)。觀察看看為什麼旋鈕轉到底後,LED 卻變得很暗?這能幫助你更直覺地理解「映射」的意義。資訊可視化 (進階預告):在後續我們學到 Serial Monitor 與 LCD 顯示器 後,你可以練習將電位器的數值直接顯示在螢幕上,達成真正的「資訊可視化」。情境規則練習 (進階預告):等我們學完下一章的 if 判斷式,你可以挑戰:「只有當旋鈕轉超過一半時,LED 才開始發光」這種帶有邏輯規則的控制。 下一章節預告:使用 if 條件判斷與 millis 函式賦予專案「思考能力」與「時間觀念」 雖然我們現在能透過旋鈕調整亮度,但目前的程式只是單純地「讀取並執行」。如果我們希望專案更聰明一點,例如在光線低於某個數值時才自動啟動,這就需要透過 if/else 「邏輯判斷」 來下達指令;又或者,如果你想讓多個零件同時運作而不互相干擾,該怎麼辦呢?在下一篇教學中,我們將深入探討 Arduino 的控制結構 與 時間處理。我們將回顧並結合今天學到的類比技術,教你如何運用 if/else 與 millis(),賦予專案「自主邏輯」與「多工處理」的能力!