第 12 章 Arduino 入門
本章目標
- 學完你會指出 Arduino UNO 板子上每個重要部位:數位腳位、類比腳位、電源腳位、USB 孔、重置鈕。
- 學完你會自己安裝 Arduino IDE 2.x,選對開發板與連接埠,把程式上傳到板子。
- 學完你會說出
setup()與loop()的差別,並會用pinMode、digitalWrite、digitalRead、delay四個基本指令。 - 學完你會用序列埠監控視窗把板子裡的資料印到電腦上。
- 學完你會用示波器量 Blink 程式的波形,確認
delay(500)真的等了半秒。
開場:那塊藍色的板子到底是什麼?
前面幾章,我們一直把 Arduino 當成一台「方波產生器」:要方波就叫它吐方波,要 2.5V 就叫它輸出 PWM,要音階就叫它 tone()。你可能照著打了程式、按了上傳、看到結果,但心裡一直有個問號:這塊藍色板子到底是什麼?裡面在幹嘛?
想一想家裡的電鍋。你按一下「煮飯」,它自己會加熱、偵測溫度、時間到就跳起來保溫。沒有人在裡面看著,是誰在做決定?答案是一顆小小的晶片,叫微控制器(Microcontroller)。電鍋、微波爐、遙控器、電子錶、腳踏車碼表,裡面都有一顆。它就像一個很小、很專心的大腦,只會做你教它的事,但一秒可以做幾百萬次,而且從不喊累。
Arduino UNO 就是一塊讓你「方便使用微控制器」的板子。這一章我們不急著做花俏的東西,先把板子看清楚、把工具裝好、把最基本的四個指令練熟,然後用示波器去驗證:程式說等 500 毫秒,它真的等了 500 毫秒嗎?
核心概念
Arduino UNO 板子構造:大腦、手腳和電源
把板子拿起來,USB 孔朝左,你會看到這樣的配置:
┌──────────────────────────────────────────────┐
USB 孔 ──┤ [USB] 數位腳位 D13 ... D0 │
│ [重置鈕] ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
│ 13 12 ~11 ~10 ~9 8 7 ~6 ~5 4 ~3 2 1 0
│ ┌─────────┐ │
│ │ATmega328P│ ← 大腦(微控制器) │
│ └─────────┘ │
│ 電源腳位 類比腳位 │
DC 電源 ──┤ [JACK] ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ │
│ 3V3 5V GND GND Vin A0 A1 A2 A3 A4 A5 │
└──────────────────────────────────────────────┘
- 大腦:ATmega328P:板子中央那顆長長的黑色晶片,就是微控制器。你的程式住在它裡面,拔掉電源也不會消失,下次插電就繼續跑。
- 數位腳位 D0–D13:上排 14 個洞。每個都可以當輸出(給 0V 或 5V)或輸入(讀 LOW 或 HIGH)。編號前面有
~的(3、5、6、9、10、11)支援 PWM,所以本書的 LED 一律接 D9。D0 和 D1 是序列埠用的(RX、TX),平常不要接東西在上面,否則上傳程式會失敗。 - 類比腳位 A0–A5:下排 6 個洞,可以讀 0–5V 之間任何電壓(第 13 章)。
- 電源腳位:
5V可以供電給外部零件,3V3是 3.3V,GND有三個(都一樣,隨便用),Vin是外部電源的入口。 - USB 孔:上傳程式、和電腦講話、同時供 5V 電。
- DC 電源孔:可以插 7–12V 的電源,本書用 9V 電池加電池扣接在這裡就能脫離電腦運作。不要超過 12V。
- 重置鈕(Reset):按一下,程式從頭開始跑,不會刪掉程式。
- 板子上的小 LED:
L燈接在 D13 上,可以不用接線就測試;TX/RX燈在傳資料時會閃;ON燈亮表示有電。
電流的限制要記住:每個腳位最多安全輸出約 20 mA(極限 40 mA,但不要挑戰它)。LED 經過 220 Ω 大約流 (5 − 2) ÷ 220 ≈ 14 mA,剛好。馬達、蜂鳴器以外的大電流負載,要像第 9 章那樣用電晶體幫忙。USB 給整塊板子的電大約 500 mA。
安裝 Arduino IDE 2.x:教大腦說話的工具
程式要先在電腦上寫好,再「上傳」到板子裡。寫程式的軟體叫 Arduino IDE(Integrated Development Environment,整合開發環境),本書用 2.x 版本。
安裝步驟
- 到 Arduino 官方網站(arduino.cc,找 Software 頁面)下載 Arduino IDE 2。Windows 選
.exe或.msi,macOS 選.dmg。 - 安裝時 Windows 可能跳出「要不要安裝驅動程式」,請選「安裝」。macOS 把圖示拖到應用程式資料夾即可。
- 第一次打開會是英文介面。想改中文:File → Preferences → Language 選「繁體中文」,重新啟動。本書下面都用中文選單名稱。
- 用 USB 線把 UNO 接到電腦,板子上的 ON 燈會亮。
- 選開發板:功能表「工具 → 開發板 → Arduino AVR Boards → Arduino UNO」。IDE 2 也可以直接點視窗上方中間那個下拉選單,選有「Arduino UNO」字樣的那個。
- 選連接埠:「工具 → 連接埠」。Windows 會看到
COM3、COM5之類(數字因電腦而異);macOS 會看到/dev/cu.usbmodem14101之類。選那個後面寫著「(Arduino UNO)」的。如果不確定,拔掉板子看哪個選項消失,那個就是。 - 視窗左上角兩個按鈕:**✓(驗證)只檢查程式有沒有寫錯,→(上傳)**檢查後把程式送進板子。上傳時 TX/RX 燈會快速閃,下方出現「上傳完成」就成功了。
安裝好後,最快的測試是「檔案 → 範例 → 01.Basics → Blink」,直接上傳,板子上的 L 燈會開始每秒閃一次。
程式長什麼樣:setup 一次,loop 一直
Arduino 的程式(檔案叫 sketch,草稿碼)一定有兩個部分:
void setup() {
// 這裡只會跑一次:開機(或按重置)的時候
}
void loop() {
// 這裡會一直重複跑,跑完最後一行就回到第一行,永遠不停
}
打個比方:setup() 像開學典禮,只辦一次,用來宣布規定、分配位子;loop() 像每天的上課,從早上到放學一直重複。所有「設定腳位是輸入還是輸出」的事放 setup,「讀按鈕、亮燈」這種要一直做的事放 loop。
四個基本指令:
| 指令 | 意思 | 例子 |
|---|---|---|
pinMode(腳位, 模式) | 告訴板子這隻腳要當輸出還是輸入 | pinMode(9, OUTPUT)、pinMode(2, INPUT_PULLUP) |
digitalWrite(腳位, 值) | 讓輸出腳位變 5V 或 0V | digitalWrite(9, HIGH) |
digitalRead(腳位) | 讀輸入腳位,得到 HIGH 或 LOW | int s = digitalRead(2); |
delay(毫秒) | 什麼都不做,等這麼多毫秒 | delay(500) 等半秒 |
幾個會害你卡很久的小規則:
- 每句指令結尾要有分號
;。 - 大小寫有差:
digitalWrite可以,DigitalWrite不行。 {和}要成對。//後面是註解,給人看的,板子會忽略。多寫註解是好習慣。
**變數(Variable)**是給數字取名字的盒子。int ledPin = 9; 做了一個叫 ledPin 的盒子,裡面放 9。之後程式寫 ledPin 就等於寫 9,要改腳位只要改一個地方。const int 表示這個值固定不會變。
if 是做判斷:
if (digitalRead(2) == LOW) { // 如果按鈕被按下(上拉:按下是 LOW)
digitalWrite(9, HIGH); // 就亮燈
} else { // 否則
digitalWrite(9, LOW); // 就關燈
}
注意比較是兩個等號 ==,一個等號 = 是「放進盒子」,寫錯不會報錯但結果會怪怪的。
序列埠:讓板子跟你說話
板子沒有螢幕,怎麼知道它在想什麼?用序列埠(Serial Port),透過那條 USB 線把文字送到電腦。
Serial.begin(9600);放在 setup,意思是「打開序列埠,速度 9600」。Serial.println("你好");印一行字並換行;Serial.print(x);印完不換行。- 看結果:點 IDE 右上角的放大鏡(序列埠監控視窗),右下角速度要選 9600 baud,和程式一樣,否則會看到亂碼。
9600 是鮑率(Baud Rate),意思是每秒傳 9600 個位元。傳一個字元大約要 10 個位元(第 15 章會講為什麼),所以 9600 ÷ 10 = 每秒約 960 個字元。印一行 20 個字的訊息要 20 ÷ 960 ≈ 0.02 秒,很快,但如果你在 loop 裡每一圈都印,一秒印幾千行,就會塞車。所以範例裡印完都會 delay 一下。
動手做
實驗 12-1:Blink,第一支程式
材料
- Arduino UNO 與 USB 線、麵包板、杜邦線
- 紅色 LED ×1
- 220 Ω 電阻 ×1
接線
Arduino D9 ──[ 220Ω ]──►|── Arduino GND
LED
- Arduino D9 → 220 Ω 電阻 → LED 長腳(+)。
- LED 短腳(−)→ Arduino GND。
程式
// 實驗 12-1:Blink,讓 LED 一秒閃一次
const int ledPin = 9; // LED 接在 D9
void setup() {
pinMode(ledPin, OUTPUT); // D9 當輸出
}
void loop() {
digitalWrite(ledPin, HIGH); // 給 5V,LED 亮
delay(500); // 等 500 毫秒
digitalWrite(ledPin, LOW); // 給 0V,LED 暗
delay(500); // 再等 500 毫秒,然後回到 loop 開頭
}
步驟
- 接好線,確認 LED 長短腳沒接反。
- 打開 IDE,把程式打進去(或複製貼上),確認開發板與連接埠選對。
- 按 ✓ 驗證,下方沒有紅字就按 → 上傳。
- LED 應該開始閃。順便看板子上的 L 燈:它沒閃,因為我們用的是 D9,不是 D13。
- 把兩個
delay(500)都改成delay(100),上傳,看閃的速度。 - 改成
delay(1000),再上傳。 - 把第一個
delay改成 100、第二個改成 900(亮短暗長),觀察差別。
你應該看到
delay(500):亮半秒、暗半秒,一秒閃一次。delay(100):閃得很快,一秒五次。delay(1000):亮一秒、暗一秒。- 100/900:短促的一閃,像警示燈。
觀察與記錄
| 亮的 delay(ms) | 暗的 delay(ms) | 一個週期幾秒 | 一秒閃幾次 | 看起來像什麼 |
|---|---|---|---|---|
| 500 | 500 | |||
| 100 | 100 | |||
| 1000 | 1000 | |||
| 100 | 900 |
實驗 12-2:按鈕控制 LED
材料
- 實驗 12-1 的全部材料
- 按鈕開關 ×1
接線
Arduino D9 ──[ 220Ω ]──►|── GND
LED
Arduino D2 ──── 按鈕 ──── GND (程式打開內建上拉)
- LED 同實驗 12-1。
- 按鈕一腳 → Arduino D2,另一腳 → GND。不用外接電阻,程式用
INPUT_PULLUP。
程式
// 實驗 12-2:按住按鈕 LED 才亮
const int ledPin = 9; // LED 接 D9
const int buttonPin = 2; // 按鈕接 D2
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // 內建上拉:沒按 HIGH,按下 LOW
}
void loop() {
int buttonState = digitalRead(buttonPin); // 讀按鈕,存進盒子
if (buttonState == LOW) { // 被按下
digitalWrite(ledPin, HIGH); // 亮
} else { // 沒按
digitalWrite(ledPin, LOW); // 暗
}
}
步驟
- 接線、上傳。
- 按住按鈕,LED 亮;放開,LED 暗。
- 挑戰:把
HIGH和LOW對調,變成「按下才暗」。 - 再挑戰:改成「按一下亮、再按一下暗」(提示:需要一個記住目前狀態的變數,還有第 11 章的去彈跳)。
你應該看到
- 按住亮、放開暗,反應幾乎是瞬間的。
觀察與記錄
| 動作 | digitalRead(2) 讀到 | LED 狀態 |
|---|---|---|
| 沒按 | ||
| 按住 | ||
| HIGH/LOW 對調後,沒按 | ||
| HIGH/LOW 對調後,按住 |
實驗 12-3:把按鈕狀態印到電腦上
材料
- 與實驗 12-2 相同。
接線
- 與實驗 12-2 相同。
程式
// 實驗 12-3:序列埠印出按鈕狀態
const int ledPin = 9;
const int buttonPin = 2;
void setup() {
Serial.begin(9600); // 打開序列埠,速度 9600
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
Serial.println("開始!按按鈕看看。");
}
void loop() {
int buttonState = digitalRead(buttonPin);
digitalWrite(ledPin, buttonState == LOW ? HIGH : LOW); // 按下就亮
Serial.print("經過 ");
Serial.print(millis() / 1000); // millis() 是開機到現在的毫秒數
Serial.print(" 秒,D2 讀到 ");
Serial.print(buttonState); // 印 0 或 1
if (buttonState == LOW) {
Serial.println(" → 按下");
} else {
Serial.println(" → 放開");
}
delay(200); // 一秒印 5 行,不要塞車
}
步驟
- 上傳後打開序列埠監控視窗(右上角放大鏡),右下角速度選 9600。
- 看訊息一行一行出來。按住按鈕幾秒,看數字從 1 變 0,再放開。
- 把
delay(200)改成delay(10),看視窗會變成怎樣。 - 把速度改成 115200(程式和監控視窗都要改),看有什麼不同。
你應該看到
- 沒按:
D2 讀到 1 → 放開;按住:D2 讀到 0 → 按下。 delay(10)時訊息多到看不清,像瀑布一樣。- 監控視窗速度選錯時會看到一堆亂碼或方塊。
觀察與記錄
| 情況 | 監控視窗看到什麼 | 每秒大約幾行 |
|---|---|---|
| delay(200),沒按 | ||
| delay(200),按住 | ||
| delay(10) | ||
| 監控視窗故意選 115200(程式仍是 9600) |
用儀器看看
示波器:delay(500) 真的等了 500 毫秒嗎?
這是本章最重要的驗證:程式寫的時間,和真實世界的時間,對不對得起來?
- 接法:用實驗 12-1 的電路,CH1 探棒尖端 → D9(夾在電阻靠 D9 那一端),接地夾 → Arduino GND。
- CH1:2 V/div,DC 耦合,探棒 10×(通道設定也選 10×)。
- 時間:200 ms/div。
- 觸發:CH1 上升邊緣,準位 2.5V,模式 Auto。
上傳 delay(500) 的 Blink,畫面像這樣:
5V ┤ ┌─────────┐ ┌─────────┐
│ │ │ │ │
0V ┼──────┘ └─────────┘ └────── 時間
◄─────────────────►
一個週期 = 1 秒(5 格 × 200 ms)
亮 500 ms、暗 500 ms,一個週期 1 秒,頻率 1 Hz。用游標量兩個上升邊緣的距離,應該非常接近 1.000 秒。
接著把兩個 delay 都改成 delay(1),重新上傳。這時 LED 看起來像一直亮著(其實在高速閃),示波器時間改成 500 µs/div:
5V ┤ ┌───┐ ┌───┐ ┌───┐ ┌───┐
│ │ │ │ │ │ │ │ │
0V ┼──┘ └───┘ └───┘ └───┘ └──
◄───────►
約 2 ms → 約 500 Hz
一個週期大約 2 ms,頻率大約 500 Hz。用示波器的自動量測看「頻率」,你可能會量到 498 或 499 Hz 而不是剛好 500,因為 digitalWrite 本身也要花幾微秒,loop 繞一圈不只 2 ms。這就是真實世界:程式說 1 ms,實際上是「1 ms 加一點點」。
把量到的數字填進表,順便算算看每個 delay 對應的週期和頻率:
| delay(ms) | 算出來的週期 | 算出來的頻率 | 示波器 s/div | 示波器量到的週期 | 量到的頻率 |
|---|---|---|---|---|---|
| 500 | 1000 ms = 1 s | 1 Hz | 200 ms | ||
| 100 | 200 ms | 5 Hz | 50 ms | ||
| 10 | 20 ms | 50 Hz | 5 ms | ||
| 1 | 2 ms | 500 Hz | 500 µs |
三用電表:慢眼睛看快訊號
把三用電表切到直流電壓檔,量 D9 對 GND。delay(500) 時數字會在 0 和 5 之間慢慢跳,跟 LED 同步;delay(1) 時數字會停在約 2.5V,因為電表反應慢,把方波平均掉了,這就是第 10 章講的「電表自己在濾波」。要看清楚快訊號,一定得用示波器。
邏輯分析儀:也可以量時間
把邏輯分析儀 CH0 接 D9、GND 接 GND,取樣率 1 MHz,按 Run 抓 3 秒。在 PulseView 裡點兩個邊緣,軟體會直接顯示間隔時間,delay(500) 會看到 500.0 ms 左右,delay(1) 會看到 1.00 ms 多一點。邏輯分析儀抓長時間的方波特別方便。
常見錯誤與除錯
- 上傳失敗,訊息有「port」或「avrdude」字樣 → 連接埠沒選對,或 USB 線只有充電功能沒資料線 → 重選連接埠(拔掉再插看哪個出現),換一條 USB 線。
- 上傳失敗,而且 D0/D1 有接東西 → 序列埠被占用 → 拔掉 D0、D1 上的線再上傳。
- 驗證就出現紅字 → 程式打錯:少分號、少括號、大小寫錯 → 看紅字指的行數,通常錯在那一行或上一行。
- LED 完全不亮 → LED 接反、電阻沒接到、接到的不是 D9 → 把 LED 轉 180 度;用三用電表量 D9 對 GND 有沒有在 0 和 5V 之間變化。
- LED 一直亮不閃 → delay 太短(例如 1 ms)眼睛看不出來 → 用示波器看,或把 delay 改大。
- 序列埠視窗是亂碼 → 鮑率不一致 → 程式
Serial.begin(9600)和監控視窗都選 9600。 - 序列埠視窗什麼都沒有 → 沒按右上角放大鏡,或上傳時視窗被關掉 → 重新打開監控視窗,按一下板子的重置鈕。
- 按鈕沒反應 → 按鈕插的方向錯或忘了
INPUT_PULLUP→ 回第 11 章檢查。 - 示波器看到方波但只有 0.5V 高 → 探棒 10× 但示波器通道設 1× → 兩邊設一致。
想一想
setup()和loop()各跑幾次?如果把pinMode寫在loop()裡會怎樣?
參考答案
setup() 開機後跑一次,loop() 一直重複。pinMode 放 loop 裡功能上還是能動,但每一圈都重新設定一次,浪費時間,也容易讓人看不懂,應該放 setup。
- 要讓 LED 每秒閃 10 次,亮暗時間一樣長,兩個
delay要填多少?
參考答案
每秒 10 次 → 週期 100 ms → 亮 50 ms、暗 50 ms,兩個都填 delay(50)。
- 程式寫
delay(1)亮、delay(1)暗,示波器為什麼量到 498 Hz 而不是剛好 500 Hz?
參考答案
因為 digitalWrite 和 loop 本身也要花幾微秒,實際週期比 2 ms 多一點點,例如 2.008 ms → 1 ÷ 0.002008 ≈ 498 Hz。delay 越短,這個誤差占的比例越大;delay(500) 時幾乎看不出來。
- 序列埠用 9600 鮑率,一行訊息 30 個字元,傳完大約要多久?如果 loop 裡沒有 delay,一秒最多能印幾行?
參考答案
一個字元約 10 位元,30 字元 = 300 位元,300 ÷ 9600 ≈ 0.031 秒 = 31 ms。一秒最多約 1000 ÷ 31 ≈ 32 行。超過這個速度,程式會被序列埠拖慢。
- 有一位同學的 Blink 上傳成功,但 LED 不亮。他用三用電表量 D9 對 GND,讀到 0V 和 5V 慢慢交替。問題在哪裡?
參考答案
板子和程式都正常,是 LED 那邊的問題:LED 接反(長短腳顛倒)、電阻沒插到同一排、或 LED 壞了。把 LED 轉 180 度最常解決。
- 開放挑戰:只用一個按鈕和一顆 LED,做一個「調速閃燈」:每按一次按鈕,閃的速度就換一檔(1 Hz → 5 Hz → 10 Hz → 回到 1 Hz)。提示:一個記錄檔位的變數、第 11 章的去彈跳、
delay的值跟著檔位變。做完用示波器驗證三檔的頻率。
參考答案
用一個陣列存三檔的半週期 int halfPeriods[3] = {500, 100, 50}; 和一個變數 int level = 0;。偵測到按鈕「從放開變按下」(去彈跳)時 level = (level + 1) % 3。loop 裡用 delay(halfPeriods[level]) 閃燈。難點是:delay 期間按鈕沒人讀,按太短會漏掉,可以把長 delay 拆成很多個 delay(10) 中間檢查按鈕,或改用 millis() 計時(第 14 章會更深入)。示波器應量到約 1 Hz、5 Hz、10 Hz。
本章小結
- Arduino UNO 的大腦是 ATmega328P 微控制器;D0–D13 是數位腳位(
~的支援 PWM),A0–A5 是類比腳位,5V/3V3/GND/Vin 是電源腳位。D0、D1 留給序列埠,不要接東西。 - 每個腳位安全電流約 20 mA;LED 配 220 Ω 約 14 mA,剛好。
- 安裝 Arduino IDE 2.x 後,「工具 → 開發板 → Arduino UNO」、「工具 → 連接埠 → 有 (Arduino UNO) 的那個」,✓ 驗證、→ 上傳。
setup()跑一次(設定),loop()一直重複(工作)。- 四個基本指令:
pinMode、digitalWrite、digitalRead、delay。比較用==,分號和大小寫不能錯。 Serial.begin(9600)加Serial.println()可以把資料印到電腦;監控視窗的鮑率要跟程式一致。9600 鮑率約每秒 960 個字元。delay(500)的 Blink 在示波器上是週期 1 秒、1 Hz 的方波;delay(1)大約 500 Hz,會略低一點,因為程式本身也要花時間。- 三用電表量快方波只會得到平均值,看波形要用示波器或邏輯分析儀。
名詞表
| 中文 | 英文 | 一句話解釋 |
|---|---|---|
| 微控制器 | Microcontroller | 一顆小晶片,裡面有大腦、記憶體和腳位,專門做你教它的事。 |
| 草稿碼 | Sketch | Arduino 程式檔案的名字。 |
| 整合開發環境 | IDE, Integrated Development Environment | 寫程式、檢查、上傳的軟體,本書用 Arduino IDE 2.x。 |
| 開發板 | Board | 像 Arduino UNO 這種把微控制器裝好、方便接線的板子。 |
| 連接埠 | Port | 電腦認得板子的那個通道,Windows 叫 COM 幾,macOS 叫 /dev/cu.usbmodem…。 |
| 上傳 | Upload | 把寫好的程式送進板子裡。 |
| 驗證 | Verify | 只檢查程式有沒有寫錯,不上傳。 |
| 重置 | Reset | 讓程式從頭開始跑,不會刪掉程式。 |
| 設定函式 | setup() | 開機後只跑一次的程式區塊。 |
| 迴圈函式 | loop() | 一直重複跑的程式區塊。 |
| 腳位模式 | pinMode | 設定腳位當輸出或輸入的指令。 |
| 變數 | Variable | 給一個數值取名字的盒子,例如 int ledPin = 9;。 |
| 常數 | const | 宣告這個變數的值不會改變。 |
| 條件判斷 | if / else | 滿足條件做一件事,否則做另一件事。 |
| 序列埠 | Serial Port | 板子和電腦透過 USB 傳文字的通道。 |
| 鮑率 | Baud Rate | 序列埠每秒傳的位元數,本書用 9600。 |
| 序列埠監控視窗 | Serial Monitor | IDE 裡顯示板子送來的文字的視窗。 |
| 毫秒計時 | millis() | 回傳開機到現在經過的毫秒數。 |