Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 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 版本。

安裝步驟

  1. 到 Arduino 官方網站(arduino.cc,找 Software 頁面)下載 Arduino IDE 2。Windows 選 .exe 或 .msi,macOS 選 .dmg。
  2. 安裝時 Windows 可能跳出「要不要安裝驅動程式」,請選「安裝」。macOS 把圖示拖到應用程式資料夾即可。
  3. 第一次打開會是英文介面。想改中文:File → Preferences → Language 選「繁體中文」,重新啟動。本書下面都用中文選單名稱。
  4. 用 USB 線把 UNO 接到電腦,板子上的 ON 燈會亮。
  5. 選開發板:功能表「工具 → 開發板 → Arduino AVR Boards → Arduino UNO」。IDE 2 也可以直接點視窗上方中間那個下拉選單,選有「Arduino UNO」字樣的那個。
  6. 選連接埠:「工具 → 連接埠」。Windows 會看到 COM3、COM5 之類(數字因電腦而異);macOS 會看到 /dev/cu.usbmodem14101 之類。選那個後面寫著「(Arduino UNO)」的。如果不確定,拔掉板子看哪個選項消失,那個就是。
  7. 視窗左上角兩個按鈕:**✓(驗證)只檢查程式有沒有寫錯,→(上傳)**檢查後把程式送進板子。上傳時 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 或 0VdigitalWrite(9, HIGH)
digitalRead(腳位)讀輸入腳位,得到 HIGH 或 LOWint 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 開頭
}

步驟

  1. 接好線,確認 LED 長短腳沒接反。
  2. 打開 IDE,把程式打進去(或複製貼上),確認開發板與連接埠選對。
  3. 按 ✓ 驗證,下方沒有紅字就按 → 上傳。
  4. LED 應該開始閃。順便看板子上的 L 燈:它沒閃,因為我們用的是 D9,不是 D13。
  5. 把兩個 delay(500) 都改成 delay(100),上傳,看閃的速度。
  6. 改成 delay(1000),再上傳。
  7. 把第一個 delay 改成 100、第二個改成 900(亮短暗長),觀察差別。

你應該看到

  • delay(500):亮半秒、暗半秒,一秒閃一次。
  • delay(100):閃得很快,一秒五次。
  • delay(1000):亮一秒、暗一秒。
  • 100/900:短促的一閃,像警示燈。

觀察與記錄

亮的 delay(ms)暗的 delay(ms)一個週期幾秒一秒閃幾次看起來像什麼
500500
100100
10001000
100900

實驗 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);                // 暗
  }
}

步驟

  1. 接線、上傳。
  2. 按住按鈕,LED 亮;放開,LED 暗。
  3. 挑戰:把 HIGH 和 LOW 對調,變成「按下才暗」。
  4. 再挑戰:改成「按一下亮、再按一下暗」(提示:需要一個記住目前狀態的變數,還有第 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 行,不要塞車
}

步驟

  1. 上傳後打開序列埠監控視窗(右上角放大鏡),右下角速度選 9600。
  2. 看訊息一行一行出來。按住按鈕幾秒,看數字從 1 變 0,再放開。
  3. 把 delay(200) 改成 delay(10),看視窗會變成怎樣。
  4. 把速度改成 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示波器量到的週期量到的頻率
5001000 ms = 1 s1 Hz200 ms
100200 ms5 Hz50 ms
1020 ms50 Hz5 ms
12 ms500 Hz500 µ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× → 兩邊設一致。

想一想

  1. setup() 和 loop() 各跑幾次?如果把 pinMode 寫在 loop() 裡會怎樣?
參考答案

setup() 開機後跑一次,loop() 一直重複。pinMode 放 loop 裡功能上還是能動,但每一圈都重新設定一次,浪費時間,也容易讓人看不懂,應該放 setup。

  1. 要讓 LED 每秒閃 10 次,亮暗時間一樣長,兩個 delay 要填多少?
參考答案

每秒 10 次 → 週期 100 ms → 亮 50 ms、暗 50 ms,兩個都填 delay(50)。

  1. 程式寫 delay(1) 亮、delay(1) 暗,示波器為什麼量到 498 Hz 而不是剛好 500 Hz?
參考答案

因為 digitalWrite 和 loop 本身也要花幾微秒,實際週期比 2 ms 多一點點,例如 2.008 ms → 1 ÷ 0.002008 ≈ 498 Hz。delay 越短,這個誤差占的比例越大;delay(500) 時幾乎看不出來。

  1. 序列埠用 9600 鮑率,一行訊息 30 個字元,傳完大約要多久?如果 loop 裡沒有 delay,一秒最多能印幾行?
參考答案

一個字元約 10 位元,30 字元 = 300 位元,300 ÷ 9600 ≈ 0.031 秒 = 31 ms。一秒最多約 1000 ÷ 31 ≈ 32 行。超過這個速度,程式會被序列埠拖慢。

  1. 有一位同學的 Blink 上傳成功,但 LED 不亮。他用三用電表量 D9 對 GND,讀到 0V 和 5V 慢慢交替。問題在哪裡?
參考答案

板子和程式都正常,是 LED 那邊的問題:LED 接反(長短腳顛倒)、電阻沒插到同一排、或 LED 壞了。把 LED 轉 180 度最常解決。

  1. 開放挑戰:只用一個按鈕和一顆 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一顆小晶片,裡面有大腦、記憶體和腳位,專門做你教它的事。
草稿碼SketchArduino 程式檔案的名字。
整合開發環境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 MonitorIDE 裡顯示板子送來的文字的視窗。
毫秒計時millis()回傳開機到現在經過的毫秒數。