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

前言 開始之前

這本書是給誰的

這本書是寫給想自己動手搞懂電的人。主要對象是國小五、六年級程度較好的學生與國中生,但完全沒碰過電子的大人也可以從第 1 章讀起。它假設你會四則運算、會把 a = b × c 移項、看得懂折線圖,其他都從零開始。

它的目標不是讓你背公式,而是讓你親手把電路接起來、親眼用儀器看到電在做什麼。

市面上的電學教材常常分成兩種:一種只講理論,算了一堆歐姆定律卻沒摸過電阻;另一種只教 Arduino 接線和複製程式碼,做出會動的東西卻不知道為什麼會動。這本書把兩者接在一起:每個概念都有一個「動手做」的實驗,每個實驗都盡量用示波器或邏輯分析儀把看不見的電壓與訊號畫出來。當你第一次在示波器上看到電容充電的圓弧曲線、第一次用邏輯分析儀解碼出 Arduino 傳出的 “Hello”,那個「原來如此」的瞬間就是這本書存在的理由。

給同學:怎麼讀這本書

  1. 一定要動手做。 只看不做,一週後就會忘光。
  2. 接錯了不要怕。 本書只用低電壓,最糟糕的狀況是燒掉一顆幾塊錢的零件。但請遵守下面的安全守則。
  3. 每章的「想一想」要真的想。 答案就在底下,但先想過再看,才會真的學到。
  4. 把量到的數字記下來。 書裡有很多空白表格,填上去。真正的工程師都會記錄數據。
  5. 卡關的時候看「常見錯誤與除錯」和附錄 E。 你遇到的問題,九成別人也遇過。
  6. 一週一章就好。 一章約 2–3 小時含實驗,全書大約半年。不要趕,實驗做完、數字填完再往下。
  7. 已經玩過 Arduino 的人可以從第 5 章開始,但請回頭補第 2、3 章的計算,後面的章節都靠它們。

給陪讀的家長

你不需要先懂電學。和孩子一起讀、一起接線、一起轉示波器的旋鈕就好。你最有用的角色是:

  • 採購與整理器材:附錄 A 有完整清單與購買提示。零件用分格盒裝好、貼上數值標籤,孩子才不會把時間花在找零件上。
  • 安全把關:讀一遍下面的安全守則,實驗前看一眼接線,尤其是電解電容的正負極與電池有沒有短路。
  • 卡關時陪著查:先翻該章的「常見錯誤與除錯」和附錄 E,再一起拿三用電表逐段量,通常都找得到問題。不要直接給答案。
  • 讓孩子自己操作儀器:示波器與邏輯分析儀是本書的特色,請讓孩子親手按按鈕、轉旋鈕,大人示範一次就好。

本書的器材都是台灣電子材料行與網購容易買到的常見零件,全書只用 12V 以下的直流電。

怎麼使用這本書

全書分成四部,共 17 章加附錄:

部章內容主要工具
第一部 基礎電學1–4電流、電壓、電阻、歐姆定律、串並聯、功率、電池三用電表、麵包板
第二部 電子元件與訊號5–10電容、示波器、電感、二極體、電晶體、交流與濾波示波器
第三部 數位與微控制器11–16數位邏輯、Arduino、感測器、PWM、通訊協定、ESP32Arduino、邏輯分析儀、ESP32
第四部 專題製作17五個完整專題與展示方法全部

每一章都有固定的段落:本章目標 → 開場 → 核心概念 → 動手做 → 用儀器看看 → 常見錯誤與除錯 → 想一想 → 本章小結 → 名詞表。你可以先讀目標和小結,知道這章要學什麼,再回頭仔細讀。

本書的電路圖用文字符號畫,看起來像這樣:

 Arduino D9 ──[ 220Ω ]──►|── GND
                        LED

── 是導線,[ 220Ω ] 是電阻,►| 是 LED 或二極體(箭頭方向是電流可以流的方向),GND 是接地(電路的「零點」)。每個實驗的文字圖下面還會有一張彩色的麵包板接線圖,照著插就可以。這些符號和正式的電路符號怎麼對照,請看附錄 G。

安全守則(一定要讀)

本書只用 12V 以下的直流電,來源是電池、USB、Arduino 或 ESP32。這些電壓不會電到人。但還是有幾件事要注意:

  1. 絕對不碰家用插座。 牆上的 110V 交流電會致命。本書任何實驗都不需要它。
  2. 電池不可以短路。 用導線直接把電池正負極接在一起,電線會發燙甚至起火。9V 電池與鋰電池尤其危險。
  3. 電解電容有正負極,接反會爆。 長腳是正極,殼上有白色條紋那邊是負極。接電源前先檢查兩次。
  4. 電阻、電晶體摸起來燙就先拔掉電源。 表示有東西接錯或電流太大。
  5. 線圈、馬達、繼電器一定要加飛輪二極體(第 7 章會教),不然會產生高壓尖波打壞 Arduino。
  6. 示波器探棒的接地夾只能接電路的 GND。 接到別的地方可能燒壞示波器或你的電路。
  7. 接線時先拔掉電源,接完檢查再接上。 養成這個習慣可以避免九成的意外。
  8. LED 一定要串電阻。 沒有電阻的 LED 會在一秒內燒掉。

器材總表(簡版)

詳細的規格、數量和採購建議在附錄 A。這裡先列出你會用到的東西,讓你有個概念:

基本工具:麵包板、杜邦線、數位三用電表

被動元件:電阻包、陶瓷電容與電解電容、電感與漆包線

主動元件:LED、二極體(1N4007、1N4148)、電晶體(2N2222)、MOSFET(IRLZ44N)

輸入與輸出:按鈕、可變電阻、光敏電阻、DHT11 溫濕度感測器、蜂鳴器、小直流馬達、SG90 伺服馬達、繼電器模組、0.96 吋 OLED

電源:9V 電池、3 號電池盒、USB 線

微控制器:Arduino UNO、ESP32 DevKit V1

儀器:示波器(雙通道)、USB 邏輯分析儀

示波器與邏輯分析儀是什麼(一頁預告)

這兩台儀器是本書的主角,第 6 章和第 15 章會完整教。這裡先讓你有個印象。

三用電表只能告訴你「現在的電壓是 3.2V」,一個數字。但電路裡的電壓常常是一直在變的,例如 Arduino 讓 LED 每秒閃一次,電壓就是 5V、0V、5V、0V 一直跳。三用電表看不出來。

**示波器(Oscilloscope)**就是一台「把電壓隨時間的變化畫成圖」的機器。橫軸是時間,縱軸是電壓。你會看到方波、正弦波、電容充電的圓弧線、馬達關掉時的高壓尖波。它讓看不見的東西變成看得見。

電壓
 5V ┤    ┌────┐    ┌────┐
    │    │    │    │    │
 0V ┼────┘    └────┘    └──── 時間

**邏輯分析儀(Logic Analyzer)**專門看數位訊號,也就是只有 0 和 1 的訊號。它一次可以看 8 條線,而且可以幫你「翻譯」:Arduino 用序列埠印出 “Hello”,邏輯分析儀能把那串 0 和 1 解碼回 H、e、l、l、o 給你看。晶片之間怎麼講話,用它一看就懂。

CH0 (TX) ─────┐ ┌─┐ ┌───┐ ┌─┐ ┌─────
              └─┘ └─┘   └─┘ └─┘
             起始 0 1 0 0 1 0 0 0 停止  → 'H'

準備好了嗎?翻到第 1 章,我們從一顆電池和一顆 LED 開始。

第 1 章 電是什麼

本章目標

  • 學完你會用「水流」的比喻,說出電荷、電流、電壓各是什麼,以及它們的單位。
  • 學完你會分辨導體與絕緣體,並且解釋為什麼電路一定要「繞成一圈」才會動。
  • 學完你會看懂麵包板裡面哪些孔是相連的,知道杜邦線該插哪裡。
  • 學完你會用數位三用電表量電池的電壓,也會把電表「串」進電路裡量電流。
  • 學完你會親手接出人生第一個電路:電池+電阻+LED,而且知道每個零件為什麼要在那裡。

開場:一顆不亮的燈

小安的手電筒壞了。他把電池拿出來,換上新的,還是不亮。他把電池反過來裝,不亮。他把燈泡轉一轉,喀的一聲,燈亮了!原來是燈泡沒鎖緊,金屬接點之間有一點點空隙。

「只是一點點空隙,電為什麼過不去?」小安問。

這是一個非常好的問題。電不是魔法,它很像水:水要流動,需要水壓、需要水管,而且水管不能斷掉。電要流動,需要電壓、需要導線,而且整條路一定要繞成一個圈。只要中間有一小段斷掉,哪怕只有一根頭髮那麼細的縫,電就不走了。

這一章,我們要先搞懂「電」到底是什麼東西、它怎麼流、靠什麼推動。接著你會認識兩個以後每一章都會用到的好朋友:麵包板和三用電表。最後,你會接出自己的第一個電路,親眼看到 LED 亮起來,然後用電表量出它「吃」了多少電。

核心概念

電荷:會互相推擠的小東西

用塑膠尺摩擦頭髮之後去吸小紙片,那就是電荷(Electric Charge)在作怪。

所有東西都是由原子組成的,原子裡有帶正電的質子和帶負電的電子(Electron)。平常正負一樣多,互相抵消,東西看起來「沒電」。但電子很輕、很容易被搬走,某個地方電子多了或少了,那裡就帶電了。

電荷有一個很重要的脾氣:同性相斥、異性相吸。電路裡的電流,說穿了就是一大群電子因為被推、被吸而一起移動。

電荷的單位是庫侖(Coulomb),記作 C。一庫侖是非常多的電子,大約是 6 後面再接 18 個零那麼多顆。本書幾乎不會直接用到庫侖,但它是理解「電流」的基礎。

電流:每秒流過多少電荷

想像一條水管,你想知道水流得多「大」,最自然的方法就是問:每秒鐘流過多少水? 每秒 1 公升,和每秒 10 公升,當然是後者水流比較大。

電流(Current)就是這個意思:每秒鐘流過導線某一個截面的電荷量。

電流 I = 電荷量 Q ÷ 時間 t

電流的單位是安培(Ampere),記作 A。1 A 就是每秒流過 1 庫侖的電荷。

算一個例子: 如果 10 秒內有 5 庫侖的電荷流過一條導線,電流就是 5 ÷ 10 = 0.5 A。

在我們的電路裡,1 A 其實是很大的電流,LED 這種小東西只需要大約 0.01 A 就很亮了。所以你常會看到一個更小的單位:毫安培(mA),1 mA = 0.001 A,也就是 1 A = 1000 mA。例如 0.02 A 就是 20 mA;反過來,7 mA 就是 0.007 A。

電流的方向: 全世界都約定電流從電源的正極(+)流出,經過電路,流回負極(-)。有趣的是,真正在動的電子其實是反方向跑的,這是歷史上先約定方向、後來才發現電子的結果。整本書我們都照「正極流向負極」來想,所有公式都是這樣定義的,不會出錯。

電壓:推動電流的「水壓」

水為什麼會從水塔流到你家的水龍頭?因為水塔比較高,有「水壓」在推。水塔越高,水噴得越有力。

電壓(Voltage)就是電路裡的水壓:兩個點之間「推動電荷的力道」的差距,也叫電位差。單位是伏特(Volt),記作 V。

請記住:電壓永遠是「兩點之間」的東西。 說「這裡有 5V」其實是省略了「比另一點高 5V」,就像「水塔 20 公尺高」是指「比地面高 20 公尺」。

算一個例子: 一顆 3 號電池大約 1.5V,意思是正極比負極高 1.5V。把兩顆頭尾相接(第一顆的正極接第二顆的負極),就像把兩座水塔疊起來,總電壓是 1.5 + 1.5 = 3V。

生活中常見的電壓:

電源電壓
3 號電池(一顆)約 1.5V
9V 方型電池約 9V
USB 充電孔5V
Arduino UNO 的 5V 腳位5V
ESP32 的 3V3 腳位3.3V
家用插座110V(本書絕對不碰)

本書只用 12V 以下的直流電,摸到不會有感覺,很安全。但家用插座的 110V 可以讓人受傷甚至死亡,全書任何實驗都不可以接插座。

導體與絕緣體

水要流動需要水管,電要流動需要能讓電子通過的材料。

  • 導體(Conductor):電子可以在裡面自由跑的材料。金屬都是導體,像銅、鋁、鐵。鹽水和人體也能導電(所以濕手摸電很危險)。
  • 絕緣體(Insulator):電子跑不動的材料。像塑膠、橡膠、玻璃、乾木頭和空氣。

你手上的杜邦線就是「銅線(導體)外面包塑膠皮(絕緣體)」,讓你可以安全地拿著線。

閉合迴路:電一定要繞一圈

這是本章最重要的觀念,也是小安手電筒的答案。

想像水族箱的水泵:水從水泵出來,流過水管、過濾器,然後再流回水泵。如果把回程的水管剪斷,水泵還是在轉,但水不會持續流動,因為沒有路可以回去。

電路(Circuit)這個英文字本來就是「繞一圈」的意思。電流從電源正極出發,經過導線和零件,一定要能夠回到電源負極,整個圈完整無缺,電流才會流。這叫做閉合迴路(Closed Circuit)。

圈圈某處斷開了(開關打開、導線鬆脫、燈泡沒鎖緊),叫做斷路(Open Circuit),電流是 0。

相反的狀況叫短路(Short Circuit):電流找到一條「幾乎沒有阻礙」的捷徑,直接從正極衝回負極,不經過零件。這時電流會非常大,電池會發燙、甚至漏液。絕對不要用導線直接把電池的正極和負極接在一起。

   閉合迴路(LED 會亮)         斷路(LED 不亮)           短路(危險!)

    ┌──[ 1kΩ ]──►|──┐         ┌──[ 1kΩ ]──►|─ ─┐        ┌─────────────┐
    │           LED  │         │           LED   │        │             │
   ─┴─ 9V            │        ─┴─ 9V        斷開 │       ─┴─ 9V         │
   ─┬─               │        ─┬─                │       ─┬─            │
    │                │         │                 │        │             │
    └────────────────┘         └─────────────────┘        └─────────────┘
                                                          電流只走導線,
                                                          沒有任何零件擋住

GND:大家約定的「海平面」

我們說「玉山海拔 3952 公尺」,意思是比海平面高 3952 公尺。海平面就是大家約定的「0 公尺」。

電路裡也需要一個約定的「0V」,叫做接地(Ground),簡寫 GND。電路中每一點的電壓,都是「跟 GND 比,高了多少」。

  • 用電池時,電池的負極(-)就是 GND。
  • 用 Arduino 或 ESP32 時,板子上標著 GND 的腳位就是 GND。它們的 5V 腳位,意思就是「比 GND 高 5V」。

之後用示波器時,探棒的黑色鱷魚夾一定要夾在 GND;三用電表的黑棒通常也接 GND。先記住這個觀念,以後會省很多麻煩。

認識麵包板

麵包板(Breadboard)是一塊布滿小孔的塑膠板,裡面藏著一條一條的金屬夾片。零件的腳插進孔裡會被夾住,不用焊接就能接電路,拆掉重接也方便。

重點是:哪些孔在裡面是連在一起的? 這是初學者最容易接錯的地方。請仔細看這張圖:

   ┌───────────────────────────────────────────────────────┐
   │ + ○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○  + │ ← 電源軌:整排橫向相連
   │ - ○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○  - │ ← 電源軌:整排橫向相連
   │                                                       │
   │        a   b   c   d   e        f   g   h   i   j     │
   │  1     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○  1  │
   │  2     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○  2  │
   │  3     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○  3  │  ← 每一「列」的 a–e
   │  4     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○  4  │     五個孔相連,
   │  5     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○  5  │     f–j 五個孔相連,
   │  ⋮     ⋮   ⋮   ⋮   ⋮   ⋮   溝槽  ⋮   ⋮   ⋮   ⋮   ⋮      │     但 e 和 f 之間
   │ 30     ○═══○═══○═══○═══○        ○═══○═══○═══○═══○ 30  │     被中間溝槽隔開
   │                                                       │
   │ + ○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○  + │
   │ - ○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○═══○  - │
   └───────────────────────────────────────────────────────┘

   ═══ 代表裡面有金屬片相連

請記住三條規則:

  1. 中間的主區域:同一列的 a、b、c、d、e 五個孔是連在一起的;f、g、h、i、j 五個孔也是連在一起的。 但 e 和 f 之間有一條溝槽,兩邊不相通。上下不同列(例如第 1 列和第 2 列)也不相通。
  2. 兩側的電源軌(標著+和-的長條):整排橫向相連。 我們習慣把電源的正極接到+軌,GND 接到-軌,這樣整塊板子到處都能拿到電。
  3. 注意: 有些比較長的麵包板,電源軌在正中央會斷開成左右兩段。拿到新麵包板時,先用三用電表的蜂鳴檔(本章後面會教)確認一下。

所以,如果你把 LED 的兩隻腳分別插在 a3 和 b3,它們會被同一條金屬片連在一起,等於把 LED 短路,當然不會亮。正確做法是把兩隻腳插在不同列,例如 a3 和 a4,或者跨過溝槽插在 e3 和 f3。

杜邦線

杜邦線(Jumper Wire)是接麵包板用的細導線,接頭有兩種:公頭(Male) 是一根金屬針,可以插進麵包板或 Arduino 的孔;母頭(Female) 是一個小洞,可以套在模組的針腳上。「公公線」兩端都是針,「公母線」一端針一端洞。本書大部分時候用公公線。

三用電表怎麼量電壓

三用電表(Multimeter)是電學實驗最重要的工具,可以量電壓、電流、電阻(所以叫「三用」)。本書用數位三用電表,有液晶螢幕、旋轉開關、兩支測棒(紅、黑)。

量電壓的四個步驟:

  1. 插測棒。 黑色測棒插進標著 COM 的孔(Common,共同端)。紅色測棒插進標著 V(通常是 VΩmA 或 VΩ)的孔。
  2. 轉旋鈕。 轉到直流電壓檔,記號是 DCV 或 V⎓(V 加上一條直線和一條虛線)。注意不要轉到 ACV(交流電壓,記號是 V~),那是量插座用的。如果你的電表有好幾個數字檔位(200m、2、20、200、1000),請選比你要量的電壓大一點點的那個:量 1.5V 的電池選 2V 或 20V 檔;量 9V 電池選 20V 檔。如果你的電表是「自動量程」,就只要轉到 V⎓ 就好。
  3. 把測棒跨在兩點之間。 紅棒碰電壓高的那一點(電池正極),黑棒碰電壓低的那一點(電池負極或 GND)。量電壓時,電表是「並排」在零件旁邊的,電路照常運作,不需要拆線。
  4. 讀數字。 螢幕顯示的就是兩點之間的電壓。如果出現負號(例如 −1.48),表示紅黑棒碰反了,大小還是對的,電表不會壞,調換一下就好。
   量電壓:電表「跨」在兩點之間,不用拆電路

          ┌──[ 1kΩ ]──┬──►|──┬───┐
          │           │  LED  │   │
         ─┴─ 9V      紅棒    黑棒  │
         ─┬─          │       │   │
          │        ┌──┴───────┴─┐ │
          │        │  三用電表   │ │
          │        │   V⎓ 20   │ │
          │        └────────────┘ │
          └───────────────────────┘
           這樣量的是 LED 兩端的電壓

三用電表怎麼量電流

量電流跟量電壓完全不一樣,這是初學者最常搞混、也最常把電表弄壞的地方。

回想水管:要知道水管裡每秒流過多少水,你得把水管切開,把流量計接在水管中間,讓所有的水都從流量計流過去。電流也一樣:你必須把電路切開一個缺口,把電表串進去,讓電流從電表裡面流過。 這叫做串聯(Series)量測。

量電流的五個步驟:

  1. 插測棒。 黑棒還是插 COM。紅棒要換插到標著 mA 的孔(有些電表寫 VΩmA,和量電壓同一個孔;有些電表有獨立的 mA 孔,請看孔旁邊的字)。如果你的電表另外有一個 10A 或 20A 的孔,那是量很大電流用的,本書大部分實驗用不到。
  2. 轉旋鈕。 轉到直流電流檔 DCA 或 A⎓。選比你預期的電流大一點的檔位,例如預期 7 mA 就選 20m(20 mA)檔;完全不知道多大就先從 200m 檔開始。
  3. 先把電源拔掉(拔掉電池扣或 USB),再把電路切開一個缺口。例如把電阻和 LED 之間的導線拔掉。
  4. 把電表接進缺口。 紅棒接電流「進來」的那一邊(靠近電源正極的那一邊),黑棒接電流「出去」的那一邊。然後接回電源。
  5. 讀數字。 單位要看你選的檔位:20m 檔顯示 7.03 就是 7.03 mA。
   量電流:電表「串」在電路中間,所有電流都要流過電表

          ┌──[ 1kΩ ]──┐           ┌──►|───┐
          │           │           │  LED  │
         ─┴─ 9V      紅棒         黑棒     │
         ─┬─          │           │       │
          │        ┌──┴───────────┴──┐    │
          │        │    三用電表      │    │
          │        │  A⎓ 20m  mA孔   │    │
          │        └─────────────────┘    │
          └───────────────────────────────┘
           電阻和 LED 之間切開,電表補上去

三個絕對要記住的警告:

  • 量電流時,電表內部幾乎是一條沒有阻礙的導線。 如果你在電流檔把兩支測棒直接碰電池的正負極(像量電壓那樣跨接),就等於把電池短路,電表裡的保險絲會燒斷,電表從此量不到電流。這是三用電表最常見的死因。
  • 量完電流,立刻把紅棒插回 V 孔、旋鈕轉回電壓檔。 不然下一次你想量電壓時,紅棒還在 mA 孔,一跨接就短路了。
  • 換檔位、插拔測棒時,先把電源拔掉。

動手做

實驗 1-1:量電池電壓

材料

  • 數位三用電表 1 台
  • 3 號電池 2 顆、3 號電池盒(2 顆裝)1 個
  • 9V 電池 1 顆、9V 電池扣 1 個

接線

這個實驗不用麵包板,直接用測棒碰電池就好。

   3 號電池(單顆)           9V 電池(接上電池扣)

      ┌──────────┐             ┌──────┐
   + │    AA    │ -          │  9V  │   電池扣:紅線=+,黑線=-
      └──────────┘             └─┬──┬─┘
      ▲          ▲               紅  黑
     紅棒       黑棒             ▲    ▲
                                紅棒  黑棒

步驟

  1. 黑棒插 COM,紅棒插 V 孔,旋鈕轉到 DCV 的 20V 檔(自動量程電表轉到 V⎓)。
  2. 紅棒碰 3 號電池凸起來的那一端(正極),黑棒碰平的那一端(負極)。讀數字,記在表格裡。
  3. 故意把紅黑棒對調再量一次,看看螢幕有什麼不同。
  4. 把兩顆 3 號電池裝進電池盒,量電池盒伸出來的紅線(+)和黑線(-)之間的電壓。
  5. 把 9V 電池扣扣上 9V 電池,量紅線和黑線之間的電壓。
  6. 試試看:旋鈕轉到 2V 檔再量 9V 電池。超過量程時電表會顯示「1」或「OL」,意思是量不到,不會壞,換回 20V 檔就好。

你應該看到

  • 單顆 3 號電池:新的大約 1.55–1.65V,用過的可能只剩 1.2–1.4V。
  • 兩顆串聯:大約是單顆的兩倍,例如 3.1V。
  • 9V 電池:新的大約 9.3–9.6V,用過的可能 8V 多。
  • 測棒反接:數字前面多一個負號。

觀察與記錄

量測對象預期電壓實際量到的電壓紅黑棒反接時顯示
3 號電池 A1.5V
3 號電池 B1.5V
A + B 串聯(電池盒)3.0V
9V 電池9V

想一想:A 加 B 量到的電壓,和 A、B 分別量到的電壓加起來,是不是幾乎一樣?

實驗 1-2:第一個電路——點亮一顆 LED

材料

  • 麵包板 1 塊
  • 9V 電池 1 顆、9V 電池扣 1 個
  • 1kΩ 電阻(色碼:棕 黑 紅 金)1 顆
  • 紅光 LED 1 顆
  • 公公杜邦線 2 條
  • 數位三用電表 1 台

關於這兩個零件:

  • LED(Light Emitting Diode,發光二極體)是只准電流「單向通行」的燈。長腳是正極(+),接電壓高的那邊;短腳是負極(-),接 GND。接反了不會亮,但也不會壞。
  • 電阻(Resistor)是用來「擋一下」電流的零件,沒有方向性。LED 很脆弱,直接接 9V 電池會一閃就燒掉。1kΩ 電阻會把電流限制在大約 7 mA,剛剛好。第 2 章會教你怎麼算,現在先記得:LED 一定要配電阻。

接線

   9V 電池扣紅線 ──[ 1kΩ ]──►|── 9V 電池扣黑線
                            LED
                        長腳  短腳

   麵包板上的位置(每一列的 a–e 五個孔互相連通):
          a     b     c     d     e
    5    紅線   ○    電阻   ○     ○      ← 電池扣紅線插 a5,電阻一腳插 c5
    6     ○    ○     │     ○     ○         (電阻的本體橫跨第 6、7 列)
    7     ○    ○     │     ○     ○
    8     ○    ○    電阻  LED長   ○      ← 電阻另一腳插 c8,LED 長腳插 d8,同列所以相連
    9    黑線   ○     ○   LED短   ○      ← LED 短腳插 d9,電池扣黑線插 a9,同列所以相連

文字說明:

  • 電池扣紅線 → 麵包板 a5
  • 1kΩ 電阻:一腳 c5,另一腳 c8
  • 紅光 LED:長腳 d8,短腳 d9
  • 電池扣黑線 → 麵包板 a9

這樣電流的路線是:紅線(+)→ 第 5 列 → 電阻 → 第 8 列 → LED 長腳 → LED → 短腳 → 第 9 列 → 黑線(-),剛好繞一圈。

步驟

  1. 先不要扣上 9V 電池。把電阻、LED、兩條線照上面的位置插好。
  2. 檢查三件事:LED 的長腳是不是在靠電阻那一側?電阻和 LED 是不是在同一列才相連?紅線和黑線有沒有不小心插在同一列?
  3. 扣上 9V 電池。LED 應該立刻亮起來。
  4. 把 LED 拔起來,左右腳對調再插回去。LED 應該不亮。這證明 LED 是有方向的。再把它換回正確方向。
  5. 用電表量三個電壓(旋鈕轉 DCV 20V 檔,紅棒插 V 孔):
    • 電池扣紅線與黑線之間(紅棒 a5、黑棒 a9)。
    • 電阻兩端(紅棒 c5、黑棒 c8)。
    • LED 兩端(紅棒 d8、黑棒 d9)。
  6. 做完後拔掉電池,省電也安全。

你應該看到

  • LED 亮起紅光,不會很刺眼,但在室內很清楚。
  • 電池大約 9V;LED 兩端大約 1.8–2.0V;電阻兩端大約 7V。注意:LED 電壓加上電阻電壓,差不多就等於電池電壓。這不是巧合,第 3 章會解釋。

觀察與記錄

量測位置紅棒插黑棒插量到的電壓
電池(紅線到黑線)a5a9
電阻兩端c5c8
LED 兩端d8d9
電阻電壓 + LED 電壓(用算的)

實驗 1-3:把電表串進電路量電流

材料

  • 實驗 1-2 接好的電路(不要拆)
  • 數位三用電表 1 台

接線

我們要把電阻和 LED 之間切開,把電表補上去。做法是把電阻在 c8 的那隻腳拔起來,改插到另一列(例如 c12),然後用電表的兩支測棒把 c12 和 d8 連起來。

   電池扣紅線 ──[ 1kΩ ]── 紅棒〔 三用電表 A⎓ 20m 〕黑棒 ──►|── 電池扣黑線
                                                         LED

   麵包板上:
    5    紅線  ○   電阻  ○   ○
    ⋮
    8     ○   ○   ○   LED長 ○      ← 黑棒插這一列(例如 e8)
    9    黑線  ○   ○   LED短 ○
    ⋮
   12     ○   ○   電阻  ○   ○      ← 電阻另一腳改插 c12,紅棒插這一列(例如 e12)

文字說明:

  • 電池扣紅線 → a5
  • 1kΩ 電阻:一腳 c5,另一腳 c12(原本在 c8)
  • 電表紅棒 → e12(和電阻同一列)
  • 電表黑棒 → e8(和 LED 長腳同一列)
  • LED 長腳 d8、短腳 d9,電池扣黑線 a9(不變)

步驟

  1. 先拔掉 9V 電池。
  2. 把電阻在 c8 的腳拔起來,改插 c12。這時候電路被切開了,中間有個缺口(第 12 列和第 8 列之間)。
  3. 電表:黑棒插 COM,紅棒換插到 mA 孔,旋鈕轉到 DCA 的 20m 檔(如果沒有 20m 就用 200m)。
  4. 紅棒插進 e12(靠電源正極那一邊),黑棒插進 e8(靠 LED 那一邊)。杜邦線的公頭可以直接插麵包板,測棒如果插不進去,可以用一條杜邦線插在麵包板上,再用測棒碰杜邦線露出的金屬。
  5. 扣上 9V 電池。LED 應該還是亮的(因為電表把缺口補起來了,迴路又閉合了),螢幕上會出現電流值。
  6. 拔掉電池,把 1kΩ 電阻換成 330Ω(橙 橙 棕 金),旋鈕改轉到 200m 檔(因為預期電流會超過 20 mA,留在 20m 檔會顯示「1」),接回電池再量一次電流,LED 是不是更亮?(330Ω 時電流大約 21 mA,還在 LED 安全範圍內。)
  7. 量完以後:拔掉電池,紅棒插回 V 孔,旋鈕轉回 DCV。 養成這個習慣。

你應該看到

  • 用 1kΩ 時,電流大約 7 mA(6–8 mA 都正常,看電池多新)。
  • 用 330Ω 時,電流大約 21 mA,LED 明顯比較亮。
  • 數字是負的:紅黑棒方向和電流方向相反,對調就好。
  • 顯示 0 而且 LED 不亮:電表沒有真的補上缺口,檢查測棒有沒有插緊。

觀察與記錄

電阻預期電流量到的電流LED 亮度(暗/中/亮)
1kΩ約 7 mA
330Ω約 21 mA

用儀器看看

這一章還不用示波器,但三用電表有一個超好用的功能:蜂鳴檔(Continuity,通路測試),它可以告訴你「這兩點有沒有連在一起」。

怎麼用:

  1. 旋鈕轉到有喇叭圖案或二極體符號(►|)的那一檔。有些電表要再按一個按鈕切換到蜂鳴模式。
  2. 黑棒插 COM,紅棒插 V 孔(和量電壓一樣)。
  3. 先把兩支測棒互相碰一下,應該「嗶」一聲,表示功能正常。
  4. 測棒碰在你想確認的兩點上。有嗶聲=相連;沒聲音=沒連。
  5. 一定要在沒通電的情況下用(拔掉電池)。

用蜂鳴檔探索麵包板: 拿一塊空的麵包板,把兩條杜邦線插在不同的孔,用測棒碰線的金屬端:

測試的兩個孔預期結果實際結果
a1 和 e1嗶(同一列 a–e 相連)
a1 和 a2無聲(不同列)
e1 和 f1無聲(被溝槽隔開)
+軌最左邊和+軌最右邊嗶(整排相連);若無聲,表示你的電源軌中間是斷開的

用蜂鳴檔找斷線: 杜邦線用久了裡面的銅絲可能斷掉,外表看不出來。測棒碰線的兩端,沒嗶就是壞線,丟掉。

預告: 第 6 章會用示波器看電池。電池的電壓在示波器上是一條平平的水平線,因為直流電不隨時間變化,和之後的方波、正弦波很不一樣。

常見錯誤與除錯

  • LED 不亮 → LED 接反了 → 確認長腳在靠電阻(電壓高)那一側。
  • LED 不亮 → 零件沒有真的接在一起 → 檢查電阻和 LED 的腳是不是插在同一列,而不是隔壁列;用蜂鳴檔從電池紅線開始一段一段確認。
  • LED 不亮,電池摸起來變熱 → 短路了 → 立刻拔掉電池。檢查紅線和黑線、或 LED 兩隻腳是不是插在同一列。
  • 電表顯示 1 或 OL → 量程太小 → 轉到更大的檔位。
  • 電表顯示負號 → 紅黑棒接反 → 對調測棒,數值本身是對的。
  • 數字一直跳動、不穩 → 測棒沒碰好,或電池快沒電 → 把測棒壓緊;換新電池。
  • 電流檔量到 0,LED 也不亮 → 電表沒有真的串進缺口 → 檢查測棒插的列;確認紅棒插在 mA 孔。
  • 電流檔量到 0,蜂鳴檔碰兩支測棒也不響 → 保險絲燒了 → 請老師協助更換。以後絕對不要在電流檔跨接電池。
  • 連電池都量不到 → 電表自己的電池沒電,或旋鈕轉到 ACV、Ω 區 → 換電表電池;確認旋鈕位置。

想一想

  1. 把三顆 1.5V 的 3 號電池頭尾相接串起來,總電壓是多少?
參考答案

1.5 + 1.5 + 1.5 = 4.5V。就像把三座一樣高的水塔疊起來。

  1. 你量 9V 電池時,螢幕顯示 −8.72。這代表什麼?電池壞了嗎?
參考答案

負號代表紅棒碰到負極、黑棒碰到正極,接反了。電池電壓是 8.72V,比 9V 低一些,用過一陣子但還能用。電池和電表都沒壞,測棒對調就會顯示 8.72。

  1. 為什麼量電流的時候,絕對不能像量電壓那樣,把兩支測棒直接碰在電池的正負極上?
參考答案

電流檔時電表內部幾乎是一條沒有阻礙的導線。直接碰電池兩極,等於把電池短路,會產生非常大的電流,保險絲會燒斷,電池也會發燙。量電流一定要把電表串進電路的缺口,讓電路裡的電阻限制電流。

  1. 小美把 LED 的長腳插在麵包板的 c7,短腳插在 d7,然後電阻的一腳也插在 e7。LED 會亮嗎?為什麼?
參考答案

不會亮。c7、d7、e7 都在第 7 列的 a–e 組,被同一條金屬片連在一起。LED 的兩隻腳被直接接通,電流從金屬片走捷徑,不經過 LED(LED 被短路)。兩隻腳必須插在不同列。

  1. 實驗 1-3 用 1kΩ 時,電流大約是 0.007 A。如果 LED 亮了 1 分鐘,總共有多少庫侖的電荷流過 LED?
參考答案

電荷量 Q = 電流 I × 時間 t = 0.007 A × 60 秒 = 0.42 C。看起來很小,但其實是幾十億億顆電子流過去了。

  1. (開放挑戰)請在實驗 1-2 的電路裡加一個按鈕開關,讓 LED 只有在按住按鈕時才亮。用 ASCII 畫出電路圖,並說明開關要放在迴路的哪裡。提示:按鈕平常是「斷開」的,按下去才「接通」。
參考答案

開關可以放在迴路的任何位置,因為只要迴路有一處斷開,整個迴路就沒電流:

   9V 紅線 ──/ ──[ 1kΩ ]──►|── 9V 黑線
           按鈕              LED

沒按時迴路不閉合,LED 不亮;按住時迴路閉合,LED 亮。放在電阻前面、中間或 LED 後面效果都一樣。注意按鈕開關有四隻腳,兩兩成對,要接「按下才會相通」的那一對,可以先用蜂鳴檔確認。

本章小結

  • 電流是「每秒流過多少電荷」,單位是安培(A);本書常用毫安培(mA),1 A = 1000 mA。
  • 電壓是推動電荷的力道,單位是伏特(V),而且永遠是「兩點之間」的差距。
  • GND 是大家約定的 0V 參考點,電路中每個點的電壓都是「比 GND 高多少」。
  • 電流只能在閉合迴路裡流動:從電源正極出發,經過零件,一定要回到負極。斷一處就全停。
  • 短路(正負極直接相連)會產生大電流,讓電池發燙,絕對要避免。
  • 麵包板中間區域同一列的 a–e 相連、f–j 相連,兩側電源軌整排相連;不確定就用蜂鳴檔測。
  • 量電壓:紅棒插 V 孔,轉 DCV,把電表「跨」在兩點之間,不用拆電路。
  • 量電流:紅棒插 mA 孔,轉 DCA,把電路切開,把電表「串」進缺口;量完立刻插回 V 孔。
  • LED 長腳接正極、短腳接負極,而且一定要串一顆電阻限制電流。

名詞表

中文英文一句話解釋
電荷Electric Charge讓東西「帶電」的基本性質,有正有負,單位庫侖(C)。
電子Electron帶負電的微小粒子,在導線裡移動就形成電流。
電流Current每秒流過的電荷量,單位安培(A),符號 I。
安培Ampere電流的單位,1 A = 每秒流過 1 庫侖。
毫安培Milliampere(mA)千分之一安培,小電路常用的單位。
電壓Voltage兩點之間推動電荷的力道差距,單位伏特(V)。
伏特Volt電壓的單位,符號 V。
導體Conductor電流容易通過的材料,例如銅、鋁。
絕緣體Insulator電流不容易通過的材料,例如塑膠、橡膠。
電路Circuit讓電流繞一圈的路徑,由電源、導線、零件組成。
閉合迴路Closed Circuit完整沒有斷開的電路,電流才會流。
斷路Open Circuit電路某處斷開,電流為 0。
短路Short Circuit電流不經過零件直接從正極流回負極,會產生危險的大電流。
接地Ground(GND)電路中約定為 0V 的參考點。
麵包板Breadboard不用焊接就能插零件接電路的板子。
杜邦線Jumper Wire接麵包板用的細導線,接頭分公頭與母頭。
三用電表Multimeter可以量電壓、電流、電阻的儀器。
串聯Series零件頭尾相接排成一條線,電流依序流過每一個。
發光二極體LED通電會發光、只准電流單向通過的零件,長腳正極短腳負極。
電阻Resistor用來限制電流的零件,沒有方向性。
蜂鳴檔Continuity Test三用電表的功能,兩點相連時會嗶一聲。

第 2 章 電阻與歐姆定律

本章目標

  • 學完你會說出電阻是什麼、單位歐姆(Ω)代表什麼意思。
  • 學完你會看懂電阻上的四環色碼,不用電表也能讀出 220Ω、1kΩ、10kΩ。
  • 學完你會用三用電表的 Ω 檔量電阻,而且知道哪些情況量出來會不準。
  • 學完你會用歐姆定律 V = I × R 和它的兩個變形,算出電路裡的電壓、電流或電阻。
  • 學完你會自己算出 LED 該配多大的限流電阻,並且用電表驗證你算的對不對。

開場:為什麼不能把 LED 直接接電池?

上一章的實驗裡,我們在 LED 前面串了一顆 1kΩ 的電阻,然後說「第 2 章會告訴你為什麼」。現在就是時候了。

阿哲不信邪。他想:「電阻只是在『擋』電流,拿掉的話 LED 不就更亮嗎?」於是他把 LED 的長腳直接碰 9V 電池的正極、短腳碰負極。LED 閃了一下非常亮的光,然後……就再也不亮了。拿近一看,LED 裡面的小金屬片燒黑了。

LED 確實會「更亮」,但只有不到一秒。因為沒有電阻擋著,電流大到 LED 承受不了,它就像一根被太大電流燒斷的保險絲。

那麼,電阻到底要多大才「剛剛好」?太大 LED 太暗,太小 LED 燒掉。這一章要教你一個 200 年前德國老師歐姆(Georg Ohm)發現的簡單公式,它只有三個字母,卻是整本書最常用的工具。學會以後,你就能算出任何 LED 需要的電阻,再也不用猜。

核心概念

電阻:水管有多窄

回到水管的比喻。同樣的水壓,粗水管流出的水多,細水管流出的水少。細水管「阻礙」水流的能力比較強。

電阻(Resistance)就是材料阻礙電流通過的程度。導線很粗、材料是銅,電阻很小;電阻器裡面是一層薄薄的碳膜或金屬膜,電流很難擠過去,電阻就大。

電阻的單位是歐姆(Ohm),記作 Ω(希臘字母 Omega)。常用的倍數單位:

  • 1 kΩ(千歐姆)= 1000 Ω
  • 1 MΩ(百萬歐姆)= 1,000,000 Ω = 1000 kΩ

所以 4.7kΩ 就是 4700Ω,100kΩ 就是 100,000Ω。

電阻器(Resistor)這個零件,就是故意做出一個「固定大小的電阻」給我們用。它長得像一顆有兩隻腳的小膠囊,身上有幾圈彩色條紋,沒有方向性,兩隻腳隨便接都可以。本書用的是最常見的 1/4 瓦(W)碳膜電阻,「1/4 瓦」的意思是它最多能承受多少發熱,第 4 章會講。

讀電阻色碼

電阻太小了,印不下數字,所以用顏色條紋來表示數值,叫做色碼(Color Code)。四環電阻的規則是:

        第1環 第2環 第3環      第4環
          │    │    │          │
      ────┤██┼██┼██┼──────┼██├────
          │    │    │          │
        第1個 第2個 後面補    誤差
        數字  數字  幾個 0   (金=±5%)
顏色數字當第 3 環時:乘以
黑0×1(不補 0)
棕1×10(補 1 個 0)
紅2×100(補 2 個 0)
橙3×1000(補 3 個 0)
黃4×10000(補 4 個 0)
綠5×100000
藍6×1000000
紫7—
灰8—
白9—
金—第 4 環:誤差 ±5%
銀—第 4 環:誤差 ±10%

一個好記的口訣:黑棕紅橙黃,綠藍紫灰白,從 0 數到 9。

怎麼看方向? 金色(或銀色)那一環是誤差環,要放在最右邊。另一個線索是:第 1 環通常比較靠近電阻的邊緣。

算幾個例子:

色碼第 1、2 環第 3 環結果
紅 紅 棕 金2、2 → 22棕 → 補 1 個 0220Ω ±5%
橙 橙 棕 金3、3 → 33棕 → 補 1 個 0330Ω ±5%
棕 黑 紅 金1、0 → 10紅 → 補 2 個 01000Ω = 1kΩ
黃 紫 紅 金4、7 → 47紅 → 補 2 個 04700Ω = 4.7kΩ
棕 黑 橙 金1、0 → 10橙 → 補 3 個 010000Ω = 10kΩ
棕 黑 黃 金1、0 → 10黃 → 補 4 個 0100000Ω = 100kΩ

誤差是什麼意思? 金色代表 ±5%,所以一顆標示 1kΩ 的電阻,實際值可能在 950Ω 到 1050Ω 之間,都算合格。這也是為什麼用電表量出來通常不會剛好是整數。

有些電阻包裡會有五環電阻(三個數字環+倍數環+誤差環),規則一樣,只是前面多一個數字。附錄 C 有完整對照表。

用三用電表量電阻

不想看色碼、或是色碼看不清楚(紅色和橙色、棕色和紅色常常很難分)時,直接量最快。

  1. 黑棒插 COM,紅棒插 VΩmA(或 VΩ)孔,和量電壓一樣。
  2. 旋鈕轉到 Ω 區。如果有多個檔位(200、2000、20k、200k、2M),選比電阻值大一點的檔:量 220Ω 選 2000 檔;量 4.7kΩ 選 20k 檔;量 100kΩ 選 200k 檔。自動量程電表直接轉到 Ω 就好。
  3. 兩支測棒碰電阻的兩隻腳,等數字穩定。
  4. 讀數時注意單位:在 20k 檔顯示 4.68,意思是 4.68 kΩ;在 2000 檔顯示 218,意思是 218Ω。

三個會讓你量不準的狀況:

  • 電阻還接在電路上,而且電路通著電。 一定要拔掉電源,最好把電阻整顆拔下來量,不然其他零件會干擾讀值。
  • 兩隻手同時捏著電阻的兩隻腳。 你的身體也是導體,會跟電阻「並排」在一起讓讀值變小(第 3 章會解釋並聯)。量大電阻(10kΩ 以上)時影響特別明顯。只用一隻手,或用麵包板固定電阻。
  • 顯示「1」或「OL」。 檔位太小,轉到更大的檔。如果轉到最大檔還是「1」,表示兩點之間根本不通,可能是電阻燒斷了,或測棒沒碰好。

歐姆定律:電壓、電流、電阻的三角關係

現在把三個角色放在一起看:

  • 電壓(V)是推力:水壓。
  • 電阻(R)是阻礙:水管多窄。
  • 電流(I)是結果:實際流了多少。

直覺上:推力越大,流得越多;阻礙越大,流得越少。歐姆在 1827 年用實驗證明,這個關係不只是「大概」,而是剛剛好成正比:

V = I × R

電壓(伏特)= 電流(安培)× 電阻(歐姆)

這就是歐姆定律(Ohm’s Law)。因為是簡單的乘法,可以移項變成三種形式,看你想求什麼:

            ┌───────┐
            │   V   │        遮住你想求的那一個,
            ├───┬───┤        剩下的兩個怎麼擺,就怎麼算:
            │ I │ R │
            └───┴───┘
      求 V:V = I × R      (遮住 V,剩下 I 和 R 並排 → 相乘)
      求 I:I = V ÷ R      (遮住 I,剩下 V 在 R 上面 → 相除)
      求 R:R = V ÷ I      (遮住 R,剩下 V 在 I 上面 → 相除)

算三個例子(單位一定要先換成 V、A、Ω):

例一(求電流): 9V 電池接一顆 1kΩ 電阻,電流多大? I = V ÷ R = 9 ÷ 1000 = 0.009 A = 9 mA。

例二(求電流): 5V 接 330Ω,電流多大? I = 5 ÷ 330 = 0.01515 A ≈ 15.2 mA。

例三(求電阻): 我想讓 5V 的電源只流出 10 mA,該接多大的電阻? 先把 10 mA 換成 0.01 A。R = V ÷ I = 5 ÷ 0.01 = 500Ω。

例四(求電壓): 一顆 220Ω 電阻流過 20 mA 的電流,它兩端的電壓是多少? V = I × R = 0.02 × 220 = 4.4V。

一個很好用的小技巧:如果電壓用 V、電阻用 kΩ,算出來的電流單位剛好就是 mA。例如 9V ÷ 1kΩ = 9 mA,5V ÷ 4.7kΩ ≈ 1.06 mA,不用一直換 0.00 幾。

LED 的順向電壓

LED 和電阻有一個很大的不同:LED 不遵守歐姆定律。 它的行為比較像一道「門檻」:

  • 兩端電壓不到門檻時,幾乎沒有電流,不亮。
  • 電壓一到門檻,電流就會迅速增加,而且不管電流多大,LED 兩端的電壓幾乎都停在門檻附近,不太會再升高。

這個門檻電壓叫做順向電壓(Forward Voltage),記作 V_F。不同顏色的 LED 門檻不一樣,因為發光的材料不同:

LED 顏色順向電壓(大約)
紅1.8–2.2V(本書以 2.0V 計算)
黃2.0–2.2V
綠2.0–2.4V(本書以 2.2V 計算)
藍3.0–3.4V(本書以 3.0V 計算)
白3.0–3.4V(本書以 3.0V 計算)

LED 的「正常工作電流」一般是 10–20 mA。10 mA 就已經很清楚,20 mA 很亮,超過 30 mA 就開始縮短壽命,再大就會像阿哲的 LED 那樣燒掉。

限流電阻怎麼算

現在把歐姆定律和順向電壓合在一起,就能算出 LED 該配什麼電阻。這是全書最常用的計算,請一定要自己算一遍。

想法是這樣的:電源給的電壓,LED「吃掉」了 V_F,剩下的全部落在電阻上。然後用歐姆定律算出電阻。

R = (電源電壓 − LED 順向電壓) ÷ 目標電流

算一個例子: 電源 5V(Arduino 的 5V 腳位),紅光 LED(V_F = 2.0V),希望電流 10 mA。

  1. 落在電阻上的電壓:5 − 2.0 = 3.0V。
  2. 目標電流換成安培:10 mA = 0.01 A。
  3. R = 3.0 ÷ 0.01 = 300Ω。

但電阻包裡沒有 300Ω 這個值(常見的值是 220、270、330、390……)。該怎麼選?選比算出來大一點點的,電流會稍微小一些、LED 稍微暗一些,但絕對安全。所以我們選 330Ω。

驗算一下 330Ω 的實際電流: I = 3.0 ÷ 330 = 0.00909 A ≈ 9.1 mA。比 10 mA 少一點點,完全看不出差別。

如果選 220Ω 呢?I = 3.0 ÷ 220 ≈ 13.6 mA,也在安全範圍,會亮一些。所以在本書裡,5V 配紅光 LED,用 220Ω 或 330Ω 都可以,這也是為什麼器材清單裡這兩個值特別多。

再算一個例子: 電源 9V,紅光 LED,希望 10 mA。 R = (9 − 2.0) ÷ 0.01 = 700Ω → 選 1kΩ(實際電流 7 ÷ 1000 = 7 mA)。這就是第 1 章用 1kΩ 的原因。

動手做

實驗 2-1:讀色碼,再用電表驗證

材料

  • 電阻 6 顆:220Ω、330Ω、1kΩ、4.7kΩ、10kΩ、100kΩ(先不要看袋子上的標示,自己讀色碼)
  • 數位三用電表 1 台
  • 麵包板 1 塊(用來固定電阻,避免手指影響讀值)

接線

   電阻插在麵包板上,兩隻腳跨不同列:

          a   b   c   d   e
    3     ○   ○  電阻  ○   ○    ← 一腳插 c3
    4     ○   ○   │   ○   ○
    5     ○   ○  電阻  ○   ○    ← 另一腳插 c5

   紅棒碰 a3、黑棒碰 a5(和電阻的腳同列,所以相連)

  • 電阻一腳 → c3,另一腳 → c5
  • 電表紅棒 → a3,黑棒 → a5(電阻沒有方向,紅黑對調也可以)

步驟

  1. 從電阻包隨便拿一顆,把金色環放右邊,從左邊開始讀三環顏色,用口訣算出電阻值,填進表格的「色碼讀出的值」。
  2. 把電阻插上麵包板。電表紅棒插 VΩmA 孔、黑棒插 COM,旋鈕轉到 Ω 區,選比你讀出的值大一點的檔位。
  3. 測棒碰 a3 和 a5,等數字穩定,填進「電表量到的值」,記得寫單位。
  4. 算一算誤差:(量到的值 − 色碼值) ÷ 色碼值 × 100%。應該在 ±5% 以內。
  5. 試試看:量 100kΩ 的時候,故意用兩隻手捏住電阻的兩隻腳,再看一次讀值,記下來。
  6. 六顆都做完。

你應該看到

  • 每一顆量到的值都跟色碼很接近,但通常不會剛好一樣,例如 1kΩ 量到 987Ω 或 1.01kΩ。
  • 用手捏 100kΩ 時,讀值會明顯變小(可能變成 80 幾 kΩ),因為你的身體提供了另一條路給電流走。

觀察與記錄

色碼(三環顏色)色碼讀出的值用的 Ω 檔位電表量到的值誤差 %
100kΩ 用手捏兩腳100kΩ

實驗 2-2:改變電阻看 LED 亮度,並量出電流

這是本章的主實驗:同一顆 LED,換五種電阻,看亮度怎麼變,再把電表串進去量電流,和歐姆定律算出來的比一比。

材料

  • Arduino UNO 1 塊+USB 線(只當作 5V 電源用,不用寫程式;也可以用 USB 行動電源配 USB 線剝線,但 Arduino 最方便)
  • 麵包板 1 塊
  • 紅光 LED 1 顆
  • 電阻:220Ω、330Ω、1kΩ、4.7kΩ、10kΩ 各 1 顆
  • 公公杜邦線 3 條
  • 數位三用電表 1 台

接線

   Arduino 5V ──[ R ]──►|── Arduino GND
                       LED
                    長腳 短腳

   麵包板:
          a    b    c    d    e
    3    5V線  ○   電阻   ○    ○      ← Arduino 5V 接 a3,電阻一腳 c3
    4     ○   ○    │    ○    ○
    5     ○   ○   電阻  LED長  ○      ← 電阻另一腳 c5,LED 長腳 d5
    6   GND線  ○    ○   LED短  ○      ← LED 短腳 d6,Arduino GND 接 a6

  • Arduino 5V 腳位 → 麵包板 a3
  • 電阻 R:一腳 c3,另一腳 c5
  • 紅光 LED:長腳 d5,短腳 d6
  • Arduino GND 腳位 → 麵包板 a6

步驟

  1. Arduino 先不要插 USB。先插 330Ω 電阻、LED 和兩條線。再檢查一次:5V 線和 GND 線絕對不能插在同一列(那是短路,Arduino 會過熱保護)。
  2. 把 Arduino 的 USB 接上電腦或行動電源。LED 亮了。
  3. 先量電壓(紅棒 VΩmA 孔,DCV 20V 檔):紅棒 d5、黑棒 d6,量 LED 兩端的順向電壓,記下來。你會發現它接近 2.0V,但不會剛好。
  4. 拔掉 USB。現在要量電流:把電阻在 c5 的腳拔起來改插 c9,讓電路出現缺口。電表紅棒換到 mA 孔,旋鈕轉 DCA 20m 檔。紅棒插 e9、黑棒插 e5。
  5. 接回 USB,LED 亮,讀電流,填表。
  6. 拔掉 USB,換下一顆電阻(220Ω),重複步驟 5。220Ω 預期約 13.6 mA,20m 檔夠用。
  7. 換 1kΩ、4.7kΩ、10kΩ。到 4.7kΩ 和 10kΩ 時,電流不到 1 mA,20m 檔只會顯示 0.6 或 0.3,不夠精細,請把旋鈕轉到 2000µ 檔(2000 微安培 = 2 mA),讀出來的數字單位是 µA,例如顯示 640 就是 640 µA = 0.64 mA。
  8. 每換一顆電阻,順便用眼睛比較 LED 亮度,用「很亮/亮/普通/暗/幾乎看不到」記錄。
  9. 做完記得紅棒插回 VΩmA 孔、旋鈕轉回 DCV。

你應該看到

把歐姆定律的預測先算好(假設 LED 順向電壓 2.0V,落在電阻上的電壓是 3.0V):

電阻預測電流 I = 3.0 ÷ R亮度預測
220Ω3.0 ÷ 220 ≈ 13.6 mA很亮
330Ω3.0 ÷ 330 ≈ 9.1 mA亮
1kΩ3.0 ÷ 1000 = 3.0 mA普通
4.7kΩ3.0 ÷ 4700 ≈ 0.64 mA暗
10kΩ3.0 ÷ 10000 = 0.30 mA很暗,但還看得到

實際量到的會跟預測有一點差距,原因有兩個:第一,電阻本身有 ±5% 誤差;第二,LED 的順向電壓在電流小的時候會稍微低一點(例如 0.3 mA 時可能只有 1.8V),所以小電阻那幾列會比預測略高。差個 10% 都算正常,這就是真實世界和公式的差別。

觀察與記錄

電阻預測電流量到的電流量到的 LED 電壓亮度
220Ω13.6 mA
330Ω9.1 mA
1kΩ3.0 mA
4.7kΩ0.64 mA
10kΩ0.30 mA

實驗 2-3:驗證歐姆定律——固定電阻,改變電壓

實驗 2-2 有 LED 在裡面攪局(它不守歐姆定律)。這次我們把 LED 拿掉,只留一顆 1kΩ 電阻,換三種電源,看電流是不是真的跟電壓成正比。

材料

  • 1kΩ 電阻 1 顆
  • 3 號電池 2 顆+電池盒(約 3V)
  • Arduino UNO+USB 線(5V)
  • 9V 電池+電池扣(約 9V)
  • 麵包板、杜邦線、三用電表

接線

   電源+ ──[ 1kΩ ]── 紅棒〔 電表 A⎓ 20m 〕黑棒 ── 電源-

   麵包板:
          a    b    c    d    e
    3    電源+ ○   電阻   ○    ○
    4     ○   ○    │    ○    ○
    5     ○   ○   電阻   ○   紅棒
    ⋮
    8    電源- ○    ○    ○   黑棒

  • 電源正極(電池盒紅線 / Arduino 5V / 9V 電池扣紅線)→ a3
  • 1kΩ 電阻:一腳 c3,另一腳 c5
  • 電表紅棒 → e5,黑棒 → e8(電表串在電阻和電源負極之間)
  • 電源負極(電池盒黑線 / Arduino GND / 9V 電池扣黑線)→ a8

步驟

  1. 電表設定成量電流:紅棒 mA 孔,DCA 20m 檔,紅棒 e5、黑棒 e8。
  2. 接上 2 顆 3 號電池的電池盒,讀電流,填表。
  3. 接著量電壓:把電表拿開,改用一條杜邦線把 e5 和 e8 接起來(補上缺口),電表換成量電壓(紅棒 VΩmA 孔,DCV 20V),紅棒 b3、黑棒 b8,讀出電源電壓,填表。
  4. 換成 Arduino 5V,重複步驟 1–3。
  5. 換成 9V 電池,重複步驟 1–3。
  6. 每一列算 R = V ÷ I,看是不是都接近 1kΩ。

你應該看到

  • 大約 3V → 3 mA;5V → 5 mA;9V → 9 mA。電壓變三倍,電流也變三倍。
  • 每一列用 V ÷ I 算出來都接近 1000Ω(例如 4.98V ÷ 0.00497 A ≈ 1002Ω)。

如果你把「電壓」當橫軸、「電流」當縱軸,把三個點畫在方格紙上,它們會排成一條通過原點的直線。直線的斜率就是 1 ÷ R。這條直線,就是「歐姆定律」的長相。

觀察與記錄

電源量到的電壓 V量到的電流 IR = V ÷ I
2 顆 3 號電池
Arduino 5V
9V 電池

用儀器看看

本章的主角儀器還是三用電表,而且我們一口氣用了它的三種功能。整理一下三種模式的差別,這張表以後會一直用到:

要量什麼紅棒插哪旋鈕轉哪電表怎麼接電路要不要拆
電壓VΩmADCV(V⎓)跨在兩點之間(並排)不用
電流mA(或 VΩmA,看電表標示)DCA(A⎓)串進電路缺口要切開一個缺口
電阻VΩmAΩ碰電阻兩腳要拔掉電源,最好把電阻拔下來

用電表看 LED「不守歐姆定律」: 在實驗 2-2 裡你量了五次 LED 兩端電壓。把它們排在一起看:電流從 0.3 mA 變到 13.6 mA,變了 45 倍,但 LED 電壓只從大約 1.8V 變到 2.0V。如果 LED 是一顆電阻,電壓應該也要變 45 倍才對。這就是「門檻」的行為。

電表的二極體檔也能看 LED: 旋鈕轉到二極體符號(►|)那一檔(和蜂鳴檔通常是同一檔),紅棒碰 LED 長腳、黑棒碰短腳。LED 會微微亮起來,螢幕顯示的數字就是它的順向電壓(例如 1.85)。這是電表送出一個很小的測試電流(大約 1 mA)量出來的,所以會比 10 mA 時的值低一點。紅黑棒反接的話 LED 不亮、螢幕顯示「1」,再次證明 LED 有方向。

預告: 從第 5 章開始,示波器會登場。到時候你會看到,電阻兩端的電壓波形和流過它的電流波形「長得一模一樣」(只差一個倍數 R),這就是歐姆定律在示波器上的樣子。

常見錯誤與除錯

  • 色碼讀出來的值很奇怪(例如 22MΩ) → 從金色那一邊開始讀了,方向反了 → 把金色環放右邊再讀一次。
  • 棕色和紅色、紅色和橙色分不清 → 燈光不好或電阻印刷偏色 → 直接用電表量,色碼只是輔助。
  • Ω 檔顯示 1 或 OL → 檔位太小,或電阻根本沒接到 → 轉到更大檔;確認測棒碰到金屬腳。
  • Ω 檔讀值一直慢慢變 → 量大電阻時手指碰到腳 → 放開手,用麵包板固定。
  • 量電阻時讀值比色碼小很多 → 電阻還接在電路裡,其他零件並排干擾 → 把電阻拔下來單獨量。
  • LED 不亮,換哪顆電阻都不亮 → LED 接反了 → 長腳要在電阻那一側。
  • LED 不亮,Arduino 上的電源燈也暗了 → 5V 和 GND 短路,Arduino 過熱保護 → 立刻拔 USB,檢查 5V 線和 GND 線是不是插在同一列。
  • 量電流時顯示 1 → 電流超過檔位 → 轉到 200m 檔。
  • 量電流時顯示 0.00 但 LED 亮著 → 電表沒有真的串進缺口,電流從別的路走了 → 檢查缺口是不是真的斷開(電阻的腳是不是還留在原來那一列)。
  • 量 4.7kΩ、10kΩ 時電流顯示 0.6、0.3,變化看不清楚 → 檔位太粗 → 轉到 2000µ 檔讀微安培。
  • 量完電流忘記把紅棒插回 VΩmA → 下次量電壓時一跨接就短路,燒保險絲 → 養成「量完電流立刻插回去」的習慣。

想一想

  1. 一顆電阻的色碼是「紅 紫 橙 金」,它是幾 Ω?誤差多少?
參考答案

紅=2、紫=7,所以是 27;橙=補 3 個 0,所以是 27000Ω = 27kΩ;金=±5%。實際值可能在 25.65kΩ 到 28.35kΩ 之間。

  1. 把一顆 220Ω 的電阻直接接在 9V 電池上(沒有 LED),電流是多少?如果接的是 10kΩ 呢?
參考答案

I = V ÷ R。220Ω:9 ÷ 220 ≈ 0.0409 A ≈ 40.9 mA。10kΩ:9 ÷ 10000 = 0.0009 A = 0.9 mA。電阻大 45 倍,電流就小 45 倍。

  1. 用 5V 電源點亮一顆藍光 LED(順向電壓 3.0V),希望電流 10 mA。該用多大的電阻?電阻包裡沒有這個值的話該選哪個?選了之後實際電流多少?
參考答案

落在電阻上的電壓:5 − 3.0 = 2.0V。R = 2.0 ÷ 0.01 = 200Ω。電阻包裡選比 200Ω 大一點的 220Ω。實際電流 I = 2.0 ÷ 220 ≈ 9.1 mA。注意藍光 LED 的順向電壓比紅光高,所以同樣 5V 要用比較小的電阻。

  1. 阿哲這次學乖了,想用 9V 電池點紅光 LED,但他手邊只有 220Ω 的電阻。這樣安全嗎?算算看電流。
參考答案

落在電阻上的電壓:9 − 2.0 = 7V。I = 7 ÷ 220 ≈ 0.0318 A ≈ 31.8 mA。這已經超過 LED 建議的 20 mA 上限,LED 會很亮但壽命會縮短,摸起來可能會溫溫的。比較好的選擇是 1kΩ(7 mA)或 470Ω(約 14.9 mA)。

  1. 你用 Ω 檔量一顆插在電路裡、沒有拔下來的 10kΩ 電阻,電表顯示 4.8kΩ。電阻壞了嗎?
參考答案

很可能沒壞。電阻還接在電路上時,旁邊的其他零件(例如另一顆電阻)會和它「並排」,給電流另一條路走,所以電表量到的會比它本身小。把電阻拔下來單獨量,應該就會回到接近 10kΩ。(第 3 章學並聯之後你就會知道,10kΩ 旁邊如果並排一顆 9.2kΩ 左右的東西,量出來剛好就是 4.8kΩ。)

  1. (開放挑戰)ESP32 的電源是 3.3V,不是 5V。請算出用 ESP32 點紅光 LED、電流 10 mA 時該用的電阻,然後想一想:如果改用藍光 LED(3.0V),會發生什麼事?有什麼辦法解決?
參考答案

紅光:(3.3 − 2.0) ÷ 0.01 = 130Ω,電阻包裡選 150Ω(實際約 8.7 mA)或 220Ω(約 5.9 mA,稍暗但夠用)。藍光:3.3 − 3.0 只剩 0.3V 給電阻,(0.3 ÷ 0.01) = 30Ω。問題是藍光 LED 的順向電壓有 ±0.2V 的個體差異,如果拿到一顆 3.4V 的,3.3V 根本推不亮;拿到 3.0V 的又可能太亮。解決辦法:用 5V 當 LED 的電源(ESP32 板子上通常有 VIN 或 5V 腳位從 USB 拿電),或是接受亮度會不穩定、用 47Ω 左右稍微保護一下。這個問題在第 16 章用 ESP32 時會再遇到。

本章小結

  • 電阻是材料阻礙電流的程度,單位歐姆(Ω);1kΩ = 1000Ω,1MΩ = 1000kΩ。
  • 四環色碼:前兩環是數字,第三環是補幾個 0,第四環是誤差。口訣「黑棕紅橙黃,綠藍紫灰白」。
  • 用電表量電阻要拔掉電源、最好把電阻拔下來、手不要同時碰兩腳。
  • 歐姆定律:V = I × R,變形為 I = V ÷ R、R = V ÷ I。計算前先把單位換成 V、A、Ω(或用 V、mA、kΩ 這組也行)。
  • 電壓固定時,電阻越大電流越小;電阻固定時,電壓越大電流越大,而且是成正比的直線。
  • LED 不守歐姆定律:它有一個順向電壓門檻(紅約 2.0V、綠約 2.2V、藍/白約 3.0V),電流再大電壓也差不多。
  • LED 限流電阻:R = (電源電壓 − 順向電壓) ÷ 目標電流,算出來後選電阻包裡「比它大一點」的值。5V 配紅光 LED 算出 300Ω,選 330Ω,實際約 9.1 mA。
  • 三用電表三種模式(電壓、電流、電阻)的紅棒位置和接法不一樣,量完電流一定要把紅棒插回 VΩmA 孔。

名詞表

中文英文一句話解釋
電阻Resistance材料阻礙電流通過的程度,單位歐姆(Ω),符號 R。
歐姆Ohm(Ω)電阻的單位;1Ω 表示加 1V 會流 1A。
電阻器Resistor提供固定電阻值的零件,沒有方向性。
色碼Color Code用彩色條紋標示電阻值的方法。
誤差Tolerance電阻實際值和標示值可能的差距,金色 ±5%。
歐姆定律Ohm’s LawV = I × R,電壓、電流、電阻三者的關係。
成正比Proportional一個變幾倍,另一個也跟著變幾倍。
順向電壓Forward Voltage(V_F)LED 開始導通發光所需的門檻電壓。
限流電阻Current-limiting Resistor串在 LED 前面、把電流限制在安全範圍的電阻。
二極體檔Diode Test三用電表的功能,可以量 LED 或二極體的順向電壓。
微安培Microampere(µA)百萬分之一安培;1 mA = 1000 µA。
瓦Watt(W)功率的單位,電阻標示 1/4W 表示它能承受的發熱上限(第 4 章詳述)。

第 3 章 串聯與並聯

本章目標

  • 學完你會分辨串聯和並聯,並且算出兩顆電阻串聯、並聯之後的總電阻。
  • 學完你會用「水管分流」的方式說明克希荷夫的兩個定律:電流在分岔點守恆、電壓繞一圈歸零。
  • 學完你會用分壓器公式算出電路中某一點的電壓,並用電表量出來驗證。
  • 學完你會知道可變電阻的三隻腳各是什麼,並用它做出可以手轉調整的電壓。
  • 學完你會解釋為什麼兩顆 LED 並聯時「每顆都要有自己的電阻」。

開場:聖誕燈泡為什麼會「一顆壞,全部滅」?

你有沒有看過老式的聖誕燈串?幾十顆小燈泡串成一長串,只要其中一顆燒掉,整串全部熄滅,然後你得一顆一顆去找那顆壞的。

但家裡的電燈不是這樣。客廳的燈壞了,廚房的燈還是亮的。它們明明接在同一個電源上,為什麼行為差這麼多?

答案是接法不一樣。聖誕燈是「一顆接一顆排成一條線」,電流必須依序通過每一顆,任何一顆斷掉,整條路就斷了。家裡的燈是「每一盞各自接到電源」,像好幾條平行的水管,一條塞住,其他條照流。

前一種叫串聯,後一種叫並聯。這一章我們要把兩種接法徹底搞懂:總電阻怎麼算、電壓和電流怎麼分配,然後用這些知識做出兩個非常實用的東西:一個可以「調整電壓」的分壓器(之後讀感測器會一直用到),以及一組正確接法的並聯 LED。

核心概念

串聯:排成一條線

串聯(Series)就是把零件頭尾相接,排成一條沒有分岔的路。電流只有一條路可以走,所以流過每一個零件的電流都一樣大。

   串聯:
    + ──[ R1 ]──[ R2 ]── -
         ────► 同一個電流 I 流過 R1 和 R2

水管比喻:兩段窄水管接成一條,水要先擠過第一段,再擠過第二段,兩段的阻礙加在一起。所以串聯的總電阻就是直接相加:

R總 = R1 + R2

算兩個例子:

  • 220Ω 串聯 330Ω:R總 = 220 + 330 = 550Ω。
  • 1kΩ 串聯 4.7kΩ:R總 = 1000 + 4700 = 5700Ω = 5.7kΩ。

串聯之後的總電阻一定比任何一顆都大。三顆以上也一樣,全部加起來就對了。

並聯:分成好幾條路

並聯(Parallel)是把零件的兩端分別接在一起,讓電流有好幾條路可以同時走。因為每個零件的兩端都接在同樣的兩點上,所以每個零件兩端的電壓都一樣大。

   並聯:
              ┌──[ R1 ]──┐
    + ───────┤          ├─────── -
              └──[ R2 ]──┘
         R1 和 R2 的兩端都接在同樣的兩個點上,電壓相同

水管比喻:在一條水管旁邊再並排一條水管,水可以分兩邊走,整體變得「更容易通過」。所以並聯之後總電阻會變小,比最小的那一顆還要小。

兩顆電阻並聯的公式(本書只教兩顆的情況):

R總 = (R1 × R2) ÷ (R1 + R2)  (口訣:積除以和)

算三個例子:

  • 10kΩ 並聯 10kΩ:(10000 × 10000) ÷ (10000 + 10000) = 100,000,000 ÷ 20,000 = 5000Ω = 5kΩ。 → 兩顆一樣大的電阻並聯,總電阻剛好是一半。這個規則很好記。
  • 220Ω 並聯 330Ω:(220 × 330) ÷ (220 + 330) = 72,600 ÷ 550 = 132Ω。
  • 1kΩ 並聯 4.7kΩ:(1000 × 4700) ÷ (1000 + 4700) = 4,700,000 ÷ 5700 ≈ 825Ω。 → 注意:結果 825Ω 比 1kΩ 還小。一顆大電阻並聯在小電阻旁邊,總電阻會比小的那顆再小一點點。這就是第 2 章「用手捏電阻讀值會變小」的原因:你的身體(幾百 kΩ)並聯在電阻旁邊了。

用 kΩ 算也可以,數字會小很多:1 × 4.7 ÷ (1 + 4.7) = 4.7 ÷ 5.7 ≈ 0.825kΩ。

克希荷夫電流定律:分岔點進出的水量一樣多

德國物理學家克希荷夫(Gustav Kirchhoff)在 1845 年整理出兩條電路的基本規則,聽起來很厲害,其實用水管想就很直覺。

第一條是克希荷夫電流定律(Kirchhoff’s Current Law,簡稱 KCL):流進一個分岔點的電流總和,等於流出這個分岔點的電流總和。

水管比喻:一條大水管分成兩條小水管,每秒流進分岔點 10 公升,那兩條小水管加起來每秒也一定流出 10 公升,不多不少。水不會憑空消失,也不會在分岔點堆起來。電流也是。

             I1 = 9 mA
          ┌──[ 330Ω ]──►|──┐
   I總 ───┤              紅  ├─── I總 = I1 + I2 = 17.5 mA
          └──[ 330Ω ]──►|──┘
             I2 = 8.5 mA   綠

算一個例子: 兩條支路並聯,一條流 9 mA,另一條流 8.5 mA,從電源流出來的總電流就是 9 + 8.5 = 17.5 mA。

克希荷夫電壓定律:繞一圈回到原點,高度差歸零

第二條是克希荷夫電壓定律(Kirchhoff’s Voltage Law,簡稱 KVL):沿著任何一個閉合迴路走一圈,電源提供的電壓,等於沿路所有零件「吃掉」的電壓加起來。

水管比喻:水泵把水抽高 9 公尺,水沿著管子流回水泵的過程中,會在每一段窄管「掉」一些高度,掉的總和一定剛好是 9 公尺,因為它最後回到了起點。

第 1 章實驗 1-2 你已經量過了:電池 9V,電阻兩端約 7V,LED 兩端約 2V,7 + 2 = 9。那不是巧合,就是 KVL。

算一個例子: 9V 電池,串聯一顆 330Ω 電阻、一顆紅光 LED(2.0V)、一顆綠光 LED(2.2V)。電阻兩端的電壓是多少?電流呢?

  • KVL:9 = V電阻 + 2.0 + 2.2,所以 V電阻 = 9 − 4.2 = 4.8V。
  • 歐姆定律:I = 4.8 ÷ 330 ≈ 0.0145 A ≈ 14.5 mA。

串聯的電壓分配:大電阻分到比較多

串聯時電流一樣,那電壓怎麼分?用歐姆定律 V = I × R:電流 I 相同,所以電阻越大的那顆,分到的電壓越多,而且是按比例分。

   5V ──[ R1 = 1kΩ ]──┬──[ R2 = 4.7kΩ ]── GND
                      │
                    這一點的電壓?

算一個例子: 5V 接 1kΩ 串聯 4.7kΩ。

  1. 總電阻 = 5.7kΩ。
  2. 電流 I = 5V ÷ 5.7kΩ ≈ 0.877 mA。
  3. R1 兩端:0.877 mA × 1kΩ ≈ 0.877V。
  4. R2 兩端:0.877 mA × 4.7kΩ ≈ 4.12V。
  5. 檢查:0.877 + 4.12 ≈ 5.0V,符合 KVL。

分壓器公式:直接算出中間那一點

上面那個計算其實可以縮成一個公式。兩顆電阻串聯接在電源和 GND 之間,中間那一點對 GND 的電壓叫做輸出電壓 V_out,這個電路叫分壓器(Voltage Divider)。它會讓你以後在讀感測器(光敏電阻、可變電阻)時天天用到。

   V_in ──[ R1 ]──┬── V_out
                  │
               [ R2 ]
                  │
                 GND

V_out = V_in × R2 ÷ (R1 + R2)

記法:V_out 是「靠 GND 那顆電阻(R2)」佔總電阻的比例。R2 越大,V_out 越接近 V_in;R2 越小,V_out 越接近 0。

算三個例子(V_in 都是 5V):

  • R1 = 10kΩ、R2 = 10kΩ:V_out = 5 × 10 ÷ (10 + 10) = 5 × 0.5 = 2.5V。兩顆一樣大,剛好對半分。
  • R1 = 10kΩ、R2 = 4.7kΩ:V_out = 5 × 4.7 ÷ 14.7 ≈ 5 × 0.32 ≈ 1.6V。
  • R1 = 10kΩ、R2 = 1kΩ:V_out = 5 × 1 ÷ 11 ≈ 0.45V。

這三個例子正好就是待會實驗 3-1 要量的,你可以先把答案記下來,等一下看電表會不會同意。

並聯的電流分配:小電阻分到比較多

並聯時電壓一樣,那電流怎麼分?還是歐姆定律 I = V ÷ R:電壓相同,所以電阻越小的那條路,流過的電流越大。

算一個例子: 5V 接 1kΩ 並聯 4.7kΩ。

  • 1kΩ 那條:I1 = 5 ÷ 1000 = 5 mA。
  • 4.7kΩ 那條:I2 = 5 ÷ 4700 ≈ 1.06 mA。
  • 總電流(KCL):5 + 1.06 = 6.06 mA。
  • 驗算:用總電阻算,5V ÷ 825Ω ≈ 6.06 mA。兩種算法答案一樣,太好了。

可變電阻:可以用手轉的分壓器

可變電阻(Variable Resistor),也叫電位器(Potentiometer),是一個有三隻腳、頂上有個旋鈕的零件。本書用的是 10kΩ 的款式。

          1 ────[ ╱╱╱╱╱╱╱╱╱╱╱╱ ]──── 3        腳 1 到腳 3:固定 10kΩ
                       ▲
                       │                       腳 2(中間腳):滑動接點,
                       2                       轉旋鈕時它在電阻條上滑動

裡面是一條 10kΩ 的電阻帶,腳 1 和腳 3 接在帶子的兩端,所以 1 到 3 之間永遠是 10kΩ。腳 2 是一個滑動接點,壓在帶子上,轉旋鈕時它會沿著帶子移動。所以:

  • 腳 1 到腳 2 的電阻 + 腳 2 到腳 3 的電阻 = 10kΩ(永遠成立)。
  • 轉到一邊時,1–2 是 0Ω、2–3 是 10kΩ;轉到正中間時,兩邊各 5kΩ;轉到另一邊時,1–2 是 10kΩ、2–3 是 0Ω。

如果把腳 1 接 5V、腳 3 接 GND,那腳 2 就是一個分壓器的 V_out,而且 R1 和 R2 可以用手轉!

算一個例子: 旋鈕轉到正中間,上半 5kΩ、下半 5kΩ,V_out = 5 × 5 ÷ (5 + 5) = 2.5V。轉到四分之一的位置(上半 7.5kΩ、下半 2.5kΩ),V_out = 5 × 2.5 ÷ 10 = 1.25V。從一端轉到另一端,V_out 可以從 0V 一路平滑變到 5V。

動手做

實驗 3-1:分壓器——量各點電壓

材料

  • Arduino UNO+USB 線(當 5V 電源)
  • 麵包板 1 塊
  • 10kΩ 電阻 2 顆、4.7kΩ 電阻 1 顆、1kΩ 電阻 1 顆
  • 10kΩ 可變電阻 1 顆
  • 公公杜邦線 4 條
  • 數位三用電表 1 台

接線(第一部分:兩顆固定電阻)

   Arduino 5V ──[ R1 = 10kΩ ]──┬──[ R2 = 10kΩ ]── Arduino GND
                               │
                             V_out(量這裡對 GND 的電壓)

   麵包板:
          a    b    c    d    e
    3    5V線  ○   R1    ○    ○      ← Arduino 5V 接 a3,R1 一腳 c3
    4     ○   ○    │    ○    ○
    5     ○   ○   R1    R2   ○      ← R1 另一腳 c5,R2 一腳 d5,這一列就是 V_out
    6     ○   ○    ○    │    ○
    7   GND線  ○    ○    R2   ○      ← R2 另一腳 d7,Arduino GND 接 a7

  • Arduino 5V → a3
  • R1(10kΩ):一腳 c3,另一腳 c5
  • R2(10kΩ):一腳 d5,另一腳 d7
  • Arduino GND → a7
  • 電表(DCV 20V 檔):紅棒 e5(V_out),黑棒 e7(GND)

步驟

  1. 先不插 USB,照上圖插好兩顆 10kΩ。
  2. 插上 USB。量三個電壓,填表:
    • V_in:紅棒 e3、黑棒 e7。
    • V_out:紅棒 e5、黑棒 e7。
    • R1 兩端:紅棒 e3、黑棒 e5。
  3. 檢查 KVL:R1 兩端的電壓 + V_out(也就是 R2 兩端的電壓)是不是等於 V_in?
  4. 拔掉 USB,把 R2 換成 4.7kΩ(R1 不動),插回 USB,再量 V_out。
  5. 拔掉 USB,把 R2 換成 1kΩ,插回 USB,量 V_out。
  6. 量電流(選做):把 R2 換回 10kΩ,拔掉 USB,把 R2 在 d7 的腳改插 d10,電表紅棒 mA 孔、旋鈕轉 2000µ 檔,紅棒 e10、黑棒 e7,插回 USB。預期 5V ÷ 20kΩ = 0.25 mA = 250 µA。量完記得紅棒插回 VΩmA。

接線(第二部分:可變電阻)

   Arduino 5V ── 可變電阻腳 1
                 可變電阻腳 2 ── V_out(量這裡)
                 可變電阻腳 3 ── Arduino GND

   麵包板:
          a    b    c    d    e
   12    5V線  ○    ○   腳1   ○      ← 可變電阻三隻腳插 d12、d13、d14
   13     ○   ○    ○   腳2   紅棒  ← 中間腳是 V_out
   14   GND線  ○    ○   腳3   黑棒

  • Arduino 5V → a12
  • 可變電阻:腳 1 → d12,腳 2(中間)→ d13,腳 3 → d14(三隻腳剛好跨三列)
  • Arduino GND → a14
  • 電表:紅棒 e13,黑棒 e14

步驟 7. 拔掉 USB,拆掉固定電阻,照第二部分接可變電阻。 8. 插上 USB,把旋鈕轉到最左邊,量 V_out;轉到大約中間,量;轉到最右邊,量。 9. 慢慢轉旋鈕,一邊看電表數字。

你應該看到

  • 10kΩ+10kΩ:V_out 約 2.5V(Arduino 的 5V 實際上可能是 4.9–5.1V,所以 V_out 可能是 2.45–2.55V)。
  • R1 兩端約 2.5V,加上 V_out 2.5V,剛好等於 V_in。
  • 10kΩ+4.7kΩ:V_out 約 1.6V。
  • 10kΩ+1kΩ:V_out 約 0.45V。
  • 可變電阻:一端 0V,另一端 5V,中間大約 2.5V,轉動時數字平滑變化,沒有跳動。

觀察與記錄

電路預測 V_out量到的 V_in量到的 V_out量到的 R1 兩端電壓R1 電壓 + V_out
10kΩ+10kΩ2.5V
10kΩ+4.7kΩ1.6V
10kΩ+1kΩ0.45V
可變電阻 轉最左0V 或 5V——
可變電阻 轉中間約 2.5V——
可變電阻 轉最右5V 或 0V——

實驗 3-2:並聯 LED 與電流分配

這個實驗要證明兩件事:並聯支路的電流加起來等於總電流(KCL),以及為什麼每顆 LED 都要有自己的電阻。

材料

  • Arduino UNO+USB 線(5V 電源)
  • 麵包板 1 塊
  • 紅光 LED 1 顆、綠光 LED 1 顆
  • 330Ω 電阻 2 顆
  • 公公杜邦線 4 條
  • 數位三用電表 1 台

接線(正確接法:各自一顆電阻)

                ┌──[ 330Ω ]──►|──┐
   Arduino 5V ──┤           紅   ├── Arduino GND
                └──[ 330Ω ]──►|──┘
                            綠

   麵包板(用電源軌比較方便):
   +軌 ═══════════════════════════  ← Arduino 5V 接+軌
   -軌 ═══════════════════════════  ← Arduino GND 接-軌

          a    b    c    d    e
    3    +線  ○   電阻A  ○    ○      ← +軌拉一條線到 a3,電阻 A 一腳 c3
    4     ○   ○    │    ○    ○
    5     ○   ○   電阻A  紅長  ○      ← 電阻 A 另一腳 c5,紅 LED 長腳 d5
    6    -線  ○    ○   紅短   ○      ← 紅 LED 短腳 d6,-軌拉一條線到 a6

    9    +線  ○   電阻B  ○    ○      ← +軌拉一條線到 a9,電阻 B 一腳 c9
   10     ○   ○    │    ○    ○
   11     ○   ○   電阻B  綠長  ○      ← 電阻 B 另一腳 c11,綠 LED 長腳 d11
   12    -線  ○    ○   綠短   ○      ← 綠 LED 短腳 d12,-軌拉一條線到 a12

  • Arduino 5V → 麵包板+軌;Arduino GND → 麵包板-軌
  • 支路 A:+軌 → a3;330Ω 電阻 c3–c5;紅 LED 長腳 d5、短腳 d6;a6 → -軌
  • 支路 B:+軌 → a9;330Ω 電阻 c9–c11;綠 LED 長腳 d11、短腳 d12;a12 → -軌

步驟

  1. 不插 USB,照上圖接好。插上 USB,兩顆 LED 都應該亮,亮度差不多。
  2. 量支路 A 的電流:拔 USB,把電阻 A 在 c5 的腳改插 c7,電表(紅棒 mA 孔、DCA 20m)紅棒 e7、黑棒 e5,插回 USB,讀數,填表。
  3. 量支路 B 的電流:拔 USB,把電阻 A 接回 c5,把電阻 B 在 c11 的腳改插 c13,電表紅棒 e13、黑棒 e11,插回 USB,讀數。
  4. 量總電流:拔 USB,把電阻 B 接回 c11。把 Arduino 5V 的那條線從+軌拔掉,改成:Arduino 5V → 杜邦線 → 電表紅棒,電表黑棒 → 杜邦線 → +軌(測棒碰杜邦線露出的金屬針就可以)。這樣所有進入麵包板的電流都會先經過電表。插回 USB,讀數。
  5. 比一比:支路 A + 支路 B 是否等於總電流?
  6. 錯誤示範(共用一顆電阻): 拔 USB,把電表拿掉、5V 接回+軌。把電阻 B 拔掉,用一條杜邦線把 c9 和 c11 接起來(綠 LED 直接接+軌,沒有自己的電阻),再用另一條杜邦線把 d5 和 d11 接起來(讓紅、綠 LED 的長腳並聯,共用電阻 A)。插回 USB,觀察兩顆 LED 的亮度。
  7. 拔 USB,恢復成各自一顆電阻的正確接法。

你應該看到

  • 正確接法:紅 LED 支路約 9 mA((5 − 2.0) ÷ 330);綠 LED 支路約 8.5 mA((5 − 2.2) ÷ 330);總電流約 17.5 mA,等於兩條支路相加。
  • 錯誤示範:紅 LED 正常亮,綠 LED 很暗或完全不亮。因為兩顆 LED 並聯時兩端電壓一樣,紅 LED 的門檻(2.0V)比綠 LED(2.2V)低,電壓被紅 LED「壓」在 2.0V 左右,綠 LED 還沒到門檻就沒電流了。就算兩顆同色 LED,也會因為個體差異讓一顆特別亮、一顆特別暗。所以:並聯 LED,每顆都要有自己的限流電阻。

觀察與記錄

量測預測量到的值
支路 A(紅)電流約 9 mA
支路 B(綠)電流約 8.5 mA
總電流約 17.5 mA
支路 A + 支路 B—
錯誤示範:紅 LED 亮度亮
錯誤示範:綠 LED 亮度很暗或不亮

實驗 3-3:串聯 LED 與電壓分配

材料

  • 9V 電池+電池扣
  • 麵包板 1 塊
  • 紅光、綠光、藍光 LED 各 1 顆
  • 330Ω 電阻 1 顆
  • 數位三用電表 1 台

接線

   9V 紅線 ──[ 330Ω ]──►|──►|──►|── 9V 黑線
                        紅  綠  藍
                     (每顆 LED 長腳朝向電阻那一側)

   麵包板:
          a    b    c    d    e
    3    紅線  ○   電阻   ○    ○
    4     ○   ○    │    ○    ○
    5     ○   ○   電阻  紅長   ○      ← 電阻另一腳 c5,紅 LED 長腳 d5
    6     ○   ○    ○   紅短  綠長    ← 紅 LED 短腳 d6,綠 LED 長腳 e6,同列所以相連
    7     ○   ○    ○   藍長  綠短    ← 綠 LED 短腳 e7,藍 LED 長腳 d7,同列所以相連
    8    黑線  ○    ○   藍短   ○      ← 藍 LED 短腳 d8,9V 黑線 a8

  • 9V 紅線 → a3;330Ω 電阻 c3–c5
  • 紅 LED:長腳 d5,短腳 d6
  • 綠 LED:長腳 e6,短腳 e7
  • 藍 LED:長腳 d7,短腳 d8
  • 9V 黑線 → a8

步驟

  1. 先只接紅、綠兩顆(藍 LED 先不插,改用一條杜邦線把第 7 列和第 8 列接起來)。扣上電池,兩顆都亮。用電表(DCV 20V)量四個電壓:電阻兩端(紅棒 e3、黑棒 e5)、紅 LED 兩端(紅棒 c5、黑棒 c6)、綠 LED 兩端(紅棒 c6、黑棒 c7)、電池電壓(紅棒 e3、黑棒 e8)。
  2. 把三個零件的電壓加起來,和電池電壓比較。
  3. 拔掉電池,拆掉那條杜邦線,插上藍 LED,扣回電池。三顆都亮,但比剛才暗。再量一次每個零件兩端的電壓(藍 LED 兩端:紅棒 c7、黑棒 c8)。
  4. 想一想:如果換成 5V 的 Arduino 來推這三顆串聯的 LED,會發生什麼事?(可以試試看,不會壞。)

你應該看到

  • 兩顆 LED 時:紅約 2.0V、綠約 2.2V、電阻約 4.8V,加起來約 9V。電流約 14.5 mA,兩顆都很亮。
  • 三顆 LED 時:紅 2.0、綠 2.2、藍 3.0,加起來 7.2V,電阻只剩 9 − 7.2 = 1.8V,電流 1.8 ÷ 330 ≈ 5.5 mA,三顆都變暗了。
  • 換成 5V:三顆 LED 的門檻加起來 7.2V 已經超過 5V,根本推不動,三顆全不亮(或極微弱)。這就是串聯 LED 的限制:電源電壓必須大於所有順向電壓的總和。
  • 另外注意:串聯時三顆 LED 的電流一模一樣(只有一條路),所以只需要一顆限流電阻。這和並聯剛好相反。

觀察與記錄

電路電阻兩端紅 LED綠 LED藍 LED全部加起來電池電壓
9V,紅+綠—
9V,紅+綠+藍

用儀器看看

三用電表:沿著迴路「走」一圈。 KVL 最好的驗證方法是把黑棒固定在 GND,紅棒依序碰迴路上的每一個點,把電壓記下來。以實驗 3-3 兩顆 LED 的電路為例,從電池正極出發:

   位置          對 GND 的電壓       和前一點的差
   電池正極        9.0V                 —
   電阻後          4.2V               掉了 4.8V(電阻吃掉的)
   紅 LED 後       2.2V               掉了 2.0V(紅 LED 吃掉的)
   綠 LED 後       0.0V               掉了 2.2V(綠 LED 吃掉的)= GND

電壓像下樓梯一樣一階一階往下掉,最後剛好回到 0V。這張表比任何公式都更能讓你「看見」KVL。

示波器初體驗(選做,若教室有示波器): 雖然示波器要到第 6 章才正式教,但分壓器是一個很適合偷看一眼的電路。接法:

  1. 示波器 CH1 探棒的鉤子勾在可變電阻的腳 2(V_out),探棒的黑色鱷魚夾一定要夾 Arduino GND。
  2. 探棒上的開關撥到 1×(如果示波器設定裡有探棒倍率,也設成 1×)。
  3. 設定:CH1 耦合(Coupling)選 DC;垂直刻度 1 V/div;水平刻度 10 ms/div;觸發(Trigger)模式選 Auto。
  4. 把 CH1 的 0V 基準線(螢幕左邊有個小箭頭)移到螢幕最下面第一格。

你會看到一條平平的水平線。慢慢轉可變電阻,這條線會跟著上上下下移動:轉到中間時線在基準線上方 2.5 格(2.5V),轉到一端時線貼著基準線(0V),轉到另一端時線在上方 5 格(5V)。

 電壓
   5V ┤ ─────────────────────   ← 轉到一端
      │
 2.5V ┤ ─────────────────────   ← 轉到中間
      │
   0V ┼───────────────────────── 時間

直流電壓在示波器上就是一條不隨時間變化的直線,它的「高度」就是電壓。第 6 章你會看到更有趣的波形。

常見錯誤與除錯

  • 分壓器 V_out 量到 0V → R1 沒接到 5V,或 R2 短路 → 用電表量 e3 對 GND 是否有 5V;檢查 R2 兩腳是否插在同一列。
  • 分壓器 V_out 量到 5V → R2 沒接到 GND(迴路沒閉合,R1 上沒電流也就沒壓降) → 檢查 GND 線和 R2 的腳是否同列。
  • V_out 跟預測差很多(例如預測 2.5V 量到 3.3V) → R1、R2 拿錯值,或其中一顆是 1kΩ 不是 10kΩ → 用 Ω 檔把兩顆都拔下來量。
  • 可變電阻轉動時 V_out 不變 → 量到的是腳 1 或腳 3,不是中間腳 → 確認紅棒在中間腳那一列;有些可變電阻的中間腳比較短,要插緊。
  • 可變電阻轉動時數字跳來跳去 → 旋鈕接點老化或髒了 → 來回轉幾十次通常會改善;換一顆。
  • 並聯 LED 其中一顆不亮 → 那顆 LED 接反了,或那條支路的電阻沒接到 → 用 KCL 的想法:量那條支路的電流是不是 0,再找斷在哪。
  • 並聯 LED 兩顆亮度差很多 → 共用了一顆電阻,或兩顆電阻值不同 → 確認每條支路有自己的 330Ω。
  • 串聯 LED 全部不亮 → 其中一顆接反了(串聯只要一顆斷,全部斷)→ 用電表量每顆 LED 兩端:接反的那顆會吃掉幾乎全部的電壓(例如 8 點多 V),其他顆接近 0V。
  • 串聯 LED 全部很暗 → 電源電壓減去所有順向電壓後剩太少 → 減少 LED 顆數,或用更高電壓。
  • 量總電流時 LED 都不亮 → 電表沒有串好,迴路被切斷了 → 確認 5V → 紅棒、黑棒 → +軌這兩段都接上。

想一想

  1. 220Ω 和 1kΩ 串聯,總電阻多少?並聯呢?
參考答案

串聯:220 + 1000 = 1220Ω。並聯:(220 × 1000) ÷ (220 + 1000) = 220,000 ÷ 1220 ≈ 180Ω。注意並聯結果比 220Ω 還小。

  1. 兩顆 330Ω 並聯,總電阻多少?用公式算,再用「一樣大的兩顆並聯是一半」的規則檢查。
參考答案

公式:(330 × 330) ÷ (330 + 330) = 108,900 ÷ 660 = 165Ω。規則:330 ÷ 2 = 165Ω。一致。

  1. 9V 電池接分壓器,R1 = 4.7kΩ(靠 9V 那邊)、R2 = 10kΩ(靠 GND 那邊)。V_out 多少?流過電阻的電流多少?
參考答案

V_out = 9 × 10 ÷ (4.7 + 10) = 9 × 10 ÷ 14.7 ≈ 6.12V。電流 = 9V ÷ 14.7kΩ ≈ 0.61 mA。驗算:R1 兩端 = 0.61 mA × 4.7kΩ ≈ 2.88V,9 − 2.88 ≈ 6.12V,符合。

  1. 小傑說:「兩顆 LED 並聯共用一顆電阻可以省一顆零件,反正電流會平均分給兩顆。」請用「順向電壓」的觀念說明他哪裡想錯了。
參考答案

並聯的兩顆 LED 兩端電壓一定相同,但 LED 不是電阻,它的電流由「電壓有沒有超過門檻」決定,而且超過門檻後電流對電壓非常敏感。兩顆 LED 的門檻一定不完全一樣(不同顏色差 0.2V 以上,同顏色也有個體差異),門檻比較低的那顆會先導通,把共同的電壓「壓」在它的門檻附近,另一顆就分不到足夠電壓,變得很暗甚至不亮。電流不會平均分配。各自一顆電阻之後,每條支路的電流由自己的電阻決定,就不會互相搶了。

  1. 第 13 章會用光敏電阻(LDR)做自動夜燈。LDR 的電阻在亮處約 1kΩ、暗處約 100kΩ。如果把它當 R1(接 5V)、10kΩ 當 R2(接 GND),亮處和暗處的 V_out 各是多少?V_out 是「變亮時升高」還是「變暗時升高」?
參考答案

亮處:V_out = 5 × 10 ÷ (1 + 10) ≈ 4.55V。暗處:V_out = 5 × 10 ÷ (100 + 10) ≈ 0.45V。所以變亮時 V_out 升高、變暗時下降。如果想要「變暗時升高」,把 LDR 和 10kΩ 對調位置(LDR 當 R2)就可以。Arduino 讀到這個電壓,就知道現在亮不亮。

  1. (開放挑戰)請用 9V 電池、10kΩ 可變電阻、330Ω 電阻和一顆紅光 LED,設計一個「旋鈕調光燈」:轉旋鈕可以讓 LED 從最亮慢慢變到幾乎不亮。畫出 ASCII 電路圖,說明可變電阻的哪兩隻腳要用,並解釋為什麼 330Ω 不能省掉。
參考答案

把可變電阻當成「可以調的電阻」來用,只用腳 1 和腳 2(或腳 2 和腳 3),和 330Ω、LED 全部串聯:

   9V 紅線 ── 可變電阻腳1 ╱╱╱ 腳2 ──[ 330Ω ]──►|── 9V 黑線
                 (腳 3 不接)                  紅

轉到 1–2 是 0Ω 時,總電阻只有 330Ω,電流 = (9 − 2) ÷ 330 ≈ 21 mA,最亮。轉到 1–2 是 10kΩ 時,總電阻 10,330Ω,電流 ≈ 7 ÷ 10,330 ≈ 0.68 mA,幾乎不亮。中間可以平滑調整。330Ω 不能省,因為旋鈕轉到 0Ω 那一端時,如果沒有 330Ω,LED 就直接接 9V,電流會大到把 LED 燒掉,330Ω 是「最後一道保險」。

本章小結

  • 串聯:一條路、電流相同、總電阻相加(R1 + R2)、電壓按電阻比例分配,大電阻分得多。
  • 並聯:多條路、電壓相同、總電阻用「積除以和」(R1 × R2 ÷ (R1 + R2)),結果比最小的那顆還小;電流按電阻反比分配,小電阻流得多。
  • 兩顆一樣大的電阻並聯,總電阻剛好一半。
  • 克希荷夫電流定律(KCL):流進分岔點的電流總和等於流出的總和。
  • 克希荷夫電壓定律(KVL):繞迴路一圈,電源電壓等於所有零件壓降的總和。
  • 分壓器公式:V_out = V_in × R2 ÷ (R1 + R2),R2 是靠 GND 的那顆。10kΩ+10kΩ 接 5V 得到 2.5V。
  • 可變電阻腳 1、3 接電源兩端,中間腳 2 就是可以手轉的 V_out,從 0V 到 V_in 平滑變化。
  • 並聯 LED 每顆要有自己的限流電阻;串聯 LED 只需一顆電阻,但電源電壓必須大於所有順向電壓的總和。

名詞表

中文英文一句話解釋
串聯Series零件頭尾相接排成一條路,電流相同、電阻相加。
並聯Parallel零件兩端分別接在一起形成多條路,電壓相同、總電阻變小。
總電阻Total / Equivalent Resistance把多顆電阻合起來看成一顆時的電阻值。
克希荷夫電流定律Kirchhoff’s Current Law(KCL)流進任何分岔點的電流總和等於流出的總和。
克希荷夫電壓定律Kirchhoff’s Voltage Law(KVL)沿閉合迴路一圈,電源電壓等於各零件壓降總和。
分岔點Node / Junction電路中三條以上導線相接的點。
壓降Voltage Drop電流流過零件時,零件兩端「吃掉」的電壓。
分壓器Voltage Divider兩顆串聯電阻把輸入電壓按比例分出一個較小電壓的電路。
輸入電壓Input Voltage(V_in)分壓器接的電源電壓。
輸出電壓Output Voltage(V_out)分壓器中間點對 GND 的電壓。
可變電阻Variable Resistor可以用旋鈕改變阻值的電阻,有三隻腳。
電位器Potentiometer可變電阻的另一個名字,強調它當分壓器用。
滑動接點Wiper可變電阻的中間腳,轉動時在電阻帶上滑動。
支路Branch並聯電路中的其中一條路。
耦合Coupling示波器設定,DC 表示連直流成分一起顯示。

第 4 章 電功率與電池

本章目標

  • 學完你會用 P = V × I 算出任何元件「吃」掉多少功率,知道瓦特是什麼。
  • 學完你會判斷一顆 1/4W 電阻會不會過熱,並親手摸到超載電阻的溫度。
  • 學完你會看懂電池上的 mAh,估算一顆電池可以讓 LED 亮多久。
  • 學完你會量出電池的內阻,解釋為什麼舊電池「量起來有電壓,卻推不動馬達」。
  • 學完你會知道 USB、Arduino 的 5V 與 3.3V 腳位能給多少電流,以及電池串聯和並聯的差別。

開場:為什麼充電器會熱、電池會「虛弱」?

小宇把手機接上充電器,一個小時後摸到充電器溫溫的,心裡想:「它又沒有在動,為什麼會熱?」晚上他拿出遙控車,放進去年的舊電池,用三用電表一量:8.5V,看起來還有電啊!可是一按前進,馬達只「嗯」了一聲就不動了。換上新電池,一樣是 9V 電池,車子卻衝了出去。

這兩件事其實是同一個主題:電在流動的時候,每一秒鐘都在把能量交出去。交出去的能量有的變成光(LED)、有的變成轉動(馬達)、有的變成熱(充電器、電阻)。而電池交出能量的「速度」是有上限的,舊電池的上限變得很低,所以電壓量起來還在,卻給不出大電流。這一章我們就來弄清楚「功率」與「電池」這兩件事。

核心概念

功率:電每秒做了多少事

想像一座水車。水從高處落下(電壓)、水量很大(電流),水車就轉得很有力。水車每一秒拿到的能量,就是「功率」。

功率(Power) 的符號是 P,單位是 瓦特(Watt,W)。它告訴你一個元件每秒消耗(或產生)多少能量。公式很簡單:

P = V × I
功率(W)= 電壓(V)× 電流(A)

算一個例子:一顆紅色 LED 兩端電壓 2V,流過 20mA(= 0.02A)。

P = 2V × 0.02A = 0.04W = 40mW

40 毫瓦(mW)非常小,所以 LED 摸起來不會熱。

因為歐姆定律 V = I × R(第 2 章),把 V 或 I 代進去,可以得到另外兩個常用的寫法:

P = V × I
P = V² ÷ R      (只知道電壓和電阻時用這個)
P = I² × R      (只知道電流和電阻時用這個)

例子:一顆 220Ω 電阻直接接在 9V 電池上。

P = V² ÷ R = (9 × 9) ÷ 220 = 81 ÷ 220 ≈ 0.37W

0.37W 看起來很小,但下一節你會發現:對一顆小電阻來說,這已經太多了。

順帶一提,家裡電費單上的「1 度電」就是 1000W 的東西用 1 小時所消耗的能量。能量 = 功率 × 時間,功率越大、用越久,吃掉的能量越多。

電阻會發熱:1/4W 是什麼意思

電阻吃進去的功率沒有變成光或轉動,全部變成熱。買電阻的時候你會看到「1/4W」這種字,這是額定功率(Power Rating),意思是「這顆電阻最多能安全地把 0.25W 的熱散掉」。超過了,它會越來越燙、變色、發臭,嚴重會燒斷。

我們算算 9V 電池接不同電阻時的功率:

電阻P = 81 ÷ R和 0.25W 比預測
10kΩ81 ÷ 10000 = 0.0081W很小完全不會熱
1kΩ81 ÷ 1000 = 0.081W約 1/3微溫
330Ω81 ÷ 330 ≈ 0.245W剛好接近明顯溫熱
220Ω81 ÷ 220 ≈ 0.37W超過 1.5 倍燙!

這張表在「動手做」會讓你親手驗證。

電池的容量:mAh 是什麼

電池像一座水塔,水塔的大小就是容量(Capacity),單位是 毫安培小時(mAh)。「2000mAh」的意思是:可以用 2000mA 的電流放 1 小時,或是 20mA 放 100 小時。

使用時間(小時)= 容量(mAh)÷ 電流(mA)

例子:一顆 3 號(AA)鹼性電池大約 2000mAh。點亮一顆 20mA 的 LED:

2000 ÷ 20 = 100 小時

9V 鹼性電池比較小,大約只有 500mAh:

500 ÷ 20 = 25 小時

真實情況會打折,因為電池用到後面電壓會慢慢降低,LED 會越來越暗,而不是突然熄滅。大概抓計算值的 7 成比較實際:25 × 0.7 ≈ 17 小時。

電池的內阻:為什麼舊電池推不動馬達

回到開場的問題。你可以把一顆真實電池想成「一個完美的電池」再串聯「一個很小的電阻」,這個電阻叫做內阻(Internal Resistance),符號 r。

 ┌─────── 真實電池 ───────┐
 │                        │
 │  ┌──┤├── [ r ]──┐      │
 │  │  完美        內阻   │
 │  │  9V                 │
 └──┼────────────────┼────┘
    −                +

沒有接負載(空載)時,電流是 0,內阻上沒有壓降,你量到的是完美電池的電壓。一旦接上負載有電流流過,內阻就會「吃掉」一部分電壓:

V負載 = V空載 − I × r

所以反過來,只要量兩個電壓和電流,就能算出內阻:

r = (V空載 − V負載) ÷ I

例子:一顆新的 9V 電池,空載量到 9.40V。接上 200Ω 負載後量到 9.15V。

I = 9.15 ÷ 200 ≈ 0.0458A(45.8mA)
r = (9.40 − 9.15) ÷ 0.0458 = 0.25 ÷ 0.0458 ≈ 5.5Ω

新電池內阻只有幾歐姆。用久的電池內阻可能變成 30Ω、50Ω 甚至更高。馬達啟動要吃好幾百 mA,假設 300mA、內阻 30Ω:壓降 = 0.3 × 30 = 9V,整顆電池的電壓都被內阻吃光了,馬達當然轉不動。這就是「量起來有電壓,用起來沒電」的原因。

USB 與 Arduino 能給多少電

本書所有實驗都用 12V 以下的直流電,常見的電源有三種:

電源電壓大約能給的電流
電腦的 USB 孔5V500mA(USB 2.0 規格)
手機充電器5V1A~2A 以上(看充電器標示)
9V 電池9V短時間幾百 mA,但內阻大、容量小
3 號電池盒(4 顆)6V1A 以上,容量大

Arduino UNO 本身也可以當電源,但要注意上限:

  • 5V 腳:由 USB 供電時,整塊板加上你接的東西總共不能超過約 500mA(板上有保險絲)。
  • 3.3V 腳:最多 50mA,只能接小東西(例如一些感測器)。
  • 每一支 I/O 腳(D0~D13、A0~A5):建議 20mA,絕對不能超過 40mA。所有 I/O 腳加起來不能超過 200mA。
  • ESP32 的 I/O 腳更弱,每腳建議 12mA,而且只能 3.3V。

所以小直流馬達(啟動時幾百 mA)絕對不能直接接在 I/O 腳上。第 9 章我們會用電晶體來解決這個問題。

電池串聯與並聯

串聯(Series):正極接下一顆的負極,電壓相加,容量不變。

 ┤├──┤├──┤├──┤├      4 顆 1.5V 串聯 = 6V,容量仍是 2000mAh
 1.5V 1.5V 1.5V 1.5V

你手上的 3 號電池盒就是這樣:4 顆 AA 串起來得到 6V。9V 電池拆開來看,裡面其實是 6 顆 1.5V 的小電池串聯(6 × 1.5 = 9V)。

並聯(Parallel):正極接正極、負極接負極,電壓不變,容量相加。

 ┌──┤├──┐
 │ 1.5V  │     2 顆 1.5V 並聯 = 1.5V,容量 2000 + 2000 = 4000mAh
 ├──┤├──┤
 │ 1.5V  │

並聯有一個重要規則:只能並聯同型號、同樣新舊的電池。如果一顆滿電、一顆快沒電,滿的那顆會拚命往沒電的那顆灌電流,兩顆都會發熱。絕對不可以把 9V 電池和 AA 電池並聯,那是短路。

動手做

安全提醒:本章會讓電阻發熱,請按照步驟的時間限制操作,用指背輕碰,不要握住。只要看到電阻變色或聞到焦味,立刻拔掉電池。

實驗 4-1:量 LED 與電阻各吃了多少功率

材料

  • 3 號電池盒(4 顆 AA,約 6V)
  • 220Ω 電阻 1 顆
  • 紅色 LED 1 顆
  • 麵包板、杜邦線
  • 數位三用電表

接線

 電池盒 +(6V)──[ 220Ω ]──►|── 電池盒 −(GND)
                          LED

  • 電池盒紅線 → 220Ω 一端
  • 220Ω 另一端 → LED 長腳(+)
  • LED 短腳(−)→ 電池盒黑線(GND)

步驟

  1. 先不要接電路,三用電表轉到直流電壓(DCV,20V 檔),量電池盒的電壓,記下 V電池。
  2. 接好電路,LED 應該亮起來。
  3. 電表紅棒放在 LED 長腳、黑棒放在 LED 短腳,量 LED 兩端電壓 V_LED。
  4. 電表改量 220Ω 兩端電壓 V_R。檢查:V_LED + V_R 應該幾乎等於 V電池。
  5. 量電流:把電表轉到直流電流(mA 檔,紅棒插到 mA 孔),拔掉 LED 短腳到 GND 的那條線,改成「LED 短腳 → 電表紅棒,電表黑棒 → GND」,讓電流流過電表。記下 I。
  6. 用 P = V × I 算出三個功率:P_LED、P_R、P總(= V電池 × I)。

你應該看到

V電池 約 6.0V、V_LED 約 1.9V、V_R 約 4.1V、I 約 18~19mA。以 18.6mA 計算:

P_LED = 1.9V × 0.0186A ≈ 0.035W = 35mW
P_R   = 4.1V × 0.0186A ≈ 0.076W = 76mW
P總   = 6.0V × 0.0186A ≈ 0.112W = 112mW

注意 35 + 76 = 111mW,和 P總 幾乎一樣。電池交出來的功率,全部被 LED 和電阻分掉了,一點都沒有消失。另外,這個電路裡有 2/3 的功率浪費在電阻上變成熱,這就是為什麼限流電阻「不划算但必要」。

觀察與記錄

項目量測電壓(V)電流(A)功率 P = V × I(W)
電池
LED(同上)
220Ω 電阻(同上)
LED + 電阻的功率加總

實驗 4-2:摸摸看,電阻超載有多燙

材料

  • 9V 電池與電池扣
  • 10kΩ、1kΩ、330Ω、220Ω 電阻各 1 顆(都是 1/4W)
  • 麵包板

接線

 9V 電池 + ──[ R ]── 9V 電池 −

  • 電池扣紅線 → 電阻一端
  • 電阻另一端 → 電池扣黑線
  • 一次只接一顆電阻。

步驟

  1. 動手前先算:用 P = V² ÷ R 算出四顆電阻各會吃多少功率,填進表格的「計算功率」欄。
  2. 插上 10kΩ,等 20 秒,用指背輕碰電阻本體,記下感覺。拔掉。
  3. 換 1kΩ,一樣等 20 秒再碰。拔掉。
  4. 換 330Ω,等 20 秒再碰。拔掉。
  5. 換 220Ω,只等 15 秒,用指背很快碰一下就離開。立刻拔掉電池。這顆電阻超過額定功率 1.5 倍,會很燙。
  6. 等 220Ω 冷卻後看看它的顏色有沒有變深。

你應該看到

10kΩ 完全沒感覺;1kΩ 微溫;330Ω 明顯溫熱(它剛好吃 0.245W,貼近 0.25W 的上限);220Ω 燙到不能久碰。超載時間久了,電阻表面會變成深褐色,電阻值也可能永久改變。

觀察與記錄

電阻計算功率 P = 81 ÷ R(W)超過 0.25W?摸起來(無感/微溫/溫熱/燙)
10kΩ
1kΩ
330Ω
220Ω

實驗 4-3:量電池的內阻

材料

  • 9V 電池(最好準備一顆新的、一顆用過很久的)
  • 100Ω 電阻 2 顆(串聯成 200Ω)
  • 麵包板、杜邦線
  • 數位三用電表

為什麼用兩顆 100Ω 串聯而不是一顆 200Ω?因為 9V 接 200Ω 總共會吃 81 ÷ 200 ≈ 0.4W,一顆 1/4W 電阻撐不住。串聯後每顆分到 4.5V,各自只吃 4.5² ÷ 100 ≈ 0.2W,剛好安全。這就是上一節學到的東西派上用場。

接線

 9V 電池 + ──[ 100Ω ]──[ 100Ω ]── 9V 電池 −
            ▲                     ▲
            └─── 三用電表(DCV)───┘

  • 電池扣紅線 → 第一顆 100Ω
  • 第一顆 100Ω → 第二顆 100Ω
  • 第二顆 100Ω → 電池扣黑線
  • 電表紅棒夾在電池扣紅線,黑棒夾在電池扣黑線(量的是電池端電壓)。

步驟

  1. 先把電阻拔掉,只接電表,量空載電壓 V空載。
  2. 插上兩顆電阻,5 秒內讀電表,記下 V負載。
  3. 拔掉電阻(不要讓電池一直放電)。
  4. 算電流 I = V負載 ÷ 200。
  5. 算內阻 r = (V空載 − V負載) ÷ I。
  6. 換舊電池再做一次。

你應該看到

新電池:空載約 9.4V,負載約 9.15V,掉 0.25V 左右。

I = 9.15 ÷ 200 ≈ 0.0458A
r = 0.25 ÷ 0.0458 ≈ 5.5Ω

舊電池:空載可能還有 8.6V,但接上負載後掉到 7.4V 甚至更低。

I = 7.4 ÷ 200 = 0.037A
r = (8.6 − 7.4) ÷ 0.037 = 1.2 ÷ 0.037 ≈ 32Ω

內阻差了好幾倍。如果你有小直流馬達,可以再試試看:把馬達直接接在舊電池上、同時量電壓,你會看到電壓一瞬間掉到剩 3、4V,馬達可能動不了;新電池掉得少很多。

觀察與記錄

電池V空載(V)V負載(V)I = V負載 ÷ 200(A)r = (V空載 − V負載) ÷ I(Ω)
新 9V
舊 9V
其他(例如電池盒 6V)

實驗 4-4:電池串起來,電壓加起來

材料

  • 3 號電池盒(4 顆 AA)
  • 單顆 AA 電池 1 顆(從電池盒拿一顆出來也可以)
  • 9V 電池
  • 數位三用電表

接線

這個實驗不用麵包板,直接用電表的兩支探棒碰電池兩端。

 單顆 AA:  紅棒 → 凸起那端(+)   黑棒 → 平的那端(−)
 電池盒:   紅棒 → 紅線           黑棒 → 黑線

步驟

  1. 電表轉 DCV 20V 檔,量單顆 AA 電池,記下來。
  2. 量 4 顆裝好的電池盒,記下來。算算看是不是「單顆 × 4」。
  3. 量 9V 電池。想一想:它裡面要幾顆 1.5V 的小電池串聯才會得到這個數字?
  4. 把電池盒其中一顆電池反過來裝(正負顛倒),再量一次。

你應該看到

單顆約 1.5~1.6V,電池盒約 6.0~6.4V,剛好 4 倍。9V 電池約 9.0~9.5V,是 6 顆串聯。反裝一顆之後,那顆電池的電壓變成「減」的:1.5 × 3 − 1.5 = 3V。這就是為什麼遙控器電池裝反會不能用。

觀察與記錄

量什麼量到電壓(V)預測(V)
單顆 AA1.5
4 顆串聯
9V 電池
反裝一顆後

用儀器看看

本章最重要的儀器是三用電表,重點是量電流的正確方法:

  1. 紅棒要插在 mA 孔(不是 V/Ω 孔),轉到直流電流檔(DCA,200mA 檔)。
  2. 電表要串聯在電路裡:把原本的導線斷開,電流從電表的紅棒進去、黑棒出來。
  3. 絕對不可以用電流檔去「並聯」量電池兩端,那等於把電池短路,電表裡的保險絲會燒掉。
  4. 量完電流,記得把紅棒插回 V/Ω 孔,不然下次量電壓時又會短路。

示波器也能看電池,而且能看到三用電表看不到的「瞬間變化」。如果你已經讀過第 6 章,可以試試看:

  • 探棒夾在 9V 電池兩端(接地夾夾負極)。
  • 設定:CH1 直流耦合(DC)、2V/div、水平 200ms/div,觸發模式 Auto。
  • 畫面上會是一條平平的線,在 0V 上方約 4.5 格的位置(9V)。
  • 這時把小直流馬達接到電池上,你會看到線瞬間往下掉,然後慢慢回升一點:
電壓
 9V ┤──────────┐
    │          └──┐  ← 馬達接上去,內阻吃掉電壓
 6V ┤             └──────────
    │
 0V ┼─────────────────────────── 時間
              ▲
           接上馬達

舊電池的掉落會深得多。

常見錯誤與除錯

  • 量電流時電表顯示 0,電路也不動 → 電表轉到電流檔但紅棒還插在 V/Ω 孔,或保險絲已經燒斷 → 檢查紅棒位置;轉到電阻檔量電表自己的兩根棒子,如果是無限大,保險絲壞了,請老師更換。
  • 實驗 4-1 的 V_LED + V_R 和 V電池 差很多 → 杜邦線或麵包板接觸不良 → 把線重新插緊,用電表量每一段導線兩端是否為 0V。
  • 220Ω 電阻一插上就冒煙 → 可能拿到的是更小功率(1/8W)的電阻,或電池是 2 顆 9V 串聯 → 立刻拔掉,確認電壓與電阻額定功率。
  • 內阻算出來是負的 → 空載與負載電壓記反了,或負載電壓在接上很久之後才量(電池回升) → 重做一次,接上負載 5 秒內讀值。
  • 內阻算出來超大(幾百 Ω) → 可能用了快沒電的電池,或用了舊的碳鋅電池;也可能電池扣接觸不良 → 換電池、重新壓緊電池扣。
  • 電池盒量到的電壓只有 3V 或 4.5V → 有一顆裝反了或接觸點生鏽 → 檢查每顆方向,用橡皮擦擦彈簧。

想一想

  1. 一台 5V、100mA 的小風扇,功率多少?
參考答案

P = V × I = 5V × 0.1A = 0.5W。

  1. 你想把一顆 1/4W 電阻直接接在 5V 上,最小可以用幾 Ω 的電阻而不超載?
參考答案

P = V² ÷ R 移項得 R = V² ÷ P = 25 ÷ 0.25 = 100Ω。所以至少要 100Ω;實際上留一點餘裕,用 220Ω 以上更安全。

  1. 一顆 2000mAh 的電池接一個吃 50mA 的電路,理論上可以用多久?考慮實際打 7 折呢?
參考答案

2000 ÷ 50 = 40 小時;打 7 折約 28 小時。

  1. 一個電池盒空載量到 6.2V,接上 100Ω 電阻後量到 5.8V。算出電流與內阻。
參考答案

I = 5.8 ÷ 100 = 0.058A。r = (6.2 − 5.8) ÷ 0.058 = 0.4 ÷ 0.058 ≈ 6.9Ω。

  1. (開放挑戰)電動車的電池包通常是幾百顆小電池串聯再並聯。想想看:為什麼要串聯這麼多顆?為什麼又要並聯?如果只串聯不並聯,會有什麼問題?
參考答案

串聯是為了得到高電壓(幾百伏特),同樣功率下電壓高、電流就小,電線可以比較細、發熱比較少。並聯是為了增加容量(mAh)和能給出的最大電流。只串聯不並聯,容量會跟單顆一樣小,跑不遠,而且大電流會讓每顆電池的內阻壓降很大、發熱嚴重。

  1. (開放挑戰)設計一支手電筒:用 3 顆 AA 電池(4.5V)點亮一顆白光 LED(順向電壓 3.2V,電流 20mA)。需要多少 Ω 的限流電阻?電阻吃多少功率?電池大約能用多久?
參考答案

電阻上的電壓 = 4.5 − 3.2 = 1.3V,R = 1.3 ÷ 0.02 = 65Ω,用 68Ω(或手邊有的 100Ω,會稍暗一點)。電阻功率 = 1.3 × 0.02 = 0.026W,1/4W 綽綽有餘。使用時間 = 2000 ÷ 20 = 100 小時,實際約 70 小時。

本章小結

  • 功率 P = V × I,單位瓦特(W),代表每秒消耗的能量;也可以寫成 P = V² ÷ R 或 P = I² × R。
  • 電阻吃進去的功率全部變成熱。1/4W 電阻最多只能承受 0.25W,超過會燙、變色、燒壞。
  • 電池容量用 mAh 表示,使用時間 = 容量 ÷ 電流,實際大約打 7 折。
  • 電池有內阻 r,接負載時電壓會掉:V負載 = V空載 − I × r。舊電池內阻大,所以「有電壓卻沒力」。
  • 量內阻:r = (V空載 − V負載) ÷ I。
  • USB 孔約給 500mA;Arduino 5V 腳總共約 500mA、3.3V 腳只有 50mA、每支 I/O 腳建議 20mA。馬達不能直接接 I/O 腳。
  • 電池串聯電壓相加、容量不變;並聯電壓不變、容量相加,而且只能並聯相同狀態的電池。
  • 量電流要串聯、紅棒插 mA 孔;量完記得插回去。

名詞表

中文英文一句話解釋
功率Power每秒消耗或產生的能量,P = V × I
瓦特Watt(W)功率的單位,1W = 1V × 1A
毫瓦Milliwatt(mW)千分之一瓦特
額定功率Power Rating元件能安全承受的最大功率,例如 1/4W
容量Capacity電池能放出的總電量,單位 mAh
毫安培小時mAh1mA 的電流放 1 小時的電量
內阻Internal Resistance電池內部像串聯著的小電阻,接負載時會吃掉電壓
空載No Load沒有接任何負載,電流為 0 的狀態
負載Load接在電源上、會消耗電流的東西
串聯Series頭尾相接,電壓相加
並聯Parallel正接正、負接負,容量相加
保險絲Fuse電流太大時會燒斷來保護電路的元件

第 5 章 電容

本章目標

  • 學完你會用「水桶」的比喻說明電容在做什麼,看懂 µF、nF、pF 的換算。
  • 學完你會分辨電解電容的正負極,知道為什麼接反很危險。
  • 學完你會算 RC 時間常數 τ = R × C,並且知道「5 個 τ 就充飽(或放光)」。
  • 學完你會做出一個放開按鈕後 LED 慢慢變暗的「延遲關燈」電路。
  • 學完你會用三用電表看電容電壓慢慢下降,並用示波器第一次看到充電與放電的曲線。

開場:關掉電源,燈怎麼還亮著?

小宇組了一塊 Arduino 的電路,拔掉 USB 線的瞬間,他注意到板子上的電源指示燈不是「啪」一聲熄滅,而是像螢火蟲一樣慢慢暗下去,大概半秒鐘才完全黑掉。他把 USB 插回去再拔一次,又看到一樣的事。

「電都拔掉了,燈還有電可以用?」他拿放大鏡看板子,發現 USB 孔旁邊有幾顆圓柱形的小元件,上面印著「100µF」。那就是電容。電容像一個小水桶,電源接著的時候它悄悄把水裝滿;電源一拔掉,它就把存的水倒出來,所以燈還能多亮一下下。

這一章我們就來玩這個小水桶:它能裝多少、裝滿要多久、倒光要多久,以及怎麼用三用電表和示波器「看」到它在倒水。

核心概念

電容像水桶

電阻是「讓電流不好走的窄水管」,而**電容(Capacitor)**是「接在水管旁邊的水桶」。它的構造很簡單:兩片金屬板,中間夾一層不導電的東西。電壓加上去,電荷就往兩片金屬板上堆,一片堆正電、一片堆負電。電壓拿掉,電荷還留在上面,這就是「存電」。

 電路符號:

   ──┤├──    一般電容(陶瓷電容,沒有正負)

   ──┤|──    電解電容(有正負,彎的那邊是 +,直的那邊是 −)
      +

水桶越大,同樣的水位能裝越多水。電容也一樣:電容值(Capacitance)越大,同樣的電壓能存越多電荷。電容值的符號是 C,單位是法拉(Farad,F)。

1 法拉非常非常大(1V 就能存 1 庫侖的電荷),所以日常用的電容都是「百萬分之一法拉」等級。換算要記熟:

1 F  = 1,000,000 µF(微法拉)
1 µF = 1,000 nF(奈法拉)
1 nF = 1,000 pF(皮法拉)

例子:100µF = 0.0001F;100nF = 0.1µF;1000µF = 0.001F。

怎麼看電容上的數字?

  • 電解電容(圓柱形、藍色或黑色外殼)會直接印「100µF 25V」。25V 是耐壓(Rated Voltage),代表最多只能加 25V,超過會壞。本書最高只用 12V,所以 16V 或 25V 的電容都安全。
  • 陶瓷電容(小小的扁圓片,淡黃或藍色)印三個數字,例如「104」。讀法是:前兩個數字「10」後面加上第三個數字那麼多個 0,單位是 pF。「104」= 10 後面加 4 個 0 = 100000pF = 100nF。

極性:電解電容接反會爆

陶瓷電容沒有方向,怎麼接都可以。電解電容有正負極:長腳是正(+),短腳是負(−),而且外殼上有一條白色或灰色的帶子,帶子那邊是負極。

接反會發生什麼事?電解電容裡面是一層非常薄的化學膜,接反的時候這層膜會被破壞,電容變成短路,裡面的液體快速發熱、變成氣體,外殼撐不住就會「啪」一聲噴開。所以本書的安全紅線之一就是:電解電容的正極一定接比較高電壓的那邊。不確定時先用三用電表量一下哪邊電壓高。

充電與放電

把電容接上電池,電荷會流進去,電容兩端的電壓從 0 慢慢升到電池電壓,這叫充電(Charging)。充電不是瞬間完成的,因為電路裡一定有電阻(就算沒有刻意放,電線和電池內阻也算),電阻限制了電流,水桶只能慢慢裝。

把充滿的電容從電池拔下來,接到一個電阻上,電荷會從電阻流掉,電壓從滿慢慢降到 0,這叫放電(Discharging)。

重點是「慢慢」的樣子:一開始快,越來越慢。放電時,剛開始電壓高、電流大,水嘩啦嘩啦流;電壓越低、電流越小,最後只剩涓涓細流,所以曲線是圓弧形的,不是直線。

電壓                                 電壓
 9V ┤        ╭───────────            9V ┤╮
    │      ╱                            │ ╲
    │    ╱                              │  ╲
    │   ╱                               │   ╲
    │  ╱                                │    ╲
    │ ╱                                 │     ╰╮
 0V ┼╯─────────────────── 時間        0V ┼──────╰──────────── 時間
         充電                                  放電

RC 時間常數:τ = R × C

充電要多久?放電要多久?這取決於電阻 R 和電容 C 的乘積,叫做時間常數(Time Constant),符號是希臘字母 τ(唸作「tau」)。

τ = R × C
時間常數(秒)= 電阻(Ω)× 電容(F)

例子一:10kΩ 和 100µF。

τ = 10000Ω × 0.0001F = 1 秒

例子二:10kΩ 和 100nF。

τ = 10000Ω × 0.0000001F = 0.001 秒 = 1 毫秒(ms)

例子三:1kΩ 和 1000µF。

τ = 1000Ω × 0.001F = 1 秒

小技巧:kΩ 乘上 µF,答案直接就是 ms。10kΩ × 100µF = 1000ms = 1 秒;10kΩ × 0.1µF = 1ms。

τ 是什麼意思?每過一個 τ,放電時的電壓會變成原來的 37%;充電時則是「剩下的差距」縮小到 37%。用表格看最清楚(以 9V 為例):

經過時間放電:剩下多少放電電壓(從 9V 開始)充電:充到多少充電電壓(充向 9V)
0100%9.0V0%0V
1τ37%3.3V63%5.7V
2τ14%1.2V86%7.8V
3τ5%0.45V95%8.6V
4τ2%0.17V98%8.8V
5τ0.7%0.06V99.3%8.9V

所以我們只要記一句話:5 個 τ 就算充飽(或放光)了。10kΩ 配 100µF,τ = 1 秒,5 秒就充飽。想讓它慢 10 倍?把電阻換成 100kΩ,或把電容換成 1000µF。

電容在電路裡做什麼

  1. 暫時供電:開場故事裡的 Arduino 電源燈,就是電容在電源拔掉後撐了一下。
  2. 延遲:放開按鈕後 LED 慢慢熄滅,或者讓某件事「等一下」再發生。這章的實驗 5-1 就是。
  3. 濾波/穩壓:把忽大忽小的電壓弄平順(第 10 章會用示波器看)。
  4. 擋直流、讓變化通過:電容充飽後直流電就流不過去了,但變化中的訊號可以「透過」它(第 6 章 AC 耦合會用到這個觀念)。

動手做

安全提醒:電解電容的長腳(+)一定要接電路裡電壓高的那邊,白色帶子那邊接 GND。本章最高只用 9V,電容耐壓 16V 以上都安全。接線前先把電池拔掉。

實驗 5-1:延遲關燈電路——用 LED 看電容放電

材料

  • 9V 電池與電池扣
  • 按鈕開關 1 個
  • 220Ω 電阻 1 顆(充電用)
  • 1kΩ、4.7kΩ、10kΩ 電阻各 1 顆(放電用,輪流換)
  • 1000µF 電解電容 1 顆(耐壓 16V 以上)
  • 紅色 LED 1 顆
  • 麵包板、杜邦線

接線

 9V + ──[ 按鈕 ]──[ 220Ω ]──┬──────────┐
                            │+         │
                          ══╧══     [ 1kΩ ]
                          1000µF       │
                            │−        ►|  LED(長腳在上)
                            │          │
 9V − ──────────────────────┴──────────┴── GND

  • 電池扣紅線 → 按鈕一腳
  • 按鈕另一腳 → 220Ω → 麵包板上的「節點 A」
  • 1000µF 長腳(+)→ 節點 A;1000µF 短腳(−,白帶那邊)→ GND
  • 1kΩ 一端 → 節點 A;1kΩ 另一端 → LED 長腳
  • LED 短腳 → GND
  • 電池扣黑線 → GND

步驟

  1. 檢查 1000µF 的方向:長腳在節點 A(高電壓),白帶在 GND。
  2. 按住按鈕約 2 秒,LED 亮起。
  3. 放開按鈕,盯著 LED,用手機碼表量「從放開到完全看不見」花了幾秒。
  4. 把 1kΩ 換成 4.7kΩ,重複步驟 2~3。
  5. 再換成 10kΩ,重複一次(房間最好暗一點,因為電流很小,LED 比較暗)。
  6. 算一算每種電阻的 τ = R × C,填進表格。

你應該看到

按住時 LED 亮,放開後 LED 不是立刻熄滅,而是慢慢變暗。用 1kΩ 時 τ = 1kΩ × 1000µF = 1 秒,大約 1.5~2 秒後幾乎看不見(LED 要 1.8V 以上才會發光,所以電壓掉到 2V 以下你就看不到了,不用等到 5τ)。換 4.7kΩ,τ = 4.7 秒,會亮比較久、但比較暗;10kΩ 時 τ = 10 秒,可以撐十幾秒,但很暗。

按鈕按下去的時候,220Ω 負責充電:τ = 220Ω × 1000µF = 0.22 秒,大約 1 秒就充飽了,所以按 2 秒綽綽有餘。

觀察與記錄

放電電阻τ = R × C(秒)放開後看不見 LED 的秒數亮度(亮/普通/暗)
1kΩ
4.7kΩ
10kΩ

實驗 5-2:用三用電表看電容電壓慢慢掉

材料

  • 9V 電池與電池扣
  • 按鈕開關 1 個
  • 10kΩ 電阻 1 顆
  • 100µF 電解電容 1 顆;另外準備 470µF、1000µF 各 1 顆做比較
  • 麵包板、杜邦線
  • 數位三用電表
  • 手機碼表(或請同學數秒)

接線(放電)

 9V + ──[ 按鈕 ]──┬──────────┐
                  │+         │
                ══╧══     [ 10kΩ ]      三用電表(DCV 20V 檔)
                100µF        │          紅棒 → 電容 +
                  │−         │          黑棒 → GND
 9V − ────────────┴──────────┴── GND

  • 電池扣紅線 → 按鈕 → 電容長腳(+)
  • 電容短腳(−)→ GND
  • 10kΩ 跨在電容兩端(一端電容 +,一端 GND)
  • 電表紅棒夾在電容 +,黑棒夾在 GND

步驟

  1. 先算:τ = 10kΩ × 100µF = 1 秒。預測放開按鈕後每秒的電壓,填進表格「預測」欄(用上一節的表:37%、14%、5%……)。
  2. 按住按鈕,電表應該顯示約 9V(電容充飽)。
  3. 放開按鈕的同時按下碼表,每隔 1 秒讀一次電表。因為電表每秒只更新 2~3 次,建議一個人讀數、一個人報時,或是用手機錄影電表和碼表再慢慢看。
  4. 換成 470µF(τ = 4.7 秒),每 5 秒讀一次,會輕鬆很多。
  5. 換成 1000µF(τ = 10 秒),每 10 秒讀一次。
  6. 額外觀察:把 10kΩ 拔掉,只留電表。充飽後放開按鈕,看電壓掉多快。

接線(充電)

想看充電曲線,把 10kΩ 移到按鈕和電容之間:

 9V + ──[ 按鈕 ]──[ 10kΩ ]──┬────  電表紅棒
                            │+
                          ══╧══ 100µF
                            │−
 9V − ──────────────────────┴────  電表黑棒(GND)

  1. 先用一條杜邦線碰一下電容兩端讓它放光(電壓歸 0)。
  2. 按住按鈕不放,每秒讀一次:應該看到 0 → 5.7 → 7.8 → 8.6 → 8.8 → 8.9V,越來越慢地接近 9V。

你應該看到

放電時(10kΩ + 100µF)大約是:

時間0 秒1 秒2 秒3 秒4 秒5 秒
電壓9.0V3.3V1.2V0.45V0.17V0.06V

換 470µF 後(τ = 4.7 秒):0 秒 9.0V、5 秒約 3.1V、10 秒約 1.1V、15 秒約 0.4V、20 秒約 0.1V。換 1000µF 後(τ = 10 秒):10 秒 3.3V、20 秒 1.2V、30 秒 0.45V。

步驟 6 把 10kΩ 拔掉後,電壓幾乎不動,一分鐘可能才掉零點幾伏。因為三用電表的輸入電阻大約 10MΩ,τ = 10MΩ × 100µF = 1000 秒!這也說明了:三用電表量東西時幾乎不會「偷」電流,所以不會干擾電路。

觀察與記錄

時間(秒)預測電壓(V)100µF 實際(V)470µF 實際(V)(每 5 秒)1000µF 實際(V)(每 10 秒)
09.0
1τ3.3
2τ1.2
3τ0.45
4τ0.17
5τ0.06

實驗 5-3:用示波器看充放電曲線(Arduino 方波經過 RC)

三用電表每秒只能看兩三次,τ = 1 秒已經快到很難讀;如果 τ 只有 1 毫秒,電表完全來不及。這時候就要請出示波器:讓 Arduino 不停地「接上電池、拔掉電池」(也就是輸出方波),示波器就能把一次次的充放電曲線畫出來。

材料

  • Arduino UNO 與 USB 線
  • 10kΩ 電阻 1 顆
  • 100nF 陶瓷電容(印 104)1 顆;另外準備 100µF 電解電容做慢速版本
  • 麵包板、杜邦線
  • 示波器(雙通道,探棒 2 支)

接線

 Arduino D9 ──┬──[ 10kΩ ]──┬──────── 
              │            │
          CH1 探棒      ══╧══ 100nF      CH2 探棒
              │            │
 Arduino GND ─┴────────────┴──── 接地夾(兩支都夾這裡)

  • Arduino D9 → 10kΩ 一端
  • 10kΩ 另一端 → 節點 B → 100nF 一腳
  • 100nF 另一腳 → Arduino GND
  • CH1 探棒鉤在 D9(方波輸入),CH2 探棒鉤在節點 B(電容電壓)
  • 兩支探棒的接地夾都夾在 Arduino GND

程式

// 第 5 章 實驗 5-3:Arduino 產生方波,用示波器看 RC 充放電
const int squarePin = 9;       // 方波輸出腳位 D9
const int halfPeriodMs = 5;    // 半個週期的長度(毫秒)
                               // 5 → 週期 10ms,頻率 100Hz(配 10kΩ + 100nF)
                               // 改成 500 → 週期 1 秒,頻率 1Hz(配 10kΩ + 100µF 或 LED)

void setup() {
  pinMode(squarePin, OUTPUT);  // 把 D9 設成輸出
}

void loop() {
  digitalWrite(squarePin, HIGH);   // D9 輸出 5V,開始充電
  delay(halfPeriodMs);             // 等半個週期
  digitalWrite(squarePin, LOW);    // D9 輸出 0V,開始放電
  delay(halfPeriodMs);             // 再等半個週期
}

如果你想要更快的方波,也可以用 tone(),它會在背景自動產生方波,loop() 裡什麼都不用寫:

// 第 5 章 實驗 5-3(替代版):用 tone() 產生 100Hz 方波
const int squarePin = 9;       // 方波輸出腳位 D9

void setup() {
  tone(squarePin, 100);        // 在 D9 輸出 100Hz 方波,改成 1000 就是 1kHz
}

void loop() {
  // 不用做任何事,tone() 會自己一直輸出
}

步驟

  1. 先算 τ = 10kΩ × 100nF = 1ms。方波半個週期是 5ms = 5τ,所以每次充電都來得及充飽、每次放電都來得及放光。
  2. 上傳程式。接好線,兩支探棒的接地夾都夾 GND。
  3. 示波器設定:CH1 與 CH2 都開啟,都設 1V/div(探棒若是 10×,示波器該通道也要設 10×);水平 1ms/div;觸發來源 CH1、上升邊緣、準位 2.5V;觸發模式 Auto。
  4. 畫面上 CH1 應該是乾淨的方波,CH2 是圓弧形的充放電曲線。
  5. 用游標(Cursor)量時間:把一條游標放在 CH1 由 0V 跳到 5V 的那一瞬間,另一條放在 CH2 爬到 3.2V(5V 的 63%)的地方,兩條游標的時間差應該約 1ms,就是 τ。
  6. 把 100nF 換成 100µF(注意極性:長腳接節點 B),程式的 halfPeriodMs 改成 500 重新上傳,水平改成 500ms/div。這時 τ = 1 秒,但半個週期只有 0.5 秒,電容還沒充飽就要放電,看看波形變成什麼樣。
  7. 再把 halfPeriodMs 改成 5000(5 秒),水平改成 2s/div,看看是不是又變回完整的圓弧。

你應該看到

CH1:D9 的方波(1V/div,1ms/div)
 5V ┤    ┌─────────┐         ┌─────────┐
    │    │         │         │         │
    │    │         │         │         │
 0V ┼────┘         └─────────┘         └──── 時間

CH2:電容電壓(1V/div,1ms/div)
 5V ┤       ╭──────╮            ╭──────╮
    │     ╱         ╲         ╱         ╲
3.2V┤  ╱            ╲      ╱            ╲
    │  ╱               ╲   ╱               ╲
 0V ┼─╯                 ╰─╯                 ╰── 時間
      ◄─►
      1ms = τ(CH2 爬到 3.2V 的時間)
      ◄────────►
        5ms = 5τ(充飽)

方波一跳上去,電容電壓就開始「往上爬」,一開始陡、越來越平,5ms 後幾乎貼到 5V;方波一掉下來,電容電壓就「往下滑」,一樣先快後慢。步驟 6 的慢速版本,因為只有 0.5τ 就換方向,曲線會變成一個圓圓的三角波,高度到不了 5V。步驟 7 把半週期拉長到 5τ,又會看到完整的圓弧。

觀察與記錄

設定RCτ = R × C半週期半週期是幾個 τ?電容電壓最高到幾 V?游標量到的 τ
步驟 410kΩ100nF5ms
步驟 610kΩ100µF0.5s
步驟 710kΩ100µF5s

用儀器看看

三用電表:有些數位三用電表有電容檔(符號是「F」或「─┤├─」)。把電容兩腳插進電表專用的小孔或用探棒夾住(電解電容要先放電、注意極性),就能直接讀出電容值。你會發現電解電容的實際值可能和標示差 10%~20%,這是正常的。如果你的電表沒有這個檔位,用實驗 5-2 的方法反推也可以:量出放電到 37% 需要幾秒,再用 C = τ ÷ R 算出來。例如放電到 3.3V 花了 4.5 秒,R = 10kΩ,C = 4.5 ÷ 10000 = 0.00045F = 450µF,表示那顆「470µF」的實際值差不多。

示波器:實驗 5-3 就是示波器的第一次登場。重點提醒三件事:

  1. 兩支探棒的接地夾都只能夾 GND。
  2. 探棒的 1×/10× 開關和示波器的設定要一致,否則讀值會差 10 倍(第 6 章會詳細說明)。
  3. 看慢速訊號(500ms/div 以上)時,示波器會進入「滾動模式」,波形像心電圖一樣從右邊往左邊流過去,這是正常的。

下一章我們會把示波器的每一個旋鈕都講清楚。

常見錯誤與除錯

  • 實驗 5-1 按住按鈕 LED 也不亮 → 電容接反(接反的電解電容會像短路,把電壓拉到 0)、LED 接反、或按鈕插在麵包板上沒有接通 → 拔掉電池,檢查電容白帶是否在 GND 側、LED 長腳是否接電阻;按鈕四支腳換一組試試。
  • 放開按鈕 LED 立刻熄滅,沒有慢慢變暗 → 電容沒接到節點 A,或電容太小(拿到 100µF 而不是 1000µF) → 看電容上印的數字,用電表量節點 A 的電壓是否會慢慢掉。
  • 電容發熱、鼓起、有怪味 → 接反了或超過耐壓 → 立刻拔掉電池,那顆電容不要再用。
  • 實驗 5-2 電壓掉得比預測快很多 → 電表轉在電阻檔或電流檔、或電容的實際值偏小 → 確認電表在 DCV;換一顆電容比較。
  • 實驗 5-2 電壓完全不掉 → 10kΩ 沒接好,變成只有電表在放電(τ = 1000 秒) → 檢查 10kΩ 兩端是否真的跨在電容上。
  • 實驗 5-3 CH2 看起來和 CH1 一樣是方波 → 探棒鉤錯地方(鉤到 D9 而不是節點 B),或電容沒接上 → 重新確認探棒位置;把 10kΩ 換成 100kΩ,曲線應該變得更圓更慢。
  • 實驗 5-3 波形一直左右跑、停不下來 → 觸發來源不是 CH1,或準位不在 0~5V 之間 → 設觸發來源 CH1、上升邊緣、準位 2.5V。
  • 實驗 5-3 讀出來的電壓只有 0.5V → 探棒是 10× 但示波器設 1× → 把示波器的探棒設定改成 10×。

想一想

  1. 10kΩ 配 100µF 的 τ 是多少?要幾秒才算充飽?
參考答案

τ = 10000 × 0.0001 = 1 秒。5τ = 5 秒充飽。

  1. 你想要一個放開按鈕後大約 5 秒才熄滅的延遲關燈,手上只有 1000µF 電容。應該用幾 Ω 的放電電阻?
參考答案

τ = R × C,R = τ ÷ C = 5 ÷ 0.001 = 5000Ω。手邊最接近的是 4.7kΩ(τ = 4.7 秒)。注意 LED 在 2V 以下就看不到了,所以實際「看起來亮著」的時間會比 τ 短一些,想要更久可以用 10kΩ。

  1. 一顆充到 9V 的電容開始放電,經過 1τ 剩多少伏特?2τ 呢?
參考答案

1τ:9 × 0.37 ≈ 3.3V。2τ:9 × 0.14 ≈ 1.2V(也可以算 3.3 × 0.37 ≈ 1.2V)。

  1. 示波器上,你量到 CH2 從 0V 爬到 3.2V(5V 的 63%)花了 2ms,電阻是 10kΩ。電容是多少?
參考答案

τ = 2ms = 0.002 秒。C = τ ÷ R = 0.002 ÷ 10000 = 0.0000002F = 200nF。可能是兩顆 100nF 並聯(並聯電容值相加)。

  1. 為什麼電解電容接反會爆,陶瓷電容卻沒有方向?
參考答案

電解電容靠一層很薄的化學膜當絕緣層,這層膜只有在正確方向的電壓下才存在;接反會把膜破壞,電容變短路、發熱、產生氣體而爆開。陶瓷電容的絕緣層是陶瓷本身,兩個方向都一樣,所以沒有極性。

  1. (開放挑戰)實驗 5-3 步驟 6 的波形為什麼到不了 5V?如果想用 1Hz 方波(半週期 0.5 秒)看到完整的圓弧,R 和 C 要怎麼選?寫出一組可行的數值並算出 τ。
參考答案

因為半週期只有 0.5τ,電容充到 5V 的 39% 左右(約 2V)就被拉下來放電,放電也只有 0.5τ,所以電壓在中間來回晃,爬不到頂。要看到完整圓弧,半週期要有 5τ,也就是 τ ≤ 0.1 秒。例如 10kΩ + 10µF:τ = 10000 × 0.00001 = 0.1 秒,剛好;或 1kΩ + 100µF:τ = 1000 × 0.0001 = 0.1 秒,也可以。

本章小結

  • 電容像水桶,存的是電荷;電容值的單位是法拉(F),常用 µF、nF、pF,每級差 1000 倍。
  • 陶瓷電容的三位數字「104」= 100nF;電解電容直接印 µF 和耐壓。
  • 電解電容有極性:長腳是 +、白帶是 −,接反會爆。
  • 充電與放電都是「先快後慢」的圓弧曲線。
  • 時間常數 τ = R × C(Ω × F = 秒);kΩ × µF 直接等於 ms。
  • 每過一個 τ,放電剩 37%、充電到 63%;5 個 τ 就充飽或放光。
  • 三用電表看得到秒等級的充放電;毫秒等級要用示波器,用 Arduino 方波當「不停開關的電池」。
  • 示波器接地夾只能夾 GND;探棒 1×/10× 要和示波器設定一致。

名詞表

中文英文一句話解釋
電容Capacitor兩片金屬板夾絕緣層,能暫時存電荷的元件
電容值Capacitance電容能存多少電荷的能力,符號 C
法拉Farad(F)電容值的單位,1F 在 1V 下存 1 庫侖
微法拉/奈法拉/皮法拉µF / nF / pF法拉的百萬分之一/十億分之一/兆分之一
耐壓Rated Voltage電容能承受的最高電壓
極性Polarity元件有分正負極,不能接反
電解電容Electrolytic Capacitor有極性、容量大的圓柱形電容
陶瓷電容Ceramic Capacitor沒有極性、容量小的扁圓片電容
充電Charging電容電壓從低升到高的過程
放電Discharging電容電壓從高降到低的過程
時間常數Time Constant(τ)τ = R × C,決定充放電快慢的秒數
滾動模式Roll Mode示波器看慢速訊號時波形從右往左流動的顯示方式

第 6 章 示波器入門

本章目標

  • 學完你會說出示波器到底在畫什麼:橫軸是時間、縱軸是電壓。
  • 學完你會正確使用探棒:1×/10× 開關要和示波器設定一致、先做探棒補償、接地夾只能夾 GND。
  • 學完你會看格子換算電壓與時間:V/div、s/div,並用 Auto Set 快速找到波形。
  • 學完你會設定觸發(來源、邊緣、準位),分辨 Auto、Normal 與 Single 三種模式,讓波形乖乖停在畫面上。
  • 學完你會用 Measure 自動量測 Vpp、頻率、週期,用 Cursor 游標手動量,並用 Run/Stop 把波形凍結。
  • 學完你會把兩個通道一起看,比較 Arduino 兩支腳位輸出的方波。

開場:三用電表看得到「現在」,看不到「變化」

小宇寫了一個 Arduino 程式讓 D9 腳位每秒閃一次 LED。他用三用電表去量 D9,電表上的數字一下 5V、一下 0V,跳來跳去。接著他把程式改成每毫秒閃一次,LED 看起來變成「一直亮著、但比較暗」,電表卻顯示 2.5V——既不是 5V 也不是 0V。

電表沒有壞。它每秒只量兩三次,再把量到的值平均一下,所以面對一秒鐘變化上千次的訊號,它只能給你一個「平均值」。真正發生的事是:D9 每毫秒在 0V 和 5V 之間跳,一半時間高、一半時間低,平均起來剛好 2.5V。

要看到「跳」的過程,你需要一台能把電壓隨時間的變化畫成圖的儀器——示波器(Oscilloscope)。它像一台超高速的心電圖機:心電圖畫的是心臟電訊號對時間的圖,示波器畫的是任何電壓對時間的圖,而且一秒鐘能畫幾百萬個點。這一章我們把示波器的每個按鈕都搞懂。

核心概念

示波器在畫什麼

示波器螢幕上是一張格線圖:橫軸是時間,從左到右;縱軸是電壓,往上是正。螢幕通常橫向 10 格、縱向 8 格,每一格叫做一個 div(division,刻度)。

 CH1 1.00V      M 200µs      觸發 CH1 ⎍ 2.50V
 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
1►━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┥ ← 0V 基準線(CH1)
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
   ◄──────────────── 10 格(橫向:時間)────────────►
   每格 = s/div 的設定值;縱向 8 格,每格 = V/div 的設定值

螢幕左邊有個小標記「1►」,標示 CH1 的 0V 在哪一條線。畫面上方(或下方)會顯示目前每格代表多少電壓(例如 CH1 1.00V)和多少時間(例如 M 200µs)。學會看這兩個數字,你就看得懂示波器的任何畫面。

探棒:1× 與 10× 一定要一致

探棒(Probe)是示波器的「手」。前端是一個可以鉤住元件腳的鉤子,旁邊有一條短線接著黑色的鱷魚夾,那是接地夾(Ground Clip)。探棒上有個小開關,寫著 1× 和 10×。

  • 1×:訊號原封不動送進示波器。
  • 10×:訊號先被探棒縮小 10 倍再送進去。

為什麼要縮小?縮小 10 倍後探棒的輸入電阻變成 10MΩ,幾乎不會從電路「偷」電流(和三用電表一樣的道理),而且能量更高的電壓。本書建議:探棒一律撥到 10×,而且示波器的通道選單裡「Probe」也設成 10×。這樣示波器會自動把讀值乘回 10 倍,你看到的就是真正的電壓。

如果兩邊不一致會怎樣?探棒 10× 但示波器設 1×,5V 的訊號會顯示成 0.5V;探棒 1× 但示波器設 10×,5V 會顯示成 50V。只要讀值看起來剛好差 10 倍,第一件事就是檢查這兩個設定。

接地夾只能夾 GND

這是本書的安全紅線,原因要講清楚。示波器所有通道的接地夾,在機器裡面是連在一起的,而且連到示波器的金屬外殼和插座的地線。所以:

  • 如果 CH1 的接地夾夾在 GND,CH2 的接地夾夾在 D9,那 D9 就會透過示波器內部直接接到 GND,等於把 D9 短路,Arduino 可能重開機甚至燒腳位。
  • 如果接地夾夾在電池的正極,再把另一支探棒的接地夾夾在負極,電池就被短路。

規則只有一條:每一支探棒的接地夾,都夾在同一個 GND 上。想量哪裡,用前端的鉤子去鉤,接地夾永遠不動。

探棒補償:讓方波變成漂亮的方形

示波器面板上有一個小金屬片或兩個小端子,標示 Probe Comp(探棒補償),它會持續輸出一個 1kHz 的方波(通常 3V 或 5V)。第一次用一支探棒、或探棒換到另一台示波器時,要先把探棒鉤在這裡看看方波長什麼樣:

  剛好(正確)          過補償              欠補償
 ┌────┐    ┌────┐     ┐    ┐            ╭───╮    ╭───╮
 │    │    │    │     │╲   │╲           │   │    │   │
 │    │    │    │     │ └──┘ └──       ╯   ╰────╯   ╰──
─┘    └────┘    └──  ─┘    └                 
  角落方方正正       角落翹起來(尖角)     角落圓圓的(塌陷)

如果方波的角落翹起來或塌下去,拿探棒附的小螺絲起子,轉探棒接頭上的小螺絲(有的在探棒前端、有的在接示波器那端),一邊轉一邊看,直到角落變成方方正正。這叫探棒補償(Probe Compensation)。沒做補償,之後量方波會一直看到奇怪的角,你會以為是電路有問題。

V/div 與 s/div:看格子算數字

V/div(Volts per division):縱向每一格代表幾伏特,由垂直刻度旋鈕(Scale)控制。 s/div(seconds per division):橫向每一格代表幾秒,由水平刻度旋鈕控制。

換算就是「數格子 × 每格多少」:

電壓 = 格數 × V/div
時間 = 格數 × s/div

例子一:V/div 設 1V,方波從 0V 基準線往上跳了 5 格。電壓 = 5 × 1V = 5V。

例子二:s/div 設 200µs,一個完整週期(從這次上升邊緣到下一次上升邊緣)占了 5 格。週期 T = 5 × 200µs = 1000µs = 1ms。頻率 f = 1 ÷ T = 1 ÷ 0.001 = 1000Hz。

例子三:s/div 設 500µs,一個週期占 4 格。T = 4 × 500µs = 2ms,f = 1 ÷ 0.002 = 500Hz。

每個通道還有一個位置旋鈕(Position),可以把波形上下移;水平位置旋鈕可以把波形左右移。移動只是「換個地方放」,不會改變格數的意義。

想讓波形看起來大一點,把 V/div 調小(例如 2V → 1V);想看更多個週期,把 s/div 調大。

觸發:讓波形停下來

示波器不停地「拍照」,一張接一張地把波形畫出來。如果每一張照片都從隨便的時間點開始畫,重疊起來就是一團亂、左右亂跑。**觸發(Trigger)**就是告訴示波器:「每次都從訊號經過某個電壓、往某個方向的那一瞬間開始畫」。這樣每一張都對齊,波形就穩穩地停在畫面上。

觸發有三個設定:

  1. 來源(Source):看哪個通道來決定何時開始畫。通常選有訊號、比較乾淨的那個,例如 CH1。
  2. 邊緣(Edge / Slope):上升邊緣(訊號從低變高的瞬間)或下降邊緣(從高變低)。
  3. 準位(Level):觸發的電壓門檻。準位一定要放在訊號的最高和最低之間。量 0~5V 的方波,準位放 2.5V 最保險;如果你把準位轉到 7V,訊號永遠碰不到,就永遠不會觸發。

畫面上會有一個小箭頭或「T」標示目前的準位,轉觸發準位旋鈕可以看到它上下移動。

Auto、Normal 與 Single

觸發模式決定「沒有觸發的時候要怎麼辦」:

  • Auto(自動):有觸發就對齊畫;等太久沒觸發,就隨便畫一張給你看。適合初學,也適合看直流(直流沒有邊緣,永遠不會觸發,用 Auto 才看得到那條直線)。
  • Normal(一般):沒有觸發就不畫,畫面停在上一張。適合等待一個偶爾才發生的訊號,例如按一下按鈕。
  • Single(單次):按下去之後,示波器只等一次觸發,抓到就停住不再更新。要抓「只發生一次」的事情(例如開關瞬間的尖波,第 7 章會用到)就靠它。

另外面板上有 Run/Stop 按鈕:Run 的時候不停更新,按一下變 Stop,畫面凍結,你可以慢慢看、慢慢量,再按一下恢復。

Auto Set:先按它,再動手調

大部分示波器都有一個 Auto Set(或 Autoscale)按鈕。按下去,示波器會自己猜一組 V/div、s/div 和觸發設定,把它看到的訊號放進畫面。對於持續不斷的週期訊號(方波、正弦波),它幾乎都能一按就看到波形,非常好用。

但它有兩個弱點:看直流時它可能把 V/div 調得太細讓直線跑出畫面;抓單次事件時它完全沒用(因為按的時候沒有訊號)。所以習慣是:先按 Auto Set 看到波形,再手動微調 V/div、s/div 和觸發準位到你想要的樣子。

自動量測與游標

Measure(量測):按下後選擇通道和項目,示波器會直接在畫面上顯示數字。常用的有:

  • Vpp(峰對峰電壓,Peak-to-Peak):最高點減最低點。0~5V 方波的 Vpp = 5V。
  • Vmax / Vmin / Mean:最高、最低、平均。0~5V 對稱方波的 Mean ≈ 2.5V,和開場小宇用電表量到的一樣。
  • Frequency(頻率) 與 Period(週期):互為倒數。

Cursor(游標):兩條可以用旋鈕移動的虛線。選「時間游標」會出現兩條直立的線,示波器顯示兩條線之間的時間差 Δt(和 1 ÷ Δt);選「電壓游標」會出現兩條橫線,顯示 ΔV。Measure 是示波器自己算,游標是你自己決定要量哪兩個點,兩個都要會。

耦合:DC 與 AC

通道選單裡的**耦合(Coupling)**有 DC 和 AC 兩種。DC 是原汁原味,電壓是多少就畫多少。AC 是在輸入端串一顆電容(第 5 章學過:電容擋住直流、讓變化通過),把訊號的「平均值」去掉,只留下變化的部分。量電池用 AC 會看到 0V,量方波用 AC 會看到方波上下對稱地跨在 0V 兩邊。初學一律用 DC,知道 AC 是什麼就好。

動手做

安全提醒:接地夾只夾 GND。本章訊號最高 9V。接線前先把 Arduino 的 USB 拔掉,接好再插。

實驗 6-1:探棒補償,然後量一條直線

材料

  • 示波器(雙通道)與 10× 探棒 1 支
  • 探棒附的小螺絲起子
  • 9V 電池與電池扣

接線

 第一階段:
   探棒鉤子 → 示波器面板的 Probe Comp 訊號端
   接地夾   → Probe Comp 旁邊的接地端(⏚ 符號)

 第二階段:
   探棒鉤子 → 9V 電池扣紅線(+)
   接地夾   → 9V 電池扣黑線(−)

步驟

  1. 開機,等它進入正常畫面。把探棒接到 CH1,探棒開關撥到 10×。
  2. 進入 CH1 選單,找到「Probe」或「探棒」,設成 10×。
  3. 把探棒鉤在 Probe Comp,接地夾夾旁邊的接地端。
  4. 按 Auto Set。畫面應該出現一個方波。看上方的標示,應該是 1kHz 左右,高度約 3V 或 5V(看機型)。
  5. 仔細看方波的角落:方方正正、翹起來、還是塌下去?用小螺絲起子輕輕轉探棒上的補償螺絲,直到角落方正。
  6. 如果你有第二支探棒,接到 CH2,重複步驟 1~5。
  7. 第二階段:把探棒改鉤 9V 電池的紅線,接地夾夾黑線。CH1 設 DC 耦合、2V/div,觸發模式 Auto,s/div 設 1ms。
  8. 用 CH1 的位置旋鈕把 0V 基準線移到畫面最下面那一格。你應該看到一條平的線,在基準線上方約 4.5 格。
  9. 把耦合改成 AC,看那條線跑去哪裡。改回 DC。
  10. 把觸發模式改成 Normal,看看畫面怎麼了(提示:直流沒有邊緣)。改回 Auto。

你應該看到

 CH1 2.00V (DC)   M 1.00ms   Auto
 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 9V:基準線上方 4.5 格
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
1►━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━┥  ← 0V 基準線
 └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

電池是直流,所以是一條完全平的線:4.5 格 × 2V/div = 9V。改成 AC 耦合後,線會掉到 0V 基準線上(直流被擋掉了)。改成 Normal 觸發後,畫面會停住不更新,因為沒有任何邊緣可以觸發,這就是為什麼看直流要用 Auto。

觀察與記錄

項目記錄
Probe Comp 方波頻率(畫面標示)
補償前角落的樣子(方正/翹起/塌陷)
電池那條線在基準線上方幾格
格數 × V/div = 電壓
三用電表量到的電池電壓(比對)
改成 AC 耦合後線在哪裡

實驗 6-2:量 Arduino 的方波——Vpp、頻率、週期

材料

  • Arduino UNO 與 USB 線、電腦
  • 示波器與 10× 探棒 1 支
  • 杜邦線(公公)2 條

接線

 Arduino D9 ────── CH1 探棒鉤子
 Arduino GND ───── CH1 接地夾

  • 一條杜邦線插在 D9,探棒鉤子鉤住杜邦線的金屬端。
  • 一條杜邦線插在 GND,接地夾夾住。

程式

// 第 6 章 實驗 6-2 / 6-3:Arduino 同時產生兩種方波
// D9  用 tone() 產生 1kHz 方波(由計時器在背景自動輸出)
// D10 用 digitalWrite + delay 產生約 500Hz 方波

const int tonePin = 9;        // tone() 輸出腳位
const int togglePin = 10;     // digitalWrite 輸出腳位
const int toneFreq = 1000;    // tone 的頻率(Hz),實驗中會改成 500、2000、5000

void setup() {
  pinMode(togglePin, OUTPUT);   // D10 設成輸出
  tone(tonePin, toneFreq);      // D9 開始輸出 toneFreq Hz 的方波
}

void loop() {
  digitalWrite(togglePin, HIGH);  // D10 變 5V
  delay(1);                       // 停 1 毫秒
  digitalWrite(togglePin, LOW);   // D10 變 0V
  delay(1);                       // 再停 1 毫秒 → 週期約 2ms,約 500Hz
}

步驟

  1. 上傳程式,接好線(探棒 10×、示波器 CH1 Probe 10×)。
  2. 按 Auto Set。應該看到方波。
  3. 手動設定:CH1 1V/div、DC 耦合;水平 200µs/div;觸發來源 CH1、上升邊緣、準位 2.5V;模式 Auto。把 0V 基準線移到下面數來第 2 格。
  4. 數格子:方波高幾格?一個週期占幾格?算出電壓、週期、頻率,填表。
  5. 按 Measure,選 CH1,加入 Vpp、Frequency、Period、Mean。把示波器算的數字和你數格子算的比一比。
  6. 按 Cursor,選時間游標,把第一條放在某個上升邊緣,第二條放在下一個上升邊緣,讀 Δt。再換電壓游標,一條放在方波頂、一條放在底,讀 ΔV。
  7. 轉觸發準位旋鈕,把準位轉到 6V 以上,看波形怎麼了。轉回 2.5V。把邊緣改成下降,看波形左右移動的樣子(觸發點永遠在畫面中央那條線上)。
  8. 按 Run/Stop,畫面凍結;再按一次恢復。
  9. 把程式裡的 toneFreq 改成 500、2000、5000,各上傳一次。每次先按 Auto Set,再把 s/div 調到剛好看到 2~3 個週期,記錄 Measure 的頻率。
  10. 試試 Single:先把 D9 的杜邦線拔掉(畫面變成 0V 直線),按 Single,示波器會顯示「等待中」;再把線插回去,它會抓到第一個邊緣就停住。按 Run/Stop 回到連續模式。

你應該看到

 CH1 1.00V (DC)   M 200µs   觸發 CH1 ⎍ 2.50V   Vpp=5.04V  Freq=1.000kHz  Period=1.000ms
 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │  ┏━━━━━━━━━┓  ┆    ┏━━━━━━━━━┓  ┆    ┏━━━━━━━━━┓ │  ← 5V(基準線上方 5 格)
 ├┄┄┃┄┼┄┄┄┄┼┄┄┃┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┤
 │  ┃ ┆    ┆  ┃ ┆    ┃    ┆    ┆┃  ┆    ┃    ┆    ┆┃  │
 ├┄┄┃┄┼┄┄┄┄┼┄┄┃┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┤
 │  ┃ ┆    ┆  ┃ ┆  T ┃    ┆    ┆┃  ┆    ┃    ┆    ┆┃  │  ← T:觸發準位 2.5V
 ├┄┄┃┄┼┄┄┄┄┼┄┄┃┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┤
 │  ┃ ┆    ┆  ┃ ┆    ┃    ┆    ┆┃  ┆    ┃    ┆    ┆┃  │
 ├┄┄┃┄┼┄┄┄┄┼┄┄┃┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┼┄┄┄┄┃┄┄┄┼┄┄┄┄┼┃┄┄┤
1►━━┛ ┆    ┆  ┗━━━━━━┛    ┆    ┆┗━━━━━━━┛    ┆    ┆┗━━┥  ← 0V 基準線
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
      ◄──────────────────►
       一個週期 = 5 格 × 200µs = 1ms  →  f = 1 ÷ 0.001 = 1000Hz

方波高 5 格 × 1V = 5V,和 Measure 的 Vpp 約 5V 一致(可能顯示 4.9~5.1V,USB 的 5V 本來就不是剛好 5.00V)。一個週期 5 格 × 200µs = 1ms,頻率 1000Hz,Measure 的 Frequency 會顯示 1.000kHz。Mean 約 2.5V,就是開場故事三用電表看到的數字。

把準位轉到 6V 以上,波形會開始左右亂跑(Auto 模式下示波器找不到觸發就隨便畫),這就是沒有觸發的樣子。改成下降邊緣,畫面中央的觸發點會從「往上跳」變成「往下掉」。

改頻率的對照:

toneFreq週期 T = 1 ÷ f建議 s/div一個週期占幾格
500Hz2ms500µs4 格
1000Hz1ms200µs5 格
2000Hz0.5ms100µs5 格
5000Hz0.2ms50µs4 格

觀察與記錄

項目數格子算的Measure 顯示的游標量到的
方波高度(Vpp)格 × V/div = VΔV =
週期 T格 × s/div = msΔt =
頻率 f = 1 ÷ T1 ÷ Δt =
Mean(平均電壓)——
toneFreq = 500 時的頻率
toneFreq = 2000 時的頻率
toneFreq = 5000 時的頻率

實驗 6-3:兩個通道一起看

材料

  • 同實驗 6-2,再加一支 10× 探棒接 CH2
  • 杜邦線(公公)3 條

接線

 Arduino D9  ────── CH1 探棒鉤子(tone 1kHz)
 Arduino D10 ────── CH2 探棒鉤子(digitalWrite 約 500Hz)
 Arduino GND ──┬─── CH1 接地夾
               └─── CH2 接地夾

  • 兩支探棒的接地夾都夾在 GND 那條杜邦線上(可以一夾夾住另一夾)。
  • 絕對不要把任何接地夾夾在 D9 或 D10。

步驟

  1. 程式用實驗 6-2 的,toneFreq 改回 1000。
  2. CH1、CH2 都打開,都設 1V/div、DC、Probe 10×。用位置旋鈕把 CH1 的基準線放在上半部、CH2 的基準線放在下半部,兩條波形就不會疊在一起。
  3. 水平 500µs/div,觸發來源 CH1、上升邊緣、準位 2.5V。
  4. 觀察:CH1 穩穩的,CH2 呢?它會慢慢左右漂移。這是因為 D10 的方波是用 delay() 一步一步做出來的,和 D9 的 tone 計時器各走各的,兩個訊號並不同步。
  5. 把觸發來源改成 CH2。現在換 CH2 穩住、CH1 漂移。觸發來源選誰,誰就穩。
  6. 用 Measure 分別量 CH1 和 CH2 的頻率。CH2 不會剛好 500Hz,大概 495~499Hz,因為 digitalWrite() 和 loop() 本身也要花幾微秒。
  7. 數數看:CH2 的一個週期裡,CH1 有幾個週期?
  8. 如果你有 ESP32,把 D9 換成 ESP32 的 GPIO 18(程式一樣,tonePin 改 18、togglePin 改 19),看看方波高度變成幾格。

你應該看到

 CH1 1.00V   CH2 1.00V   M 500µs   觸發 CH1 ⎍ 2.50V
 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
 │ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓ ┏━┓  │  CH1:1kHz,每 2 格一個週期
 │ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃  │
1►━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━┛ ┗━━┥  ← CH1 的 0V
 ├┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┼┄┄┄┄┤
 │    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    ┆    │
 │  ┏━━━━━━━┓   ┆  ┏━━━━━━━┓   ┆  ┏━━━━━━━┓   ┆    │  CH2:約 500Hz,每 4 格一個週期
 │  ┃    ┆  ┃   ┆  ┃    ┆  ┃   ┆  ┃    ┆  ┃   ┆    │       (會慢慢左右漂)
2►━━┛    ┆  ┗━━━━━━┛    ┆  ┗━━━━━━┛    ┆  ┗━━━━━━━┥  ← CH2 的 0V
 └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

CH1 一個週期 2 格 × 500µs = 1ms(1kHz);CH2 一個週期 4 格 × 500µs = 2ms(500Hz)。CH2 的一個週期裡剛好有 2 個 CH1 的週期。換 ESP32 後方波只有 3.3 格高,因為 ESP32 是 3.3V 的板子。

觀察與記錄

項目CH1(D9)CH2(D10)
一個週期占幾格
週期 = 格數 × 500µs
頻率 = 1 ÷ 週期
Measure 顯示的頻率
觸發來源設 CH1 時,哪個通道在漂?
觸發來源設 CH2 時,哪個通道在漂?
ESP32 方波高幾格(V)

用儀器看看

本章整章都是「用儀器看看」:實驗 6-1 到 6-3 已經把探棒、V/div、s/div、觸發、量測、游標全部練過一遍。之後每一章的這個段落,都會直接寫「CH1 鉤在哪裡、V/div 多少、s/div 多少、觸發怎麼設」,請把這一章當成之後隨時可以翻回來的說明書。附錄 D 另有一頁示波器速查表。

常見錯誤與除錯

  • 畫面上什麼都沒有 → 通道沒開、V/div 太大(波形被壓成一條線貼在基準線上)、或探棒沒接好 → 先按 Auto Set;確認通道選單裡 CH1 是 ON;把鉤子鉤緊。
  • 讀值剛好差 10 倍(5V 變 0.5V 或 50V) → 探棒開關和示波器的 Probe 設定不一致 → 兩邊都改成 10×。
  • 波形左右亂跑、停不下來 → 觸發來源不是有訊號的那個通道,或準位不在波形範圍內 → 觸發來源選 CH1,準位轉到波形中間(例如 2.5V)。
  • 方波的角落翹起來或圓圓的 → 探棒沒有補償 → 鉤 Probe Comp 調螺絲。
  • 看直流時畫面停住不動或一片空白 → 觸發模式在 Normal → 改成 Auto。
  • 波形跑出畫面上方 → V/div 太小或位置旋鈕轉太高 → 調大 V/div,用位置旋鈕把基準線往下移。
  • 看到一大片密密麻麻、像一塊顏色 → s/div 太大,幾千個週期擠在畫面上 → 調小 s/div 到一個畫面剩 2~5 個週期。
  • 接上接地夾的瞬間 Arduino 重開或電腦 USB 跳出警告 → 接地夾夾到了不是 GND 的地方,造成短路 → 立刻拔掉探棒,檢查接地夾只夾 GND。
  • 量 Arduino 方波只有 3.3V 高 → 你用的是 ESP32,不是 UNO → 正常,ESP32 是 3.3V。
  • Measure 顯示頻率一直跳動或是「?」 → 畫面上的週期數太少(不到一個)或太多 → 調 s/div 到 2~5 個週期。

想一想

  1. V/div 設 1V,波形從基準線往上跳 4 格。電壓多少?
參考答案

4 × 1V = 4V。

  1. s/div 設 500µs,一個週期占 4 格。週期和頻率各是多少?
參考答案

T = 4 × 500µs = 2000µs = 2ms。f = 1 ÷ 0.002 = 500Hz。

  1. 探棒撥在 10×,示波器的 Probe 設定卻是 1×,畫面上讀到 0.5V。真正的電壓是多少?
參考答案

探棒把訊號縮小了 10 倍,示波器卻沒有乘回來,所以真正的電壓是 0.5 × 10 = 5V。

  1. 你把 CH1 的接地夾夾在 GND,CH2 的接地夾不小心夾在 D9。D9 會發生什麼事?為什麼?
參考答案

兩支探棒的接地夾在示波器內部是連在一起的,所以 D9 會透過示波器直接接到 GND,等於把 D9 短路到 0V。Arduino 的腳位會輸出過大電流,可能重開機或燒壞腳位。

  1. 你想抓住「按一下按鈕」那一瞬間的波形,按鈕只會按一次。觸發模式應該用 Auto、Normal 還是 Single?準位要放哪裡?
參考答案

用 Single(或 Normal)。Auto 會在沒觸發時亂畫,蓋掉你要的畫面。準位放在按鈕按下前後電壓的中間,例如 0V 和 5V 之間的 2.5V,邊緣看你要抓按下(上升或下降,看接法)還是放開。

  1. (開放挑戰)實驗 6-3 用 delay(1) 做出來的 500Hz,用 Measure 量到的是 497Hz。想一想為什麼不是剛好 500Hz?如果想要更接近 500Hz,程式可以怎麼改?(提示:delayMicroseconds() 可以等比 1ms 更短的時間。)
參考答案

每次 loop() 除了兩個 delay(1) 之外,digitalWrite() 和 loop() 本身的跳轉也要花幾微秒,所以一個週期比 2000µs 長一點,頻率就比 500Hz 低一點。可以把 delay(1) 改成 delayMicroseconds(995) 之類的值,一邊看示波器一邊微調,直到 Measure 顯示 500Hz。更準的做法是用 tone(10, 500),但 tone 一次只能用在一支腳位。

本章小結

  • 示波器畫的是「電壓對時間」的圖:橫軸時間、縱軸電壓,螢幕橫 10 格、縱 8 格。
  • 探棒 1×/10× 開關和示波器的 Probe 設定必須一致;本書一律 10×。讀值差 10 倍,先查這個。
  • 第一次用探棒先鉤 Probe Comp 做補償,把方波角落調方正。
  • 接地夾只能夾 GND,所有通道的接地夾內部是相通的。
  • 電壓 = 格數 × V/div,時間 = 格數 × s/div,頻率 = 1 ÷ 週期。
  • 觸發三要素:來源、邊緣、準位;準位要放在波形的高低之間。
  • Auto 看直流與一般訊號、Normal 等事件、Single 抓一次;Run/Stop 可以凍結畫面。
  • 先按 Auto Set 找到波形,再手動微調;用 Measure 讀 Vpp、頻率、週期,用 Cursor 自己量兩點。
  • 兩個通道一起看時,觸發來源選誰,誰就穩住;不同步的訊號會互相漂移。

名詞表

中文英文一句話解釋
示波器Oscilloscope把電壓隨時間的變化畫成圖的儀器
探棒Probe示波器的量測線,前端有鉤子與接地夾
接地夾Ground Clip探棒上的黑色鱷魚夾,只能夾 GND
探棒補償Probe Compensation調整探棒上的小螺絲讓方波角落方正
刻度Division(div)螢幕上的一格
伏特/格V/div縱向每一格代表的電壓
秒/格s/div橫向每一格代表的時間
位置Position把波形上下或左右移動的旋鈕
觸發Trigger決定每次從訊號的哪一瞬間開始畫,讓波形穩定
觸發準位Trigger Level觸發的電壓門檻
邊緣Edge / Slope訊號上升或下降的瞬間
自動模式Auto Mode沒觸發也照畫,適合看直流
一般模式Normal Mode沒觸發就不更新畫面
單次Single只抓一次觸發就停住
自動設定Auto Set讓示波器自動猜設定並顯示波形的按鈕
峰對峰電壓Vpp(Peak-to-Peak)波形最高點減最低點
週期Period(T)波形重複一次所需的時間
頻率Frequency(f)每秒重複幾次,f = 1 ÷ T
自動量測Measure示波器自己算出 Vpp、頻率等數字的功能
游標Cursor兩條可移動的線,用來量兩點之間的時間差或電壓差
耦合CouplingDC 保留直流成分,AC 只留變化的部分
滾動模式Roll Mode看慢速訊號時波形從右往左流動

第 7 章 電感與電磁

本章目標

學完這一章,你會:

  • 用鐵釘和漆包線做出一個電磁鐵,並且說出「電流會生磁」是怎麼回事。
  • 解釋「磁生電」:線圈裡的磁場一變化,線圈兩端就會出現電壓。
  • 說出電感(Inductance)的單位是什麼,以及電感為什麼「討厭電流突然改變」。
  • 用示波器親眼看到關掉線圈的那一瞬間冒出來的高電壓尖波,再用一顆飛輪二極體把它消掉。
  • 說明繼電器和直流馬達裡面是怎麼靠磁力工作的。

開場:為什麼拔插頭會冒火花?

你有沒有注意過,家裡老舊的電風扇或吸塵器,關掉開關的瞬間,有時候會「啪」一聲,甚至看得到開關縫隙裡閃一下小火花?(提醒:那是 110V 的家電,看看就好,千萬不要自己去拆開關!)

更誇張的例子是汽車。汽車的電瓶只有 12V,可是引擎裡的火星塞需要兩萬伏特以上的高壓才能打出火花點燃汽油。12V 是怎麼變成兩萬伏特的?答案不是什麼魔法,而是一個纏得密密麻麻的線圈,加上「突然把電流切斷」這個動作。

前面幾章的電阻、電容都是「乖乖牌」:電壓給多少,電流就流多少。可是線圈有一種「脾氣」:你想讓電流突然停下來,它偏偏要用很高的電壓硬把電流推下去。這個脾氣會弄壞電晶體、讓 Arduino 當機,但也能讓汽車發動、讓馬達轉動、讓繼電器喀喀作響。這一章我們先用鐵釘做電磁鐵,再用示波器把那個「關掉瞬間的尖波」抓出來,最後學會怎麼馴服它。

核心概念

電流會生磁:奧斯特的意外發現

1820 年,丹麥科學家奧斯特(Ørsted)上課時不小心把一條通電的電線放在指南針旁邊,指南針偏掉了;一斷電,又轉回北方。他發現:只要有電流流過導線,導線周圍就會產生磁場(Magnetic Field)。

一條直直的電線產生的磁場很弱。把電線繞成一圈一圈的線圈(Coil),每一圈的磁場會疊在一起變強;再在中間塞一根鐵釘當「鐵心(Core)」,鐵會把磁場集中起來,磁力再強好幾十倍。這就是電磁鐵(Electromagnet)。

電磁鐵的強度大致上跟兩件事成正比:

磁力強度 ∝ 匝數(繞了幾圈) × 電流

工程師把「匝數 × 電流」叫做安培匝數(Ampere-turns)。算一個例子:100 匝的線圈流 0.5 A 的電流,就是 100 × 0.5 = 50 安匝;如果你把線圈繞到 200 匝,電流只要 0.25 A,200 × 0.25 = 50 安匝,磁力差不多一樣強。所以想要省電又有力,就多繞幾圈。

磁生電:法拉第的線圈

既然電能生磁,磁能不能生電?英國的法拉第(Faraday)花了十年才找到答案:能,但有一個條件——磁場必須「正在變化」。

把磁鐵靜靜放在線圈旁邊,什麼事都不會發生;但把磁鐵「推進去」或「抽出來」的那一瞬間,線圈兩端就會冒出一個電壓。推得越快、匝數越多、磁鐵越強,電壓越高。這叫電磁感應(Electromagnetic Induction),產生的電壓叫感應電動勢(Induced EMF)。發電廠的發電機、腳踏車的摩電燈、手機的無線充電,全都是這個原理。

有趣的是,直流馬達和發電機是同一個東西:給馬達電,軸會轉;反過來用手轉軸,兩端就會跑出電壓。實驗 7-2 我們就要用小直流馬達當發電機。

電感:電流的「慣性」

想像一台裝滿貨的超市推車。你想推動它,要用力推一下子才會動起來;你想讓它停,也得用力拉住才停得下來。推車有「慣性」,不喜歡速度突然改變。

線圈對電流就是這樣。線圈裡的電流一變化,磁場就跟著變化;而磁場變化又會在線圈自己身上感應出一個電壓,方向永遠是「反對電流變化」的——電流想變大,它就產生電壓拖住;電流想變小,它就產生電壓硬把電流推下去。這個「反對電流變化」的能力,就叫做電感(Inductance),符號 L,單位是亨利(Henry,H)。

1 H 非常大,常用的是毫亨(mH,千分之一 H)和微亨(µH,百萬分之一 H)。本書器材裡的 100µH 和 1mH 電感,長得像一顆胖胖的電阻,裡面就是繞在小磁心上的線圈。

電感產生的電壓有一條簡單的公式:

V = L × (電流變化量 ÷ 變化花的時間) = L × ΔI / Δt

Δ 念做「delta」,就是「變化量」的意思。這條公式告訴我們:電感越大、電流變化越多、變化得越快,電壓就越高。

算一個例子:一顆 1mH 的電感,電流在 1 毫秒內從 0 升到 1 A。

V = 0.001 H × (1 A ÷ 0.001 s) = 0.001 × 1000 = 1 V

只有 1 V,很溫和。那如果變化得非常快呢?假設一個繼電器線圈的電感是 10mH,裡面流著 0.1 A 的電流,我們用電晶體在 1 微秒(0.000001 秒)內把它切斷:

V = 0.01 H × (0.1 A ÷ 0.000001 s) = 0.01 × 100000 = 1000 V

一千伏特!當然,在真實電路裡電晶體會先被擊穿、線圈本身也有一些漏電的路徑,所以不會真的衝到 1000 V,但幾十伏特是家常便飯。這就是汽車火星塞的祕密,也是為什麼一顆小小的線圈能弄壞 Arduino。

反電動勢與尖波

我們把上面這個「關掉的瞬間,線圈自己產生的高電壓」叫做反電動勢(Back EMF)。「反」是因為它的方向跟原本推動電流的電源相反——電源想讓電流停,它偏要讓電流繼續流。

想像用電晶體當開關接在線圈下面(電源 → 線圈 → 電晶體 → GND)。電晶體一關,電流沒路走了,線圈就把下方那一點(電晶體的集極)的電壓硬往上推,推到遠超過電源電壓,直到電流找到出路為止——可能是電晶體被擊穿,可能是在空氣中跳火花。在示波器上這像一根又細又高的針,所以叫尖波(Spike)。

飛輪二極體:給電流一條回家的路

既然線圈堅持「電流要繼續流」,那我們就給它一條路。在線圈兩端並聯一顆二極體,方向是:陰極(有白色線的那一端)接電源正極,陽極接電晶體那一端。

          +5V
           │
     ┌─────┴─────┐
     │           │
  ┌──┴──┐        ▲   1N4007
  │線圈 │        │   (白線那端朝上,接 +5V)
  └──┬──┘        │
     │           │
     └─────┬─────┘
           │ ← 接電晶體集極

平常電晶體導通時,二極體是「反向」的,根本不導電,就像不存在一樣。但電晶體一關,線圈把下端往上推,推到比 5V 高 0.7V 時,二極體就導通了,電流可以從線圈下端 → 二極體 → 線圈上端繞一圈,在線圈裡慢慢消耗掉。所以集極電壓最高就只會到 5 + 0.7 = 5.7 V 左右,尖波消失。

這顆二極體叫飛輪二極體(Flyback Diode),也叫續流二極體:讓電流像飛輪一樣在圈圈裡慢慢轉到停。本書的安全紅線:只要用電晶體開關馬達、繼電器線圈這類東西,一定要加飛輪二極體。

繼電器:用小電流開關大電流

**繼電器(Relay)**是一個「用電磁鐵去按開關」的裝置。裡面有:

  • 一個線圈(電磁鐵)。
  • 一片可以被吸過去的鐵片(銜鐵)和一根彈簧。
  • 一組金屬接點:共用端(COM)、常開(NO,Normally Open,平常不通)、常閉(NC,Normally Closed,平常是通的)。

線圈通電 → 變成電磁鐵 → 吸住鐵片 → 鐵片把 COM 從 NC 推到 NO,「喀」一聲。線圈斷電 → 彈簧把鐵片拉回來,又「喀」一聲。

5V 繼電器的線圈電阻大約 70Ω,線圈電流大約是 5 ÷ 70 ≈ 0.071 A = 71 mA,比 Arduino 腳位能給的 20 mA 大,所以不能直接用腳位推線圈。本書的「5V 繼電器模組」板子上已經裝好電晶體和飛輪二極體,IN 腳可以直接接 Arduino。也因為模組上已經有二極體,實驗 7-3 看尖波時我們改用小直流馬達——馬達裡面也是線圈。

直流馬達:磁鐵推線圈

小直流馬達裡面有一圈固定的永久磁鐵,中間有一個會轉的線圈(轉子)。線圈通電就變成電磁鐵,被外面的磁鐵一吸一推,就轉了。轉半圈之後吸力方向就不對了,所以馬達裡有一個叫換向器(Commutator)的小銅環和兩片電刷(Brush),每轉半圈就自動把電流方向反過來,馬達才能一直轉下去。

這也解釋了兩件事:電刷不停切換電流,所以馬達會產生很多小雜訊;馬達剛起動還沒轉起來時,電流特別大,可能是正常轉動時的好幾倍。

動手做

實驗 7-1:自製電磁鐵

材料

  • 鐵釘 1 根(長 8–10 公分,越粗越好)
  • 漆包線 2–3 公尺(約 0.3–0.5 mm 粗)
  • 砂紙或美工刀(刮掉漆包線兩端的絕緣漆)
  • 3 號電池盒(裝 2 顆 3 號電池,3V)
  • 按鈕開關 1 個
  • 麵包板、杜邦線
  • 數位三用電表
  • 迴紋針一把(當作被吸的東西)

接線

 電池盒 +(3V)──[ 按鈕 ]──┐
                           │
                     ┌─────┴─────┐
                     │  線圈     │   纏在鐵釘上
                     │ (50~100匝)│
                     └─────┬─────┘
                           │
 電池盒 − ─────────────────┘

  • 電池盒紅線 → 麵包板 → 按鈕一腳。
  • 按鈕另一腳 → 線圈的一端(刮掉漆的部分)。
  • 線圈另一端 → 電池盒黑線。

步驟

  1. 漆包線一端留 10 公分,從釘頭開始一圈緊貼一圈朝釘尖繞 50 圈,繞完也留 10 公分,用膠帶固定。
  2. 用砂紙把兩端各 1 公分的漆刮乾淨,露出亮亮的銅色。這一步沒做好,電流流不過去。
  3. 用三用電表 Ω 檔量線圈兩端電阻,記下來(通常不到 1Ω)。
  4. 照圖接線。線圈電阻很小,幾乎等於把電池短路,所以一定要用按鈕,一次按不超過 5 秒,放開讓它休息再按。
  5. 把釘尖靠近一堆迴紋針,按下按鈕,看能吸起幾個。放開按鈕,迴紋針會不會掉?
  6. 再多繞 50 圈(變成 100 匝),重做步驟 5,比較數量。
  7. 進階:電表切到 10A 直流電流檔,串聯在電池和按鈕之間,按一下讀電流(快快讀完就放開)。

你應該看到

按住按鈕時釘子能吸起好幾個迴紋針;放開後大部分會掉下來(鐵釘留有一點磁性,可能黏住一兩個)。100 匝比 50 匝吸得多。電流大約 1–2 A,受電池內阻限制(第 4 章學過)。線圈和電池會變溫是正常的,但燙到不能摸就馬上拆掉。

觀察與記錄

匝數電池顆數線圈電阻(Ω)電流(A)吸起迴紋針數
502
1002
1003(4.5V)

實驗 7-2:磁生電——馬達當發電機,與法拉第的兩個線圈

材料

  • 小直流馬達(3–6V)1 顆
  • 實驗 7-1 做好的電磁鐵(連同電池盒與按鈕)
  • 漆包線約 1.5 公尺(再繞第二個線圈)
  • 數位三用電表
  • 示波器(1 個通道即可,探棒切 1×)
  • 杜邦線、麵包板

接線(A 部分:馬達發電)

 ┌────────┐
 │ 直流馬達 │──── 紅棒(三用電表 DC V 檔)
 │  (用手轉)│──── 黑棒
 └────────┘
  • 馬達兩隻腳直接接到三用電表的紅、黑棒,電表切到直流電壓 20V 檔(或 2V 檔更靈敏)。

接線(B 部分:法拉第線圈)

                 鐵釘
   ═══════════════════════════════
   ║ 線圈 1(電磁鐵)║ 線圈 2(感應)║
   ═══════════════════════════════
     │         │         │       │
   按鈕+電池   電池−     示波器   示波器
                        CH1 探棒  接地夾

  • 線圈 1 就是實驗 7-1 的電磁鐵,接法不變(電池 → 按鈕 → 線圈 1 → 電池)。
  • 在同一根鐵釘的另一段,再繞 30–50 圈當作線圈 2,兩端刮漆。
  • 線圈 2 一端 → 示波器 CH1 探棒尖端;另一端 → 示波器接地夾。線圈 2 不接電池。

步驟

  1. A 部分:用手指捏住馬達軸,快速一轉,同時看電表讀數。再反方向轉一次。
  2. 試著用更快的速度轉(例如把軸壓在桌面上用力一搓),看電壓能到多高。
  3. B 部分:示波器設定 CH1 為 200 mV/div、時間 10 ms/div,觸發模式選「單次(Single)」,觸發準位設在 +100 mV 左右(詳細設定見「用儀器看看」)。
  4. 按下線圈 1 的按鈕,示波器應該會被觸發,畫面停住,顯示一個小小的電壓波。
  5. 再按一次「Single」準備好,然後放開按鈕,看看這次的波形方向是不是跟剛才相反(如果觸發不到,把觸發邊緣改成「下降」,準位改成 −100 mV)。 你應該看到

A 部分:轉馬達時電表會跳出 0.1–1 V 左右的電壓,反方向轉會變成負的;轉得越快電壓越高,手一停電壓馬上歸零。

B 部分:線圈 2 明明沒接電池,可是當線圈 1 的電流「正在改變」(按下或放開的瞬間)時,示波器會看到一個幾十到幾百 mV 的脈波;按住不放的時候是一條平線。按下去和放開的脈波方向相反。這就是法拉第 1831 年做的實驗。

觀察與記錄

動作電表讀數或示波器波高方向(正/負)
慢慢轉馬達
快速轉馬達
反方向快速轉
按下線圈 1 按鈕(線圈 2 匝數=__)
放開線圈 1 按鈕

實驗 7-3:看見反電動勢尖波,再用飛輪二極體消掉它

這是本章最重要的實驗。我們用 Arduino 透過電晶體把馬達開開關關,用示波器盯著電晶體的集極,看看關掉那一瞬間發生什麼事。

材料

  • Arduino UNO 與 USB 線
  • 2N2222 NPN 電晶體 1 顆
  • 1kΩ 電阻 1 顆
  • 小直流馬達(3–6V)1 顆
  • 1N4007 整流二極體 1 顆
  • 100µF 電解電容 1 顆(選用,讓電源穩一點)
  • 麵包板、杜邦線
  • 示波器(探棒切 10×)

接線

                 Arduino 5V ─────────┬────────────┐
                                     │            │
                                  ┌──┴──┐         │
                                  │ 馬達 │     (第二階段才加)
                                  └──┬──┘      1N4007 ▲ 白線端朝上
                                     │            │
                  CH1 探棒接這裡 ───►├────────────┘
                                     │ C(集極)
  Arduino D9 ──[ 1kΩ ]───────────────┤ B(基極)   2N2222
                                     │ E(射極)
                                     │
                 Arduino GND ────────┴──── 示波器接地夾

  • Arduino D9 → 1kΩ → 2N2222 的 B 腳。
  • 2N2222 的 E 腳 → Arduino GND。
  • 2N2222 的 C 腳 → 馬達一腳;馬達另一腳 → Arduino 5V。
  • 示波器 CH1 探棒尖端 → 2N2222 的 C 腳;接地夾 → Arduino GND。
  • 2N2222 腳位:平的那一面朝向自己,由左到右是 E、B、C(第 9 章會再詳細講)。
  • 第一階段先不要接 1N4007。

程式

// 第 7 章 實驗 7-3:用電晶體開關馬達,觀察反電動勢尖波
const int motorPin = 9;        // D9 接 1kΩ,再接 2N2222 的基極

void setup() {
  pinMode(motorPin, OUTPUT);   // 把 D9 設成輸出腳
  Serial.begin(9600);          // 打開序列埠,確認程式有在跑
  Serial.println("Motor switching started");
}

void loop() {
  digitalWrite(motorPin, HIGH);  // 電晶體導通,馬達開始轉
  delay(100);                    // 轉 100 毫秒

  digitalWrite(motorPin, LOW);   // 電晶體關閉,就在這一瞬間會出現尖波
  delay(100);                    // 停 100 毫秒,然後重來
}

步驟

  1. 照接線圖接好,先不接二極體,確認示波器接地夾夾在 Arduino GND。
  2. 上傳程式。馬達會一下轉一下停,每秒 5 次,聽起來像「噠噠噠」。
  3. 示波器:探棒切到 10× 並在示波器上設定探棒倍率 10×,CH1 先設 2 V/div、時間 50 ms/div、觸發 CH1 上升緣、準位 2.5 V。你會看到集極電壓在 0V 和 5V 之間跳來跳去的方波(馬達轉時集極接近 0V,停時是 5V)。
  4. 仔細看 5V 那一段的開頭(也就是馬達被關掉的瞬間),有沒有一根細細的直線衝出畫面上方?那就是尖波,它可能超過 20V,所以把 V/div 調大到 10 V/div,讓畫面能顯示到 ±40V。
  5. 把觸發準位調到 8 V(比 5V 高,這樣只有尖波會觸發),時間調到 20 µs/div,觸發模式改「一般(Normal)」。現在畫面應該只在尖波出現時更新,你可以清楚看到尖波的形狀。用游標量它的最高點和持續時間,記下來。
  6. 把 Arduino 的 USB 拔掉(斷電),加上 1N4007:白線那一端(陰極)接 Arduino 5V,另一端(陽極)接集極,也就是跟馬達並聯。
  7. 重新接上 USB,示波器設定不變。尖波還在嗎?把觸發準位慢慢降到 6V、5.5V,看看現在集極最高到幾伏。
  8. 把 V/div 調回 2 V/div,再看一次整體波形,比較加二極體前後的差別。

你應該看到

沒有二極體時:每次馬達關掉,集極會瞬間衝出一根 20V 到 40V 以上的尖波(高度跟馬達有關;2N2222 大約在 40–60V 會被擊穿,尖波可能剛好被「削」在那附近),幾微秒到幾十微秒後掉回 5V。5V 那段也會毛毛的,那是電刷切換造成的小雜訊。

加上二極體後:大尖波不見了,集極最高只到約 5.7V(5V + 二極體的 0.7V)。馬達運作看起來一樣,但電晶體從此安全了。

觀察與記錄

情況集極平常的高電位(V)尖波最高電壓(V)尖波持續時間(µs)
沒有二極體
加 1N4007
(進階)把二極體換成 1N4148

如果馬達一起動 Arduino 就重新開機(序列埠一直印出「Motor switching started」),表示 USB 給的電不夠。你可以在 Arduino 5V 與 GND 之間並聯一顆 100µF 電解電容(長腳接 5V),或改用 3 號電池盒(3 顆,4.5V)供電給馬達:電池盒黑線接 Arduino GND,紅線接馬達和二極體的陰極。

用儀器看看

示波器:抓一根只出現幾微秒的尖波

尖波又短又高,正是示波器「觸發」功能大顯身手的時候:

項目設定為什麼
探棒10×尖波可能超過 20V,1× 探棒量程不夠也不安全
接地夾Arduino GND安全紅線,不可以夾在集極或 5V
CH1 V/div先 2 V/div 看整體,再 10 V/div 看尖波10 V/div 時畫面上下共 8 格 = ±40V
s/div先 50 ms/div,再 20 µs/div方波週期 200 ms;尖波只有幾微秒
觸發來源CH1我們只有一個訊號
觸發邊緣上升尖波是往上衝的
觸發準位8 V高於 5V,平常的方波不會觸發,只有尖波會
觸發模式一般(Normal)沒尖波就不更新畫面,畫面才會停住給你看

沒加二極體時的畫面大概像這樣(10 V/div、20 µs/div):

電壓(集極)
 30V ┤                 ╷
     │                 │╲
 20V ┤                 │ ╲
     │                 │  ╲
 10V ┤                 │   ╲
  5V ┤                 │    ╲_________________  ← 馬達關掉後停在 5V
  0V ┼─────────────────┘                        時間
       電晶體導通(≈0.2V)▲
                      關掉的這一瞬間
       ◄──────────────────────►
            每格 20 µs

加了 1N4007 之後(可以切回 2 V/div):

電壓(集極)
  6V ┤                 ┌┐
  5V ┤                 │└──────────────────────  ← 最高只到約 5.7V
  4V ┤                 │
  2V ┤                 │
  0V ┼─────────────────┘                        時間

三用電表:量線圈、量馬達

  • 線圈電阻:Ω 檔量馬達兩腳約 1–10Ω,量自製線圈不到 1Ω。電阻這麼小,所以才需要電晶體或按鈕來控制。
  • 馬達電流:直流電流 10A 檔串聯在馬達與 5V 之間。自由轉動約 100–300 mA;用手指捏住軸讓它變慢,電流會飆高到接近 1A,這就是「堵轉電流」。
  • 感應電壓:三用電表一秒只更新兩三次,實驗 7-2 只能看到一閃而過的數字;想看完整波形要用示波器。

常見錯誤與除錯

  • 電磁鐵完全不吸 → 漆包線兩端的漆沒刮乾淨,或是接點鬆了 → 用電表 Ω 檔從電池盒的接點量到線圈另一端,讀數應該不到 1Ω;如果是 OL(無限大)就是斷路。
  • 實驗 7-2 示波器什麼都沒看到 → 觸發準位設太高,或線圈 2 匝數太少 → 把觸發準位降到 50 mV,V/div 降到 100 mV/div;增加匝數;按快一點。
  • 實驗 7-3 馬達完全不轉 → 電晶體 E、C 接反,或 D9 的杜邦線沒接到 1kΩ → 用電表量 B 腳對 GND,程式 HIGH 時應該約 0.7V;量 C 腳對 GND,HIGH 時應該接近 0V。
  • 看不到尖波 → 你用的是繼電器模組(板子上已經有二極體),或者探棒沒接在集極 → 換成馬達;確認探棒尖端夾在 C 腳。
  • Arduino 一直重開機 → 馬達起動電流太大把 5V 拉垮 → 加 100µF 電容,或改用電池盒給馬達供電(記得共地)。
  • 加了二極體,馬達不轉而且二極體發燙 → 二極體接反了(白線端接到集極)→ 立刻斷電,把二極體轉 180 度。

想一想

1. 想讓實驗 7-1 的電磁鐵吸起更多迴紋針,有哪兩個最直接的方法?各有什麼代價?

參考答案

(1)多繞幾圈(增加匝數):代價是要用更多漆包線、線圈電阻變大一點。(2)加大電流(例如多串一顆電池):代價是線圈和電池更容易發熱,電池也更快沒電。另外換更粗、更長的鐵心也有幫助。

2. 一顆 1mH 的電感流著 0.2 A 的電流,被電晶體在 2 µs 內切斷。用公式算算看,它會產生多高的反電動勢?

參考答案

V = L × ΔI / Δt = 0.001 × (0.2 ÷ 0.000002) = 0.001 × 100000 = 100 V。這就是為什麼一定要加飛輪二極體。

3. 如果你把飛輪二極體接反了(白線那端接到電晶體集極),電晶體一導通會發生什麼事?

參考答案

接反的二極體在電晶體導通時會變成「順向」,等於把 5V 直接經過二極體和電晶體短路到 GND。電流會非常大,二極體或電晶體會發燙甚至燒毀,Arduino 的 5V 會被拉垮而重開機。所以接二極體前一定要再確認白線方向。

4. 為什麼繼電器模組的 IN 腳可以直接接 Arduino 腳位,但是單獨一顆繼電器的線圈不行?

參考答案

繼電器線圈需要大約 70 mA,超過 Arduino 腳位建議的 20 mA;而且線圈關掉時會產生反電動勢尖波。繼電器模組板子上已經裝了電晶體(放大電流)和飛輪二極體(吸收尖波),所以 Arduino 只要給它一個很小的訊號電流就好。

5.(開放挑戰) 老式電鈴的原理是:電磁鐵吸住鐵片 → 鐵片上的小鎚敲到鈴 → 鐵片被吸走的同時剛好把自己的電路切斷 → 電磁鐵失去磁力,彈簧把鐵片拉回 → 電路又接通……一直重複。請用本章的電磁鐵、一片鐵(例如鐵釘或迴紋針)和一根彈性的金屬片,試著畫出一個「自己會斷電」的電鈴設計圖,並說明每一步電流從哪裡流到哪裡。

參考答案

關鍵是把「鐵片本身」當作開關的一部分:電池 + → 彈性金屬片(接觸點 A)→ 固定接點 B → 線圈 → 電池 −。鐵片靜止時 A 碰著 B,電路通,線圈吸鐵片;鐵片一被吸過去,A 離開 B,電路斷,磁力消失,彈簧把鐵片彈回,A 又碰到 B……每來回一次,鐵片上的小鎚就敲一次鈴。這個開關每秒斷開很多次,每次都有一點小火花,那也是反電動勢造成的。

本章小結

  • 電流流過導線會產生磁場;把導線繞成線圈、中間放鐵心,就是電磁鐵。磁力 ∝ 匝數 × 電流。
  • 磁場「變化」時,線圈會感應出電壓,這叫電磁感應。馬達反過來用手轉就是發電機。
  • 線圈抗拒電流變化的能力叫電感 L,單位亨利(H),常用 mH、µH。
  • 電感產生的電壓 V = L × ΔI / Δt:電流變化越快,電壓越高。關掉線圈的瞬間可以產生幾十到幾百伏特的尖波,叫反電動勢。
  • 在線圈兩端並聯一顆飛輪二極體(陰極接電源正極),尖波就會被限制在電源電壓 + 0.7V。開關馬達、繼電器一定要加。
  • 繼電器是用電磁鐵去推開關;5V 繼電器模組已經內建電晶體和二極體。
  • 直流馬達靠換向器每半圈切換電流方向而持續旋轉;起動和堵轉時電流特別大。
  • 示波器抓尖波的訣竅:10× 探棒、V/div 調大、觸發準位比正常電壓高一點、用一般(Normal)觸發模式。

名詞表

中文英文一句話解釋
磁場Magnetic Field磁鐵或電流周圍看不見、但能吸鐵的作用範圍
線圈Coil導線繞成一圈一圈的樣子,能讓磁場疊加變強
電磁鐵Electromagnet通電才有磁力、斷電就沒有的「可開關磁鐵」
鐵心Core塞在線圈中間、把磁場集中起來的鐵塊
安培匝數Ampere-turns匝數 × 電流,用來估計電磁鐵有多強
電磁感應Electromagnetic Induction磁場變化時在線圈裡產生電壓的現象
感應電動勢Induced EMF電磁感應產生的那個電壓
電感Inductance線圈抗拒電流變化的能力,符號 L
亨利Henry(H)電感的單位,常用 mH 和 µH
反電動勢Back EMF電流被切斷時線圈自己產生、方向相反的高電壓
尖波Spike示波器上又細又高、只持續幾微秒的電壓突波
飛輪二極體Flyback Diode並聯在線圈兩端、吸收反電動勢的二極體
繼電器Relay用電磁鐵去推動金屬接點的開關
常開 / 常閉NO / NC繼電器平常不通 / 平常導通的那個接點
換向器Commutator馬達裡每半圈自動反轉電流方向的銅環
電刷Brush馬達裡壓在換向器上、把電送進轉子的金屬片
堵轉電流Stall Current馬達被卡住轉不動時的最大電流

第 8 章 二極體與 LED

本章目標

學完這一章,你會:

  • 說出二極體(Diode)是「只准電流往一個方向走」的元件,並且從外觀認出哪一端是陰極。
  • 知道二極體導通時會「吃掉」一點電壓:1N4007 大約 0.7V,LED 依顏色不同從 1.8V 到 3.4V。
  • 自己算出 LED 該配多大的限流電阻,並用三用電表量出各種顏色 LED 的順向電壓。
  • 用 Arduino 做出一個有正有負的交流訊號,再用二極體把負的那一半切掉——這叫半波整流,你會在示波器上看到整個過程。
  • 說出二極體在電路裡的三種保護用途。

開場:只准進、不准出的門

捷運站的閘門你一定走過:刷卡之後只能往前走,想從出口倒退進站,閘門會擋住你。腳踏車打氣筒的氣嘴也是這樣:空氣只能被打進輪胎,不能從輪胎跑回打氣筒。這種「只開一個方向」的東西叫單向閥。

電路裡也有單向閥,就是這一章的主角:二極體。它長得很不起眼——小小的圓柱,兩隻腳,身上一條線——但它到處都是:手機充電器裡把交流電變成直流電的是它;Arduino 板子上防止電池接反燒掉晶片的是它;上一章保護電晶體的飛輪二極體也是它。

而且你早就用過二極體了:LED 的全名是「發光二極體(Light Emitting Diode)」,它就是一顆會發光的二極體。還記得第 1 章 LED 接反不會亮嗎?那正是單向閥在起作用。

這一章我們要把二極體的脾氣摸清楚:它什麼時候讓電流過、過的時候要收多少「過路費」、關起來的時候能擋多高的電壓,最後用示波器看它把交流電「切」成只剩一半的樣子。

核心概念

單向導通:電的單向閥

二極體有兩隻腳:陽極(Anode)和陰極(Cathode)。電流只能從陽極流進去、從陰極流出來。電路符號是一個三角形加一條直線,三角形的尖端指著電流能流的方向,直線那邊就是陰極:

   陽極 ────►|──── 陰極
          電流只能往這邊 →

實體元件上,陰極那一端會印一條線(1N4007 是黑色身體配一條白線;1N4148 是橘紅色玻璃身體配一條黑線)。記法:符號上的那條直線 = 元件上的那條線 = 陰極。

      1N4007 實體(黑色塑膠)          1N4148 實體(橘紅色玻璃)
   ────┤██████████▌████├────        ────┤▒▒▒▒▒▒▒▒▒▒▒▌▒├────
   陽極            ▲    陰極        陽極            ▲  陰極
                 白線                             黑線
  • 電流從陽極往陰極流:叫順向(Forward),二極體導通,像閘門打開。
  • 電壓反過來加(陰極比陽極高):叫逆向(Reverse),二極體不導通,像閘門關著。

順向壓降:過門要付的「過路費」

二極體不是完美的閘門。電流要通過它,必須在它兩端維持一個最低的電壓,不然門打不開;而且門一旦開了,這個電壓就大致固定住,不太會再變。這個電壓叫順向壓降(Forward Voltage Drop),常寫成 V_F。

元件順向壓降(大約)
1N4007 整流二極體0.6–0.8V,算的時候用 0.7V
1N4148 小訊號二極體0.6–0.7V,電流很小時只有 0.5V 左右
紅色 LED1.8–2.2V
黃色 LED2.0–2.2V
綠色 LED2.0–3.0V(傳統黃綠色偏低,翠綠色偏高)
藍色 / 白色 LED3.0–3.4V

比喻:這就像過收費站,不管你後面要開多遠,過站都要先付一筆固定的費用。電源給 5V,經過一顆 1N4007 之後,剩下給後面電路用的就只有 5 − 0.7 = 4.3V。

算一個例子:5V 電源 → 1N4007 → 1kΩ 電阻 → GND。電阻兩端的電壓是 5 − 0.7 = 4.3V,所以電流是 I = V ÷ R = 4.3 ÷ 1000 = 0.0043 A = 4.3 mA。

逆向:門關著,但門也有極限

逆向時二極體幾乎不導電,只有非常非常小的漏電流(微安等級,電表大多量不到)。但是如果逆向電壓太高,門會被「撞破」,這叫逆向崩潰(Reverse Breakdown)。不同二極體能擋的逆向電壓差很多:

  • 1N4007:能擋 1000V(所以它常用在插座電壓的整流,當然我們本書不碰 110V)。
  • 1N4148:能擋 100V。
  • LED:只能擋大約 5V!所以 LED 不可以用 9V 電池反接,會壞掉。

在我們 12V 以下的世界裡,1N4007 和 1N4148 永遠不會被逆向撞破,但 LED 要小心。

二極體的家族:該用哪一顆?

本書器材有三種二極體,各有擅長:

  • 1N4007 整流二極體:耐得住 1A 的電流和 1000V 的逆向電壓,但是反應慢(從導通切換到關閉要幾微秒)。拿來當飛輪二極體、反接保護、整流大電流都很適合。
  • 1N4148 小訊號二極體:反應非常快(幾奈秒),但只能承受大約 200 mA。拿來處理 Arduino 的高頻訊號、做邏輯保護很適合。本章整流實驗用它,因為訊號是 500Hz 的方波,要快。
  • LED:會發光,順向壓降高,電流不可以超過 20–30 mA,逆向耐壓很低。

LED:會發光的二極體

LED 的腳位:長腳是陽極(+),短腳是陰極(−);燈體邊緣有一個小缺口(平的那一邊)也是陰極那側。

LED 最重要的規則:電流不能太大。一般 5mm LED 最大安全電流是 20 mA,其實 5–10 mA 就已經很亮了。但 LED 一旦導通,它兩端的電壓幾乎固定,自己不會限制電流——你直接把 LED 接在 5V 上,它會因為電流暴衝幾百 mA 而在一秒內燒掉。所以 LED 永遠要串一顆限流電阻。

限流電阻怎麼算?把電源電壓扣掉 LED 的順向壓降,剩下的電壓都落在電阻上,再用歐姆定律:

R = (電源電壓 − V_F) ÷ 想要的電流

例子一:5V 電源,紅色 LED(V_F 用 2.0V),想要 10 mA。

R = (5 − 2.0) ÷ 0.010 = 3 ÷ 0.010 = 300Ω

電阻包裡沒有 300Ω,取最接近且比較大的 330Ω,實際電流是 3 ÷ 330 ≈ 0.0091 A = 9.1 mA。很好。

例子二:同樣 5V 和 220Ω,換成藍色 LED(V_F 用 3.2V)。

I = (5 − 3.2) ÷ 220 = 1.8 ÷ 220 ≈ 0.0082 A = 8.2 mA

比紅色(3 ÷ 220 ≈ 13.6 mA)少了不少。這告訴我們:同樣的電阻,順向壓降越高的 LED 電流越小。

這也解釋了第 3 章一個有趣的現象:如果你把一顆紅色和一顆藍色 LED 並聯,只共用一顆電阻,藍色幾乎不會亮——因為並聯時兩顆的電壓一樣,紅色在 2V 就開門了,電流全部從紅色那邊走,藍色根本等不到它需要的 3V。正確做法是每一顆 LED 各配一顆電阻。

整流:把交流變直流

交流(AC,Alternating Current)是電壓一下正、一下負,來回擺盪的電(第 10 章會更詳細講)。我們的 LED、Arduino 都只吃直流(DC,Direct Current),電壓方向固定。怎麼把交流變直流?用單向閥!

在交流訊號後面串一顆二極體:正半週時二極體順向導通,訊號過得去;負半週時二極體逆向不通,輸出就是 0。結果是只剩下正半週的「半個」波形,這叫半波整流(Half-wave Rectification)。

整流前(交流)                    整流後(半波)
 +V ┤ ┌──┐    ┌──┐               +V ┤ ┌──┐    ┌──┐
    │ │  │    │  │                  │ │  │    │  │
  0 ┼─┘  └─┐  ┘  └─┐    時間      0 ┼─┘  └────┘  └──── 時間
    │      │  │    │                 │   負半週被切掉,變成 0
 −V ┤      └──┘    └──            −V ┤

再進階一點,用四顆二極體排成「橋」,可以把負半週翻上來變成正的,叫全波整流;再並聯一顆大電容把起伏填平,就接近乾淨的直流了。這就是你手機充電器裡做的事。本章先把半波看清楚,電容濾波第 10 章會做。

二極體的保護用途

二極體不只整流,還是電路裡的保全人員:

  1. 反接保護:在電池正極後面串一顆 1N4007,電池接反時二極體不導通,後面的電路一點事都沒有。代價是正常時會損失 0.7V。
  2. 飛輪二極體:第 7 章學過,並聯在馬達、繼電器線圈兩端,吸收反電動勢尖波。
  3. 箝位(Clamp):把二極體接在訊號線和電源之間,訊號電壓一超過電源電壓 + 0.7V 就被二極體導走,保護晶片的輸入腳。很多晶片的腳位內部就內建這種二極體。

七段顯示器(簡介)

把 7 條長條形的 LED 排成一個「8」的形狀(加小數點是 8 顆),就是七段顯示器(Seven-segment Display),電子鐘、計算機上的數字就是它。它裡面的每一段都是一顆獨立的 LED,所以每一段都要配自己的限流電阻,而且分「共陽極」(所有陽極接在一起接電源)和「共陰極」(所有陰極接在一起接 GND)兩種。這個元件不在本書器材裡,先知道它是「一包 LED」就好;以後你拿到一個,就知道該怎麼點亮它。

動手做

實驗 8-1:單向閥測試——二極體正接與反接

材料

  • 1N4007 整流二極體 1 顆
  • 1N4148 小訊號二極體 1 顆
  • 紅色 LED 1 顆
  • 220Ω 電阻 1 顆
  • Arduino UNO(只用它的 5V 和 GND 當電源)或 3 號電池盒(3 顆,4.5V)
  • 麵包板、杜邦線
  • 數位三用電表

接線

 +5V ────►|────[ 220Ω ]────►|──── GND
        1N4007             紅色 LED
      (白線朝右)        (長腳在左)

 量 V1:電表紅棒在 1N4007 左邊、黑棒在右邊
 量 V2:電表跨在 220Ω 兩端
 量 V3:電表跨在 LED 兩端

  • Arduino 5V → 1N4007 陽極(沒有白線那端)。
  • 1N4007 陰極(白線那端)→ 220Ω 一端。
  • 220Ω 另一端 → LED 長腳;LED 短腳 → Arduino GND。

步驟

  1. 照圖接好,接上 Arduino 的 USB 供電。LED 應該會亮。
  2. 電表切到直流電壓 20V 檔,分別量 1N4007 兩端(V1)、220Ω 兩端(V2)、LED 兩端(V3),記下來。
  3. 把三個數字加起來,跟 Arduino 5V 腳對 GND 的電壓比一比(第 3 章的克希荷夫電壓定律:串聯的電壓加起來等於電源電壓)。
  4. 用 V2 算電流:I = V2 ÷ 220。
  5. 拔掉 USB,把 1N4007 轉 180 度再插回去(白線朝左)。接上 USB,LED 還亮嗎?再量一次 V1、V2、V3。
  6. 把 1N4007 換成 1N4148(黑線朝右),正接,再量一次 V1。比較兩種二極體的順向壓降。

你應該看到

正接時 LED 亮,V1 大約 0.6–0.7V,V3 大約 1.8–2.0V,V2 大約 2.3V,三個加起來約等於 5V。電流大約 2.3 ÷ 220 ≈ 0.0105 A = 10.5 mA。

反接時 LED 不亮,V2 和 V3 都接近 0V,而 V1 變成大約 5V(全部的電壓都落在「關著的門」上)——注意電表會顯示負號,因為現在陰極那邊電壓比較高。

1N4148 的順向壓降和 1N4007 差不多,都在 0.6–0.7V 附近,1N4148 可能略高一點點。

觀察與記錄

情況V1 二極體(V)V2 電阻(V)V3 LED(V)V1+V2+V3(V)電流 = V2 ÷ 220(mA)LED 亮嗎
1N4007 正接
1N4007 反接
1N4148 正接

實驗 8-2:LED 順向電壓大賽

材料

  • 紅、綠、藍、白 LED 各 1 顆
  • 220Ω 電阻 1 顆
  • Arduino UNO(5V 與 GND 當電源)
  • 麵包板、杜邦線
  • 數位三用電表

接線

 +5V ────[ 220Ω ]────►|──── GND
                     LED(換不同顏色)

 V_R:電表跨在 220Ω 兩端
 V_LED:電表跨在 LED 兩端(紅棒接長腳)

  • Arduino 5V → 220Ω → LED 長腳;LED 短腳 → GND。

步驟

  1. 先插紅色 LED,接上電源。
  2. 量 LED 兩端電壓 V_LED 和電阻兩端電壓 V_R,算出電流 I = V_R ÷ 220。
  3. 拔掉 USB,換綠色 LED,重複步驟 2。接著換藍色、白色。
  4. 每一顆都觀察亮度,用「暗、普通、亮、很亮」描述(亮度很主觀,沒有標準答案)。
  5. 進階:把電表切到「二極體檔」(符號是 ►|),紅棒接 LED 長腳、黑棒接短腳,看看電表直接顯示的數字(電表會自己送一個小電流進去,顯示的就是順向壓降,LED 會微微發亮)。

你應該看到

紅色約 1.9V、綠色約 2.0–2.8V(看你拿到哪一種綠)、藍色和白色約 3.0–3.2V。電流從紅色的約 13–14 mA 一路降到藍色的約 8 mA,但藍、白 LED 因為本身效率高,看起來可能反而更亮。

用二極體檔量時,紅、綠可以直接讀到壓降;藍色和白色可能顯示「OL」或「1」(超出範圍),因為大多數電表的二極體檔最高只能送到 2–3V,推不開藍光 LED 的門。這不是 LED 壞了。

觀察與記錄

顏色V_LED(V)V_R(V)I = V_R ÷ 220(mA)亮度二極體檔讀數
紅
綠
藍
白

實驗 8-3:半波整流——用示波器看負半週被切掉

Arduino 的 tone() 只能輸出 0V 到 5V 的方波,它「全部都是正的」,沒有負半週,拿來示範整流看不出差別。所以我們先用一顆 10µF 電容把方波「推」成一半正、一半負的交流訊號,再送進二極體。原理回想第 5 章:電容充飽之後,直流過不去,只有「變化」能穿過電容——而方波在不停變化,所以方波的形狀會通過,但它的平均值(直流部分)會被擋掉,結果就是一個上下對稱、中心在 0V 的方波。

材料

  • Arduino UNO 與 USB 線
  • 10µF 電解電容 2 顆(1 顆用來把方波變成交流,1 顆留給進階步驟濾波用)
  • 10kΩ 電阻 1 顆
  • 100kΩ 電阻 1 顆
  • 1N4148 小訊號二極體 1 顆
  • 麵包板、杜邦線
  • 示波器(雙通道,探棒切 1× 或 10× 皆可,記得在示波器上設對)

接線

                        A 點                      B 點
 Arduino D9 ────┤├────┬─────────►|──────────┬──────── 示波器 CH2
  tone()      10µF    │        1N4148       │
         (+ 極接 D9) │      (黑線朝右)    │
                   [ 10kΩ ]              [ 100kΩ ]
                      │                     │
 Arduino GND ─────────┴─────────────────────┴──────── 示波器接地夾
                      ▲
                 示波器 CH1 接 A 點

  • Arduino D9 → 10µF 電解電容的長腳(+);電容短腳(−)→ A 點。
  • A 點 → 10kΩ → GND(這顆電阻讓 A 點有一個「回到 0V 的參考」,不能省)。
  • A 點 → 1N4148 陽極;1N4148 陰極(黑線端)→ B 點。
  • B 點 → 100kΩ → GND。
  • 示波器 CH1 探棒 → A 點;CH2 探棒 → B 點;兩個接地夾都 → Arduino GND。

程式

// 第 8 章 實驗 8-3:用 tone() 產生 500Hz 方波當作訊號源
const int signalPin = 9;     // D9 輸出方波

void setup() {
  tone(signalPin, 500);      // 在 D9 輸出 500 Hz 方波(週期 2 ms),會一直輸出
}

void loop() {
  // 什麼都不用做,tone() 會在背景自己持續輸出
}

步驟

  1. 照圖接好,上傳程式。
  2. 示波器:CH1 與 CH2 都設 1 V/div,耦合(Coupling)都選 DC,時間 500 µs/div,觸發來源 CH1、上升緣、準位 0V。兩個通道的 0V 基準線調到畫面中間(或各自分上下,方便對照)。
  3. 看 CH1(A 點):應該是一個有正有負的方波,大約在 +2.4V 和 −2.6V 之間跳動。它不會剛剛好上下對稱,因為二極體那一邊只在正半週拿電流,沒關係。
  4. 看 CH2(B 點):正半週的時候跟著 CH1 一起往上(但矮了大約 0.5V,那是二極體的過路費),負半週的時候則是一條 0V 的平線。負的一半不見了。
  5. 用游標量 CH1 的最高與最低電壓,以及 CH2 的最高與最低電壓,記下來。
  6. 拔掉 USB,把 1N4148 轉 180 度(黑線朝左)再插回去。接上 USB,看 CH2:現在變成只剩下負半週,正半週變成 0V。這證明二極體的方向決定了哪一半能通過。
  7. 把二極體轉回正接。進階:在 100kΩ 兩端並聯一顆 10µF 電解電容(長腳接 B 點,短腳接 GND)。看 CH2 變成什麼樣子?

你應該看到

步驟 3–4 的畫面大概像這樣:

CH1(A 點,整流前)
 +2V ┤ ┌────┐      ┌────┐      ┌────┐
  0V ┼─┘    │      │    │      │    │
 −2V ┤      └──────┘    └──────┘    └──────  時間
       ◄────────────►
            2 ms(500 Hz)

CH2(B 點,整流後)
 +2V ┤ ┌────┐      ┌────┐      ┌────┐
  0V ┼─┘    └──────┘    └──────┘    └──────  時間
 −2V ┤   ↑ 比 CH1 矮約 0.5V      ↑ 負半週變成 0V

步驟 6 二極體反接後:

CH2(B 點,二極體反接)
 +2V ┤
  0V ┼─┐    ┌──────┐    ┌──────┐    ┌──────  時間
 −2V ┤ └────┘      └────┘      └────┘
         只剩下負半週

步驟 7 加上電容後:CH2 的方波消失,變成一條接近 +1.8V 的直線,只有非常輕微的起伏。因為電容在正半週被充飽,負半週時二極體關著,電容只能透過 100kΩ 慢慢放電(τ = 100kΩ × 10µF = 1 秒,比 2 ms 的週期長太多了,所以幾乎沒掉)。恭喜,你做出了一個把交流變直流的電源!

觀察與記錄

情況CH1 最高(V)CH1 最低(V)CH2 最高(V)CH2 最低(V)
二極體正接
二極體反接
正接 + 100kΩ 並聯 10µF

用儀器看看

三用電表的二極體檔

大部分數位三用電表有一個 ►| 符號的檔位。在這個檔,電表會從紅棒送出大約 1 mA 的小電流,並顯示紅棒到黑棒之間的電壓。

  • 紅棒接陽極、黑棒接陰極:1N4007 顯示約 0.55–0.65,1N4148 約 0.6–0.7,紅色 LED 約 1.7–1.9(而且會微微亮)。
  • 反過來接:顯示 OL 或 1(表示超出範圍,門關著)。
  • 兩個方向都顯示 0.0:二極體短路,壞了。兩個方向都 OL:二極體斷路,也壞了。
  • 藍、白 LED 顯示 OL 不代表壞了,是電表的電壓不夠高。改用實驗 8-2 的方法(220Ω + 5V)來量。

這也是認腳位最快的方法:拿一顆看不清楚線的二極體,兩個方向各量一次,顯示 0.6 的那次,紅棒接的就是陽極。

示波器:看整流

實驗 8-3 的設定整理如下:

項目設定為什麼
CH1、CH2 V/div1 V/div訊號大約 ±2.5V,8 格的畫面放得下
耦合DC我們要看「有沒有負電壓」,AC 耦合會把 0V 線移掉,看不出整流效果
s/div500 µs/div500Hz 的週期是 2 ms,一格半一個週期,畫面約 5 個週期
觸發CH1、上升緣、0V讓每一次掃描都從同一個地方開始,波形才會停住
接地夾兩個都夾 Arduino GND安全紅線

小技巧:把兩個通道的 0V 線對齊在同一個位置,你會一眼看出 CH2 的正半週比 CH1 矮了一截(0.5V 的過路費),而負半週被「切平」在 0V。

常見錯誤與除錯

  • 實驗 8-1 LED 不亮,二極體正接 → 二極體白線方向看錯、LED 長短腳接反,或麵包板同一排沒插在一起 → 用電表二極體檔逐顆確認方向;量 5V 腳確認有電。
  • 實驗 8-2 藍、白 LED 的二極體檔顯示 OL → 電表電壓不夠,不是 LED 壞 → 用 220Ω + 5V 量。
  • 實驗 8-3 CH1 看起來是 0–5V 的方波,沒有負的部分 → CH1 探棒夾到 D9 而不是 A 點,或 10kΩ 沒接 → 確認探棒在電容的另一邊,10kΩ 一端接 A 點一端接 GND。
  • 實驗 8-3 CH1 是一條平線 → tone() 沒跑(程式沒上傳成功)或電容接反壞了 → 先把探棒直接夾 D9 看有沒有方波。
  • 實驗 8-3 CH2 什麼都沒有 → 二極體方向反了而剛好你在看正半週,或 100kΩ 沒接 → 對照圖檢查黑線方向。
  • 示波器波形一直左右跑不停 → 觸發來源不是 CH1 或準位設錯 → 把觸發來源切到 CH1、準位設 0V、模式「自動」。

想一想

1. 用 9V 電池點亮一顆紅色 LED(V_F 用 2.0V),想要 15 mA 的電流,該用多大的電阻?電阻包裡最接近的值是多少?實際電流會是多少?

參考答案

R = (9 − 2.0) ÷ 0.015 = 7 ÷ 0.015 ≈ 467Ω。取 470Ω。實際電流 = 7 ÷ 470 ≈ 0.0149 A ≈ 14.9 mA。

2. 小明把一顆紅色 LED 和一顆藍色 LED 並聯,共用一顆 220Ω 接 5V。結果紅色很亮、藍色幾乎不亮。為什麼?要怎麼改?

參考答案

並聯的兩顆 LED 兩端電壓相同。紅色 LED 在大約 2V 就導通,把電壓「釘」在 2V 附近,藍色 LED 需要 3V 以上才會開門,所以等不到足夠的電壓。改法:每顆 LED 各自串一顆電阻,再分別接到 5V。

3. 實驗 8-3 中,為什麼 CH2 的正半週會比 CH1 矮大約 0.5V?如果把 1N4148 換成紅色 LED,CH2 會變成怎樣?

參考答案

矮掉的那 0.5V 是 1N4148 的順向壓降(電流很小時大約 0.5V)。換成紅色 LED 之後,順向壓降變成約 1.8V,但 A 點正半週最高只有約 2.4V,所以 CH2 的正半週只剩大約 0.6V 高,LED 也只會非常微弱地閃爍(500Hz 太快,看起來像常亮但很暗)。

4. 實驗 8-3 的進階步驟,把 100kΩ 換成 10kΩ,再並聯同一顆 10µF 電容,CH2 的直線會變得比較「平」還是比較「起伏」?為什麼?

參考答案

會比較起伏。τ = 10kΩ × 10µF = 0.1 秒,比原來的 1 秒短 10 倍,所以在負半週(1 ms)的時候電容放電得比較多,電壓掉得比較明顯,直線上會出現看得見的鋸齒。這種起伏叫「漣波」,第 10 章會學怎麼把它濾得更平。

5.(開放挑戰) 設計一個「Arduino 用 9V 電池供電,但就算電池扣接反也不會燒掉」的接法。畫出電路,說明正常使用時 Arduino 的 VIN 腳會拿到幾伏,以及接反時電流往哪裡走。

參考答案

電池 + → 1N4007 陽極;1N4007 陰極(白線端)→ Arduino VIN;電池 − → Arduino GND。正常時 VIN 拿到 9 − 0.7 = 8.3V,Arduino 的穩壓器只要 7V 以上就能正常工作。接反時,電池的正極跑到 GND、負極經過二極體的陰極那端,二極體逆向不導通,所以沒有電流流動,Arduino 什麼事也沒有。(注意:要用 1N4007 而不是 1N4148,因為 Arduino 可能需要超過 200 mA。)

6.(開放挑戰) 用四顆 1N4007 可以做出「全波整流」:不管交流是正半週還是負半週,輸出永遠是正的。查資料或自己想想看這四顆二極體要怎麼排,畫出來,並用箭頭標出正半週和負半週時電流分別走哪條路。然後試著用實驗 8-3 的 A 點當訊號源做做看。

參考答案

四顆二極體排成菱形(橋式整流):交流的兩端接在菱形左右兩個角,輸出的 + 在上角(兩顆二極體的陰極會合處),輸出的 − 在下角(兩顆二極體的陽極會合處)。正半週時電流從左角經右上的二極體到上角 → 負載 → 下角 → 經左下的二極體回右角;負半週時從右角經左上二極體到上角 → 負載 → 下角 → 經右下二極體回左角。兩種情況負載上的電流方向都一樣,所以輸出永遠是正的。注意:橋式整流的輸出 − 不是訊號源的 GND,所以示波器接地夾要夾在輸出的 −,而不能同時夾 Arduino GND,否則會把一顆二極體短路——這個實驗最好用電池盒或馬達發電機當訊號源,比較安全。

本章小結

  • 二極體只讓電流從陽極流向陰極;元件上有線的那端是陰極,對應符號上的直線。
  • 順向導通時有固定的順向壓降:1N4007 / 1N4148 約 0.7V,紅 LED 約 2V,藍白 LED 約 3.2V。
  • 逆向時不導通,但逆向電壓太高會崩潰:1N4007 耐 1000V,1N4148 耐 100V,LED 只耐約 5V。
  • LED 一定要串限流電阻:R = (電源電壓 − V_F) ÷ 電流。不同顏色的 LED 不要共用一顆電阻並聯。
  • 半波整流:交流訊號串一顆二極體,負半週被切掉只剩正半週。二極體反過來接就剩負半週。
  • 整流後並聯一顆電容可以把起伏填平,變成接近直流(τ 要比週期長很多)。
  • 二極體的保護用途:反接保護、飛輪二極體、箝位。
  • 三用電表的二極體檔可以量順向壓降、判斷二極體好壞和腳位;藍白 LED 可能顯示 OL,不是壞掉。

名詞表

中文英文一句話解釋
二極體Diode只讓電流往一個方向流的元件
陽極Anode二極體讓電流「進來」的那一腳(LED 的長腳)
陰極Cathode二極體讓電流「出去」的那一腳,元件上有線的那端
順向Forward電流從陽極往陰極流的方向,二極體導通
逆向Reverse電壓反過來加,二極體不導通
順向壓降Forward Voltage Drop(V_F)二極體導通時兩端固定「吃掉」的電壓
逆向崩潰Reverse Breakdown逆向電壓太高把二極體「撞破」而導通
發光二極體LED(Light Emitting Diode)導通時會發光的二極體
限流電阻Current-limiting Resistor跟 LED 串聯、防止電流太大的電阻
交流AC(Alternating Current)電壓方向一正一負來回變化的電
直流DC(Direct Current)電壓方向固定不變的電
整流Rectification用二極體把交流變成只有一個方向的電
半波整流Half-wave Rectification用一顆二極體只留下交流的一半
全波整流Full-wave Rectification用四顆二極體把兩個半週都變成正的
漣波Ripple整流加電容之後殘留的小起伏
反接保護Reverse Polarity Protection用二極體防止電源接反燒壞電路
箝位Clamp用二極體把電壓限制在某個範圍內
七段顯示器Seven-segment Display用 7 段 LED 排成「8」字形來顯示數字的元件

第 9 章 電晶體

本章目標

學完這一章,你會:

  • 用「小電流控制大電流的水閥」來解釋電晶體(Transistor)在做什麼。
  • 認出 2N2222 的三隻腳 E、B、C,並且畫得出 NPN 電晶體的符號。
  • 自己算出基極電阻要用多大,才能讓電晶體「完全打開」去推動馬達。
  • 用 Arduino 經過電晶體開關一顆馬達,並在示波器上看到集極電壓跟 Arduino 腳位「剛好相反」。
  • 說出 MOSFET IRLZ44N 的 G、D、S 腳,以及它和 2N2222 的差別、什麼時候該用哪一個。

開場:Arduino 推不動馬達

社團裡有一位同學想做一台小風扇。他把小直流馬達一腳接 Arduino 的 D9、另一腳接 GND,程式寫 digitalWrite(9, HIGH)。結果馬達只是「嗡」地抖了一下就不動了,過一會兒 Arduino 的晶片還微微發熱。

問題出在哪?第 4 章我們量過:Arduino 的一隻腳位最多只能給大約 20 mA(硬撐 40 mA 就可能燒掉),可是小馬達起動時要吃幾百 mA。這就像叫一個小學生去推卡車——推不動,還會受傷。

我們需要一個「幫手」:Arduino 只要用一點點電流去「指揮」它,它就能用自己的力氣推動馬達。這個幫手就是電晶體,它是電子世界最重要的元件——你手機裡的晶片,就是幾十億顆電晶體擠在一起。這一章只教它最常用的功能:當開關。學會之後,Arduino 想開馬達、繼電器、LED 燈條,通通沒問題。

核心概念

用小電流控制大電流:水閥比喻

想像一條粗大的水管,中間裝了一個閥門。這個閥門很特別:它不是用手轉的,而是旁邊有一根細細的小水管,只要小水管裡有一點點水流進來推動閥門,大水管的閥門就會打開,讓大量的水通過。小水管的水越多,大閥門開得越大;小水管沒水,大閥門就關起來。

電晶體就是這樣的閥門:

  • 大水管 = 從集極(C)流到射極(E)的大電流,我們叫它集極電流 I_C。
  • 小水管 = 從基極(B)流到射極(E)的小電流,叫基極電流 I_B。
  • 規則:I_C 大約等於 β × I_B,β(念「beta」)叫電流放大倍數,2N2222 的 β 大約在 100 到 300 之間。

換句話說,Arduino 只要送 1 mA 的小電流進基極,電晶體就可以讓 100 mA 以上的大電流從集極流到射極。這就是「用小電流控制大電流」。

NPN 電晶體的三隻腳:E、B、C

本書用的 2N2222 是一顆 NPN 電晶體(還有另一種叫 PNP,方向相反,本書不用)。它是黑色半圓柱的塑膠包裝,一面是平的、印著字。把平的那一面朝向自己,腳朝下,由左到右是 E、B、C:

          ┌─────────┐
          │  2N2222 │   ← 平面(印字那一面)朝向自己
          │         │
          └─┬──┬──┬─┘
            │  │  │
            E  B  C
           射極 基極 集極
       (Emitter)(Base)(Collector)

注意:有些 2N2222 是金屬圓罐包裝(TO-18),腳位排法不同。本書假設你拿到的是黑色塑膠包裝(TO-92)。拿到不確定的元件,就用三用電表的二極體檔確認(見「用儀器看看」)。

電路符號長這樣,記法:箭頭在射極上,NPN 的箭頭朝外:

            C(集極)
            │
            │
     B ─────┤
    (基極)  │╲
            │ ╲
            │  ▼
            E(射極)

三隻腳的分工:

  • 基極 B:控制腳。小電流從這裡進來。
  • 集極 C:大電流從這裡進來(「收集」電流)。
  • 射極 E:大電流和小電流都從這裡出去(「射出」電流),接 GND。

基極和射極之間其實就像一顆二極體:要讓電流流進基極,B 要比 E 高大約 0.7V,這個 0.7V 跟上一章的二極體壓降是同一回事,我們寫成 V_BE ≈ 0.7V。

放大倍數 β 與「飽和」:把閥門開到底

既然 I_C = β × I_B,那是不是 I_B 越大,I_C 就可以無限大?當然不行。集極電流最多能流多少,是由外面的電路決定的:例如 5V 電源接一顆馬達,馬達轉動時只需要 200 mA,電晶體再怎麼開,也只能流 200 mA——因為水管就那麼粗。

這時候我們說電晶體**飽和(Saturation)**了:閥門已經開到底,集極和射極之間幾乎短路,只剩大約 0.1–0.3V 的壓降(叫 V_CE(sat))。這是當開關時最理想的狀態:電壓很小 × 電流 → 功率很小 → 電晶體不發熱。

相反地,如果基極電流不夠,閥門只開一半,馬達拿不到足夠的電流(轉得慢或不轉),而且集極和射極之間會落下好幾伏特——例如 2.5V × 0.2A = 0.5W,一顆小小的 2N2222 最多只能承受大約 0.5W,它會變得很燙。

結論:當開關用時,一定要給足夠的基極電流,讓電晶體飽和。 寧可多給一點,也不要剛剛好。

基極電阻怎麼算

Arduino 腳位輸出 HIGH 是 5V,基極對 GND 是 0.7V,所以中間那顆基極電阻 R_B 兩端的電壓是 5 − 0.7 = 4.3V。基極電流就是:

I_B = (5V − 0.7V) ÷ R_B

本書的標準接法是 R_B = 1kΩ:

I_B = 4.3 ÷ 1000 = 0.0043 A = 4.3 mA

β 保守取 100(規格書上的最低值),那電晶體最多可以讓多少集極電流通過?

I_C(最大) = β × I_B = 100 × 4.3 mA = 430 mA

也就是說,只要負載需要的電流在 430 mA 以內,電晶體都會乖乖飽和。我們的小馬達 100–300 mA、繼電器線圈 70 mA、蜂鳴器 30 mA 都在範圍內,所以 1kΩ 可以用。而 4.3 mA 對 Arduino 腳位來說也只是 20 mA 上限的五分之一,很安全。

反過來看,如果有人隨手拿了 100kΩ 當基極電阻:

I_B = 4.3 ÷ 100000 = 0.000043 A = 43 µA → I_C(最大) = 100 × 43 µA = 4.3 mA

4.3 mA 連 LED 都只能點到微亮,馬達完全不會動,而且電晶體會因為沒飽和而發熱。所以基極電阻不是越大越省電,要算。

一個常用的簡單規則:算出來需要的 I_B 再乘 2 到 5 倍,確保飽和。

電晶體當開關:低邊開關的標準接法

本書所有「用 Arduino 開關某個東西」都用同一種接法,叫低邊開關(Low-side Switch),因為電晶體接在負載的「下面」(GND 那一邊):

                 +5V
                  │
              ┌───┴───┐
              │ 負載  │  (馬達、繼電器線圈、蜂鳴器、LED+電阻……)
              └───┬───┘   如果是馬達或線圈,要並聯 1N4007,白線朝上
                  │ C
 Arduino 腳位 ──[ R_B ]──┤ B   2N2222
                  │ E
                  │
                 GND(和 Arduino 共地)

四個重點:

  1. 負載接在 +5V 和 C 之間。
  2. E 接 GND,而且一定要跟 Arduino 的 GND 接在一起(共地),不然基極電流沒有回路。
  3. 基極電阻 1kΩ 不能省:沒有它,Arduino 會直接把 5V 灌進 0.7V 的 B-E 二極體,電流暴衝,腳位燒掉。
  4. 馬達、繼電器線圈這種「有線圈」的負載,一定要並聯飛輪二極體(第 7 章)。

MOSFET:用電壓控制的開關

2N2222 很好用,但它有兩個小缺點:需要「餵」基極電流、飽和時還有 0.1–0.3V 的壓降(電流大時會發熱)。要推動 1A 以上的東西,我們改用另一種電晶體:MOSFET(金氧半場效電晶體)。本書用的是 N 通道的 IRLZ44N。

MOSFET 也有三隻腳,名字不同:

  • 閘極 G(Gate):控制腳,對應 BJT 的 B。
  • 汲極 D(Drain):大電流流入,對應 C。
  • 源極 S(Source):大電流流出,對應 E,接 GND。

IRLZ44N 是比較大顆的 TO-220 包裝,背面有一片金屬散熱片。印字那面朝向自己,腳朝下,由左到右是 G、D、S:

          ┌───────────┐
          │     ○     │  ← 金屬散熱片的鎖孔(散熱片和 D 腳是相通的!)
          │  IRLZ44N  │     印字那一面朝向自己
          │           │
          └─┬───┬───┬─┘
            │   │   │
            G   D   S
          閘極  汲極  源極
      (Gate)(Drain)(Source)

MOSFET 和 2N2222 最大的差別是:它靠電壓控制,不靠電流。 閘極像是一個電容,你只要把它充到夠高的電壓(IRLZ44N 大約 2V 就開始導通,5V 就完全打開),它就開了,之後幾乎不吃電流。而且它打開之後,D 和 S 之間就像一條電阻只有 0.022Ω 的電線,叫 R_DS(on)。

算一個例子:流 1A 的電流,IRLZ44N 兩端的壓降是 1 × 0.022 = 0.022V,發熱功率 = 0.022V × 1A = 0.022W,幾乎不熱。同樣 1A 給 2N2222,它根本撐不住(最大 800 mA),就算撐住也有 0.3V × 1A = 0.3W。

IRLZ44N 標準接法:

                 +5V
                  │
              ┌───┴───┐
              │ 負載  │   馬達要並聯 1N4007,白線朝上
              └───┬───┘
                  │ D
 Arduino 腳位 ──[ 220Ω ]──┬──┤ G   IRLZ44N
                      │   │ S
                  [ 10kΩ ]│
                      │   │
                     GND ─┴── GND
  • 220Ω:閘極像電容,剛開關時會有一瞬間的充電電流,這顆電阻讓它溫和一點。
  • 10kΩ 接到 GND:叫下拉電阻。Arduino 還沒開機或腳位沒設定時,閘極會「飄」在空中,MOSFET 可能自己亂開;10kΩ 把它拉在 0V,確保平常是關的。
  • 注意 IRLZ44N 的名字裡有「L」,代表 Logic-level(邏輯準位),5V 就能完全打開。一般的 IRFZ44N(沒有 L)需要 10V,Arduino 推不動,買的時候要看清楚。

達靈頓:兩個電晶體手牽手

如果一顆電晶體放大 100 倍不夠,可以把兩顆接在一起:第一顆的射極接到第二顆的基極,兩顆的集極接在一起。這樣第一顆放大 100 倍、第二顆再放大 100 倍,總共 100 × 100 = 10000 倍!這種接法叫達靈頓(Darlington)。

              C(共用)
          ┌───┴───┐
          │       │ C
   B ─────┤ Q1    │
          │╲      │
          ▼ E ────┤ B   Q2
                  │╲
                  ▼ E
                  │
                 GND

代價是:基極要比射極高兩個 0.7V(1.4V)才會導通,而且飽和壓降也變高(約 0.9V)。實驗 9-1 我們會用達靈頓做一個「手指碰一下就亮」的觸控開關。

動手做

實驗 9-1:用小電流點亮 LED,再做手指觸控開關

材料

  • 2N2222 NPN 電晶體 2 顆
  • 紅色 LED 1 顆
  • 220Ω 電阻 1 顆
  • 10kΩ 電阻 1 顆、100kΩ 電阻 1 顆
  • 按鈕開關 1 個
  • Arduino UNO(只用 5V 與 GND 當電源)
  • 麵包板、杜邦線
  • 數位三用電表

接線(第一階段:單顆電晶體)

 +5V ──[ 220Ω ]──►|───────┐
                 LED      │ C
 +5V ──[ 按鈕 ]──[ 10kΩ ]──┤ B   2N2222
                          │ E
                          │
                         GND

  • Arduino 5V → 220Ω → LED 長腳;LED 短腳 → 2N2222 的 C。
  • Arduino 5V → 按鈕一腳;按鈕另一腳 → 10kΩ → 2N2222 的 B。
  • 2N2222 的 E → GND。

步驟

  1. 照圖接好。沒按按鈕時,LED 應該不亮(基極沒電流,閥門關著)。
  2. 按住按鈕,LED 亮。按住的同時用電表量:B 對 GND 的電壓(V_BE)、C 對 GND 的電壓(V_CE)、10kΩ 兩端的電壓(用來算 I_B = 電壓 ÷ 10000)、220Ω 兩端的電壓(用來算 I_C = 電壓 ÷ 220)。
  3. 把 10kΩ 換成 100kΩ,重做步驟 2。LED 有沒有變暗?V_CE 有沒有變高?
  4. 把 100kΩ 和按鈕都拔掉,改成:一根杜邦線接 5V、另一根接 B,兩根線的另一端都露出來。用兩隻手指分別捏住兩根線的金屬部分(可以先把手指沾濕一點),看 LED 有沒有反應。你的身體電阻大概是幾十萬到幾百萬 Ω,現在它就是基極電阻。
  5. 第二階段:加第二顆 2N2222 做達靈頓。接線改成:
 +5V ──[ 220Ω ]──►|───────┬─────────┐
                 LED      │ C       │ C
 杜邦線(手指)──────────────┤ B  Q1   │
                          │ E       │
                          └─────────┤ B  Q2
                                    │ E
                                    │
                                   GND

  • Q1 的 C 和 Q2 的 C 接在一起 → LED 短腳。
  • Q1 的 E → Q2 的 B。
  • Q2 的 E → GND。
  • 手指的杜邦線接 Q1 的 B(另一根還是接 5V)。
  1. 再用手指捏住兩根線,比較 LED 的亮度跟步驟 4 差多少。

你應該看到

第一階段用 10kΩ:LED 正常亮。V_BE 約 0.7V,V_CE 約 0.05–0.2V(飽和),10kΩ 兩端約 4.3V → I_B ≈ 0.43 mA,220Ω 兩端約 2.9V → I_C ≈ 13 mA。你會發現 I_C ÷ I_B ≈ 30,比 β 小很多——這很正常,因為電晶體已經飽和,集極電流被 220Ω 限制住了,閥門開到底也只能流這麼多。

換成 100kΩ:I_B 只剩約 43 µA,β 取 100 的話最多只能供 4.3 mA。LED 可能變暗一點,也可能還是亮(因為你拿到的那顆 β 可能有 200 以上),但 V_CE 會明顯變高。

手指當電阻:單顆電晶體時 LED 可能只有一點點微光,甚至看不出來。換成達靈頓之後,手指一碰 LED 就清楚地亮起來,因為放大倍數變成一萬倍。恭喜你做出了觸控開關!(整個電路只有 5V,手指碰完全安全。)

觀察與記錄

情況V_BE(V)V_CE(V)I_B(mA)I_C(mA)LED 亮度
10kΩ 基極電阻
100kΩ 基極電阻
手指(單顆)————
手指(達靈頓)————

實驗 9-2:Arduino 經電晶體開關馬達,示波器看集極反相

材料

  • Arduino UNO 與 USB 線
  • 2N2222 NPN 電晶體 1 顆
  • 1kΩ 電阻 1 顆
  • 小直流馬達(3–6V)1 顆
  • 1N4007 整流二極體 1 顆
  • 100µF 電解電容 1 顆(選用)
  • 麵包板、杜邦線
  • 示波器(雙通道,探棒切 10×)
  • 數位三用電表

接線

                Arduino 5V ──────────┬───────────┐
                                     │           │
                                  ┌──┴──┐        │
                                  │ 馬達 │     1N4007 ▲ 白線端朝上(接 5V)
                                  └──┬──┘        │
                                     │           │
                  CH2 探棒接這裡 ───►├───────────┘
                                     │ C
  Arduino D9 ──┬──[ 1kΩ ]────────────┤ B   2N2222
               │                     │ E
   CH1 探棒接這裡                     │
                Arduino GND ─────────┴──── 兩個接地夾都夾這裡

  • Arduino D9 → 1kΩ → 2N2222 的 B。
  • 2N2222 的 E → Arduino GND。
  • 2N2222 的 C → 馬達一腳;馬達另一腳 → Arduino 5V。
  • 1N4007 並聯在馬達兩端:白線端(陰極)→ 5V,另一端(陽極)→ C。
  • 示波器 CH1 探棒 → D9(可以夾在 1kΩ 靠 D9 那一端);CH2 探棒 → C 腳;兩個接地夾 → Arduino GND。

程式

// 第 9 章 實驗 9-2:Arduino 經 2N2222 開關直流馬達
const int motorPin = 9;          // D9 → 1kΩ → 2N2222 基極
const int onTime = 500;          // 馬達轉幾毫秒(看示波器時可以改成 50)
const int offTime = 500;         // 馬達停幾毫秒

void setup() {
  pinMode(motorPin, OUTPUT);     // D9 設為輸出
  Serial.begin(9600);            // 打開序列埠回報狀態
}

void loop() {
  digitalWrite(motorPin, HIGH);  // D9 = 5V,基極有電流,電晶體導通,馬達轉
  Serial.println("Motor ON");    // 在序列埠印出狀態
  delay(onTime);

  digitalWrite(motorPin, LOW);   // D9 = 0V,基極沒電流,電晶體關閉,馬達停
  Serial.println("Motor OFF");
  delay(offTime);
}

步驟

  1. 照圖接好,再三確認 1N4007 白線朝 5V、2N2222 的 E 接 GND,然後上傳程式。
  2. 馬達應該轉半秒、停半秒。打開序列埠監控視窗(9600),應該看到 Motor ON / Motor OFF 交替。
  3. 在馬達轉的時候(程式印 ON 的那半秒),用電表量:1kΩ 兩端電壓(算 I_B)、B 對 GND(V_BE)、C 對 GND(V_CE)。因為每半秒切換一次,電表數字會跳,你可以暫時把程式的 onTime 改成 5000 讓它多轉一會兒再量。
  4. 把電表切到直流電流 10A 檔,串聯在 5V 和馬達之間,量馬達轉動時的電流 I_C。算一下 I_C 有沒有小於 β × I_B = 100 × I_B。
  5. 示波器:CH1、CH2 都設 2 V/div,時間 200 ms/div,觸發來源 CH1、上升緣、準位 2.5V,模式「自動」。把 CH1 的 0V 線放在畫面上半部、CH2 的 0V 線放在下半部。
  6. 觀察兩個通道:CH1 是 D9 的 0V/5V 方波;CH2 是集極的電壓。D9 是 HIGH 的時候,集極是幾伏?D9 是 LOW 的時候呢?
  7. 把時間調到 20 µs/div,觸發改成 CH2、上升緣、準位 5.5V、模式「一般」,看看馬達關掉的瞬間,集極有沒有一個小小的凸起(被二極體限制在約 5.7V)。如果你把二極體拔掉再看——第 7 章的尖波會回來。看完記得裝回去。

你應該看到

電表:1kΩ 兩端約 4.3V → I_B ≈ 4.3 mA;V_BE ≈ 0.7V;V_CE ≈ 0.1–0.3V(飽和)。馬達電流大約 100–300 mA,小於 430 mA,所以電晶體確實飽和了。

示波器:兩個波形剛好相反。 D9 是 5V(HIGH)時,電晶體導通,集極被拉到接近 0V;D9 是 0V(LOW)時,電晶體關閉,集極被馬達拉到 5V。這叫反相(Inverting)。

CH1(D9)
  5V ┤      ┌────────┐        ┌────────┐
  0V ┼──────┘        └────────┘        └──────  時間

CH2(集極)
  5V ┤──────┐        ┌────────┐        ┌──────
  0V ┼      └────────┘        └────────┘        ← 剛好相反
         馬達停       馬達轉      馬達停   馬達轉

在 20 µs/div 下,CH2 上升的那一瞬間會有一個小凸起到約 5.7V,然後落回 5V,那就是被飛輪二極體剪過的反電動勢。

觀察與記錄

量測項目讀數
1kΩ 兩端電壓(V)
I_B = 1kΩ 電壓 ÷ 1000(mA)
V_BE(V)
V_CE 馬達轉時(V)
馬達電流 I_C(mA)
β × I_B(取 β = 100)(mA)
有飽和嗎?(I_C < β × I_B)
示波器:D9 = 5V 時集極電壓(V)
示波器:D9 = 0V 時集極電壓(V)

替換玩法:把馬達換成無源蜂鳴器,程式改用 tone(motorPin, 440) 與 noTone(motorPin) 交替,就有一個用電晶體推動、更大聲的蜂鳴器。

實驗 9-3:換成 MOSFET IRLZ44N

材料

  • 實驗 9-2 的全部材料(2N2222 換下來)
  • IRLZ44N MOSFET 1 顆
  • 220Ω 電阻 1 顆、10kΩ 電阻 1 顆

接線

                Arduino 5V ──────────┬───────────┐
                                     │           │
                                  ┌──┴──┐        │
                                  │ 馬達 │     1N4007 ▲ 白線端朝上
                                  └──┬──┘        │
                                     │           │
                  CH2 探棒接這裡 ───►├───────────┘
                                     │ D
  Arduino D9 ──┬──[ 220Ω ]──┬────────┤ G   IRLZ44N
               │            │        │ S
   CH1 探棒接這裡        [ 10kΩ ]     │
                            │        │
                Arduino GND ┴────────┴──── 接地夾

  • Arduino D9 → 220Ω → IRLZ44N 的 G。
  • G → 10kΩ → GND。
  • IRLZ44N 的 S → GND;D → 馬達一腳;馬達另一腳 → 5V。
  • 1N4007 並聯馬達,白線端接 5V。
  • 示波器 CH1 → D9,CH2 → D 腳,接地夾 → GND。
  • 小心 IRLZ44N 背面的金屬片和 D 腳相通,不要讓它碰到別的線。

步驟

  1. 用和實驗 9-2 完全相同的程式。
  2. 馬達轉的時候量 D 對 GND 的電壓(V_DS),跟 9-2 的 V_CE 比較。
  3. 量 G 對 GND 的電壓,以及 220Ω 兩端的電壓(算閘極電流)。
  4. 示波器看 CH1 和 CH2,應該和 9-2 一樣是反相的方波。
  5. 把 10kΩ 拔掉,拔掉 Arduino 的 USB 再插回去,在程式開始跑之前的那一瞬間,馬達有沒有自己抖一下?(這就是閘極「飄」在空中的後果。)看完把 10kΩ 裝回去。

你應該看到

V_DS 幾乎是 0.00V(電表可能顯示 0.00 或 0.01V),比 2N2222 的 0.1–0.3V 低很多。220Ω 兩端電壓是 0V——MOSFET 穩定導通後閘極完全不吃電流(10kΩ 那邊會流 5 ÷ 10000 = 0.5 mA,那是下拉電阻的,不是閘極的)。示波器上一樣是反相。

觀察與記錄

比較項目2N2222(實驗 9-2)IRLZ44N(實驗 9-3)
控制腳對 GND 電壓(V_BE / V_GS)
控制腳電流(I_B / I_G)
導通時負載端對 GND 電壓(V_CE / V_DS)
摸起來的溫度
示波器 CH2 是否反相

用儀器看看

示波器:雙通道看反相

這是本書第一次正式用兩個通道同時看「輸入」和「輸出」,設定重點:

項目設定為什麼
探棒兩支都 10×集極可能有短暫的尖波,10× 比較安全
接地夾兩個都夾 Arduino GND兩個通道的接地夾在示波器裡面是連通的,夾不同地方會短路
CH1 / CH2 V/div2 V/div0–5V 的方波,約占 2.5 格
兩通道 0V 位置CH1 放上半部、CH2 放下半部兩個波形分開看,才看得出上下相反
s/div200 ms/div程式每 500 ms 切換一次,畫面可以看到兩個週期
觸發CH1、上升緣、2.5V、自動以 Arduino 的輸出當基準
看尖波時20 µs/div,觸發 CH2、5.5V、一般跟第 7 章一樣的技巧

很多示波器有「數學(Math)」功能可以把 CH1 和 CH2 相加或相減,可以試試看 CH1 + CH2:導通和關閉時都接近 5V,因為兩個波形互補。

三用電表:認腳位、量 β

用二極體檔認 2N2222 的腳位:B-E 和 B-C 之間都像一顆二極體。把電表切到二極體檔,紅棒固定在中間那隻腳(B),黑棒分別碰左右兩隻腳:兩邊都應該顯示 0.6–0.7V(黑棒碰 E 那邊會略高一點點,例如 0.68 對 0.65)。紅黑對調後兩邊都應該是 OL。如果中間腳不符合這個規律,表示你拿到的不是 E-B-C 排法,要查規格書。

量 β:有些三用電表有「hFE」檔和一個小插座,標著 E、B、C。把 2N2222 依照腳位插進去(NPN 那一側),電表會直接顯示 β 值,通常在 100–300 之間。同一包裡的兩顆 2N2222 可能差很多,這就是為什麼設計時 β 要保守取 100。

量 MOSFET 有沒有壞:IRLZ44N 的 D-S 之間內建一顆二極體(方向是 S → D)。二極體檔紅棒碰 S、黑棒碰 D 會顯示約 0.5V;反過來應該是 OL。如果兩個方向都是 0,MOSFET 已經短路燒掉了。

常見錯誤與除錯

  • 馬達完全不轉,電晶體不熱 → D9 的線沒接到 1kΩ,或 E、C 接反(接反時 β 只剩個位數,幾乎推不動)→ 量 B 對 GND,HIGH 時應有 0.7V;確認平面朝自己由左到右 E-B-C。
  • 馬達轉很慢,電晶體很燙 → 基極電阻太大沒飽和,或馬達被卡住電流過大 → 量 V_CE,超過 0.5V 就是沒飽和;確認用 1kΩ;用手撥一下馬達看會不會卡。
  • Arduino 一直重開(序列埠反覆印出開頭的訊息) → 馬達起動電流把 USB 的 5V 拉垮 → 在 5V 和 GND 之間加 100µF 電解電容;或用 3 號電池盒(3 顆)供電給馬達,電池盒黑線接 Arduino GND,紅線接馬達和二極體陰極。
  • 馬達一直轉,不受 Arduino 控制 → 2N2222 的 C、E 短路燒壞了(可能是之前沒接二極體被尖波打壞),或 MOSFET 的閘極沒有 10kΩ 下拉 → 換一顆電晶體;裝上下拉電阻。
  • 示波器 CH2 看起來跟 CH1 一樣,不是反相 → CH2 探棒夾到 D9 那一排,或夾到 5V → 確認探棒尖端在 C 腳(麵包板上跟馬達同一排)。
  • 一碰電路,Arduino 的 5V 就掉到 3V 以下 → 1N4007 接反了,電晶體一導通就把 5V 短路 → 立刻拔 USB,把二極體轉 180 度。
  • IRLZ44N 一插上去就很燙 → D-S 接反或散熱片碰到別的導線 → 斷電檢查;確認 G-D-S 由左到右,印字面朝自己。

想一想

1. 如果基極電阻改用 4.7kΩ,I_B 是多少?β 取 100 的話,最多能讓多少集極電流飽和?這樣可以推 LED(約 10 mA)嗎?可以推馬達(約 200 mA)嗎?

參考答案

I_B = (5 − 0.7) ÷ 4700 = 4.3 ÷ 4700 ≈ 0.000915 A ≈ 0.92 mA。I_C(最大) = 100 × 0.92 ≈ 92 mA。推 LED 綽綽有餘;推 200 mA 的馬達不夠,電晶體不會飽和,會發熱。所以推馬達還是用 1kΩ。

2. 實驗 9-1 用手指當基極電阻,假設你的手指電阻是 1MΩ。單顆 2N2222(β = 100)時,集極電流最多多少?換成達靈頓(β = 10000,V_BE 用 1.4V)呢?

參考答案

單顆:I_B = (5 − 0.7) ÷ 1000000 = 4.3 µA,I_C(最大) = 100 × 4.3 µA = 0.43 mA,LED 只會非常微弱地亮。達靈頓:I_B = (5 − 1.4) ÷ 1000000 = 3.6 µA,I_C(最大) = 10000 × 3.6 µA = 36 mA,已經超過 LED 電路本身(220Ω 限制約 13 mA)需要的電流,所以 LED 會全亮。

3. 為什麼飛輪二極體的白線端一定要接 5V 那邊,而不是接集極那邊?用「平常」和「關掉的瞬間」兩種情況說明。

參考答案

白線(陰極)接 5V 時,平常電晶體導通,二極體兩端是 5V 對 0.2V,是逆向的,不導電,不影響馬達。關掉瞬間,馬達線圈把集極推到高於 5.7V,二極體變成順向導通,把能量繞回去,集極就被限制在 5.7V。如果接反(陰極接集極),平常電晶體一導通,二極體就是順向,5V 直接經過二極體和電晶體短路到 GND,電流暴衝,會燒掉元件。

4. 第 17 章的「Wi-Fi 遙控風扇」要推一顆會吃 1A 的風扇。該用 2N2222 還是 IRLZ44N?請給兩個理由。

參考答案

用 IRLZ44N。理由一:2N2222 最大集極電流只有 800 mA,1A 會超過;IRLZ44N 可以到幾十安培。理由二:2N2222 要飽和 1A 需要 I_B 至少 10 mA(β = 100 時),接近 Arduino 腳位上限,而且飽和壓降 0.3V × 1A = 0.3W 會發熱;IRLZ44N 閘極幾乎不吃電流,R_DS(on) 只有 0.022Ω,1A 時只有 0.022W,幾乎不熱。

5.(開放挑戰) 第 7 章說繼電器模組的板子上已經有電晶體和二極體。請根據本章學到的低邊開關接法,畫出你猜想的繼電器模組內部電路(IN 腳、電晶體、基極電阻、線圈、飛輪二極體、VCC、GND),並說明當 IN 接 HIGH 時電流怎麼走。

參考答案

IN → 基極電阻(約 1kΩ)→ NPN 電晶體 B;E → GND;C → 繼電器線圈一端;線圈另一端 → VCC(5V);1N4007 並聯線圈,陰極接 VCC。IN 為 HIGH 時,基極電流流進 B,電晶體導通,電流從 VCC → 線圈 → C → E → GND,線圈變成電磁鐵吸住接點。IN 為 LOW 時電晶體關閉,線圈的反電動勢經二極體繞回去。(實際模組很多會再加一顆 LED 指示燈,有些則用 PNP 或光耦合器做成「LOW 才動作」的版本,所以用之前要看模組說明。)

6.(開放挑戰) 不用 Arduino,只用光敏電阻(LDR)、電阻、2N2222、LED 和 5V,設計一個「天黑自動亮燈」。提示:第 3 章的分壓器可以把「亮度」變成「電壓」,而電晶體在 B 大約 0.7V 時會開始導通。畫出電路並說明亮和暗的時候 B 腳電壓怎麼變。

參考答案

一種做法:5V → 10kΩ → B 腳節點 → LDR → GND(10kΩ 在上、LDR 在下組成分壓器,B 腳接在中間);LED 接法同實驗 9-1(5V → 220Ω → LED → C,E → GND)。白天 LDR 電阻很小(幾百 Ω),分壓點被拉得很低(遠低於 0.7V),電晶體關閉,LED 不亮;天黑時 LDR 電阻變成幾十 kΩ 以上,分壓點升到 0.7V 以上,基極有電流,電晶體導通,LED 亮。可以把 10kΩ 換成 10kΩ 可變電阻來調整「多暗才亮」。想讓它切換得更乾脆,可以改用達靈頓。

本章小結

  • 電晶體是「用小電流控制大電流」的閥門:I_C ≈ β × I_B,2N2222 的 β 約 100–300,設計時保守取 100。
  • 2N2222 平面朝自己、腳朝下,由左到右是 E、B、C;NPN 符號的箭頭在射極上、朝外。
  • 當開關時要讓電晶體飽和:V_CE 只剩 0.1–0.3V,不發熱。基極電流不夠就會「半開」而發燙。
  • 基極電阻用 1kΩ:I_B = (5 − 0.7) ÷ 1000 = 4.3 mA,β = 100 時可讓 430 mA 以內的負載飽和。
  • 標準低邊開關接法:負載接 5V 與 C 之間,E 接 GND 並與 Arduino 共地,基極串 1kΩ,馬達和線圈並聯飛輪二極體。
  • 示波器雙通道看輸入(D9)和輸出(集極):兩者反相,D9 HIGH 時集極接近 0V。
  • IRLZ44N 由左到右是 G、D、S,靠電壓控制,5V 就全開,R_DS(on) 只有 0.022Ω,適合推 1A 以上的負載;閘極串 220Ω 並加 10kΩ 下拉。
  • 達靈頓把兩顆電晶體串起來,β 相乘(100 × 100 = 10000),但需要 1.4V 才導通。

名詞表

中文英文一句話解釋
電晶體Transistor用小訊號控制大電流的半導體元件
NPN 電晶體NPN Transistor基極電流流進去、集極電流從 C 流到 E 的電晶體,本書用 2N2222
基極Base(B)電晶體的控制腳,小電流從這裡進來
集極Collector(C)大電流流進電晶體的腳
射極Emitter(E)大電流流出電晶體的腳,通常接 GND
電流放大倍數β(hFE)集極電流除以基極電流,2N2222 約 100–300
飽和Saturation電晶體開到底的狀態,C-E 之間只剩 0.1–0.3V
基極電阻Base Resistor(R_B)串在 Arduino 腳位和基極之間、決定基極電流的電阻
低邊開關Low-side Switch電晶體接在負載和 GND 之間的開關接法
共地Common Ground兩個電路的 GND 接在一起,電流才有回路
反相Inverting輸出和輸入剛好相反:輸入 HIGH 時輸出 LOW
MOSFETMetal-Oxide-Semiconductor FET用電壓控制的電晶體,本書用 IRLZ44N
閘極 / 汲極 / 源極Gate / Drain / Source(G/D/S)MOSFET 的三隻腳,分別對應 B / C / E
導通電阻R_DS(on)MOSFET 完全打開時 D-S 之間的電阻,IRLZ44N 約 0.022Ω
邏輯準位 MOSFETLogic-level MOSFET5V 就能完全打開的 MOSFET(型號裡的 L)
下拉電阻Pull-down Resistor把腳位平常拉到 0V、避免「飄」的電阻
達靈頓Darlington兩顆電晶體串接、放大倍數相乘的接法

第 10 章 交流訊號與濾波

本章目標

  • 學完你會分辨直流與交流,說得出一個波的「週期、頻率、振幅、Vpp」是什麼。
  • 學完你會解釋 PWM 的占空比,並算出它的平均電壓。
  • 學完你會用一顆電阻加一顆電容做出「低通濾波器」,把 Arduino 的 PWM 方波磨成接近直流,並用示波器看前後差別。
  • 學完你會說出為什麼時間常數 τ 要比方波的週期大很多,濾波才有效。
  • 學完你會用 tone() 做一台三鍵電子琴,再用示波器量出每個音的頻率。

開場:Arduino 只有 0V 和 5V,怎麼做出 2.5V?

園遊會快到了,社團決定做兩個攤位:一個是「電子琴」,按下按鈕就發出 Do、Re、Mi;另一個是「調光燈」,轉一轉就能讓燈從暗慢慢變亮。

做調光燈的同學先卡住了。他翻了翻 Arduino 的說明,發現數位腳位只會輸出兩種電壓:0V 或 5V。「那要怎麼得到 2.5V 呢?LED 要半亮,總不能叫它一下亮一下暗吧?」

另一個做電子琴的同學也有疑問:「蜂鳴器只是一片會震動的薄片,為什麼同一顆蜂鳴器可以發出 Do,也可以發出 Mi?聲音的高低到底是什麼決定的?」

其實這兩個問題的答案是同一個東西:時間。前面幾章我們看的多半是「不會變的電壓」,這一章開始,我們要看「會隨時間變來變去的電壓」,也就是訊號(Signal)。只要掌握訊號怎麼變,Arduino 就能做出 2.5V,蜂鳴器也能唱出整首歌。

核心概念

直流與交流:水往一個方向流,還是來回晃?

想像一條水管。如果水一直往同一個方向流,速度也差不多,這就像直流(DC, Direct Current):電池、USB 供電、Arduino 的 5V 腳位都是直流,電流方向固定,電壓大致不變。

如果水管裡的水一下往左、一下往右,來回晃動,這就像交流(AC, Alternating Current):電流的方向會週期性地反過來,電壓也在正負之間來回擺。家裡牆上的插座就是交流電(記住安全紅線:本書絕對不碰 110V 插座),第 7 章你拿磁鐵在線圈旁邊晃出來的電,也是交流。

還有一種介於中間的:電壓一直在 0V 和 5V 之間跳,方向沒有反過來,但是數值一直在變。Arduino 腳位輸出的方波就是這種。嚴格說它是「會變的直流」,不過它跟交流有一樣的特性:有週期、有頻率,所以我們把它們放在同一章講。

正弦波:最乾淨的波

最基本、最乾淨的交流訊號叫正弦波(Sine Wave),長得像平滑的山丘和山谷一直重複:

電壓
 +1V ┤   ╭─╮       ╭─╮
     │  ╱   ╲     ╱   ╲
  0V ┼─╱─────╲───╱─────╲─── 時間
     │        ╲ ╱       ╲ ╱
 -1V ┤         ╰─╯       ╰─╯
       ◄───────►
        一個週期 T

描述一個波,要記住四個詞:

  • 週期(Period,T):波重複一次需要的時間,單位是秒(s)或毫秒(ms)。
  • 頻率(Frequency,f):一秒鐘重複幾次,單位是赫茲(Hz)。1 kHz = 1000 Hz。
  • 振幅(Amplitude):從中間線到最高點的高度。
  • 峰對峰值(Vpp,Peak-to-Peak Voltage):最高點到最低點的總高度。上面那個波振幅是 1V,Vpp 就是 2V。

週期和頻率互為倒數,這是本章最重要的公式:

f = 1 / T    T = 1 / f

算一個例子:台灣的市電頻率是 60 Hz,一個週期 T = 1 ÷ 60 = 0.0167 秒 = 16.7 ms。反過來,如果示波器量到一個波的週期是 4 ms = 0.004 秒,那頻率 f = 1 ÷ 0.004 = 250 Hz。

單位換算要小心:先把 ms 換成秒再算。4 ms 是 0.004 秒,不是 4 秒。

方波與 PWM:用「快速開關」做出半亮

回到開場的問題:Arduino 只有 0V 和 5V,怎麼做 2.5V?答案是「快速切換」。如果 LED 亮 1 毫秒、暗 1 毫秒,一直重複,每秒切換幾百次,你的眼睛根本跟不上,看起來就是「半亮」。

這種在 HIGH 和 LOW 之間來回跳的訊號叫方波(Square Wave)。方波裡「HIGH 的時間占整個週期的比例」叫占空比(Duty Cycle):

占空比 D = HIGH 的時間 ÷ 週期 × 100%
平均電壓 V平均 = V高 × D

Arduino 的 analogWrite(腳位, n) 就是在輸出這種方波,n 可以是 0 到 255,占空比 = n ÷ 255。這種「用占空比控制平均值」的技巧叫 PWM(Pulse Width Modulation,脈波寬度調變)。

算一次:

  • analogWrite(9, 128):占空比 = 128 ÷ 255 = 50.2% ≈ 50%,平均電壓 = 5V × 0.5 = 2.5V。
  • analogWrite(9, 64):占空比 = 64 ÷ 255 ≈ 25%,平均電壓 ≈ 1.25V。
  • analogWrite(9, 191):占空比 = 191 ÷ 255 ≈ 75%,平均電壓 ≈ 3.75V。

Arduino UNO 的 D9 腳位 PWM 頻率大約是 490 Hz,週期 T = 1 ÷ 490 ≈ 0.00204 秒 ≈ 2 ms。也就是每 2 ms 一個循環,50% 的時候 HIGH 約 1 ms、LOW 約 1 ms。

電壓(analogWrite(9,128),約 490Hz,50%)
 5V ┤   ┌────┐    ┌────┐    ┌────┐
    │   │    │    │    │    │    │
 0V ┼───┘    └────┘    └────┘    └── 時間
        ◄────────►
          約 2 ms

RC 低通濾波:把方波「磨平」成直流

眼睛會自己把閃爍平均掉,但很多東西不會。如果你要的是真正穩定的 2.5V(例如給別的電路當參考電壓),就得自己把方波磨平。工具是第 5 章學過的老朋友:一顆電阻加一顆電容。

想像一個水桶,進水管很細(電阻大),桶子很大(電容大)。水龍頭一秒開關幾百次,但因為管子細、桶子大,桶裡的水位幾乎不會跟著跳,只會慢慢停在一個「平均水位」。電阻加電容就是這樣的水桶,它讓慢的變化通過、把快的跳動擋掉,所以叫低通濾波器(Low-pass Filter),「低」指的是低頻率的訊號可以通過。

 Arduino D9 ──[ R ]──┬──── 輸出(接近平均電壓)
                     │
                    ═╪═ C
                     │
                    GND

關鍵是第 5 章的時間常數 τ = R × C。這裡的規則是:

τ 要比方波的週期大很多(至少 10 倍,最好 50 倍以上),輸出才會平。

因為在半個週期內,電容「來不及」充飽或放光,水位只會微微晃,這個微微晃叫漣波(Ripple)。漣波大概可以這樣估(50% 占空比時):

漣波 ≈ (V高 − V平均)×(半個週期 ÷ τ)

算三組,等一下實驗會全部量到:

RCτ = R × Cτ 比週期(2 ms)預期結果
10 kΩ10 µF10000 × 0.00001 = 0.1 s = 100 ms大 50 倍幾乎平的直線,漣波 ≈ 2.5V × (1 ms ÷ 100 ms) ≈ 25 mV
10 kΩ100 nF10000 × 0.0000001 = 0.001 s = 1 ms只有一半很明顯的三角波,上下晃大約 2.3V
1 kΩ100 nF1000 × 0.0000001 = 0.0001 s = 0.1 ms比週期還短 20 倍幾乎沒濾到:電容在半個週期內就充飽、放光,看起來像圓角的方波,晃動將近 5V

磨得越平,代價就是「反應越慢」:τ = 0.1 s 的那組,從開機到輸出穩定在 2.5V,要等大約 5τ = 0.5 秒。如果你改占空比,它也要半秒才跟上。這是濾波永遠的取捨:越平越慢,越快越抖。

濾波為什麼也能去雜訊、去抖動?

雜訊(Noise)是什麼?就是訊號上面那些又快又小的毛毛刺刺。它們的頻率很高,而低通濾波器剛好專門擋高頻,所以電阻加電容也是最常見的「除毛器」。感測器的讀值一直跳,常常加一組 RC 就安靜很多。

下一章你會看到,按鈕按下去的瞬間,金屬片會「彈跳」好幾次,產生一串很快的 HIGH/LOW。同樣的道理,加一組 RC 可以把這些彈跳磨掉,讓 Arduino 只看到一次乾淨的按下。

甚至程式裡「把最近 10 次讀值平均起來」也是一種濾波,只是用軟體做。

聲音與頻率:蜂鳴器為什麼能唱歌

聲音是空氣來回震動,一秒震動幾次就是聲音的頻率。震得越快,我們聽到的音越高。本書的**無源蜂鳴器(Passive Buzzer)**本身不會響,它只是一片會跟著電壓動的薄片,你給它多少 Hz 的方波,它就震多少次。

Arduino 的 tone(腳位, 頻率) 會在那個腳位輸出 50% 的方波,頻率隨你指定,noTone(腳位) 則停止。音階和頻率的對照如下(中央 C 這一組):

音名DoReMiFaSolLaSi高音 Do
頻率(Hz)262294330349392440494523
週期(ms)3.823.403.032.872.552.272.021.91

算一個:Do 是 262 Hz,週期 T = 1 ÷ 262 = 0.00382 秒 = 3.82 ms。你會發現高音 Do(523 Hz)剛好是 Do(262 Hz)的兩倍,這就是「高八度」的意思:頻率加倍。

動手做

實驗 10-1:用 RC 濾波把 PWM 磨成直流

材料

  • Arduino UNO 與 USB 線、麵包板、杜邦線
  • 10 kΩ 電阻 ×1、1 kΩ 電阻 ×1
  • 10 µF 電解電容 ×1(有極性!)、100 nF 陶瓷電容 ×1
  • 雙通道示波器(兩支 10× 探棒)
  • 數位三用電表

接線

 CH1 探棒 ─────────────────┐
                           │
 Arduino D9 ──[ 10kΩ ]─────┼──┬──── CH2 探棒
                              │
                             ═╪═ 10µF(長腳「+」在上方)
                              │
 Arduino GND ─────────────────┴──── 兩支探棒的接地夾

  • Arduino D9 → 10 kΩ 電阻一端。
  • 10 kΩ 電阻另一端 → 麵包板上一條橫排(叫它「輸出點」)。
  • 10 µF 電解電容:長腳(+)→ 輸出點,短腳(−)→ Arduino GND。
  • 示波器 CH1 探棒尖端 → Arduino D9(濾波前);CH2 探棒尖端 → 輸出點(濾波後)。
  • 兩支探棒的黑色接地夾 → Arduino GND。接地夾只能夾 GND。

程式(上傳後可以在序列埠監控視窗輸入 0–255 改占空比)

// 實驗 10-1:輸出 PWM 給 RC 濾波器
const int pwmPin = 9;        // D9 支援 PWM,頻率約 490Hz
int dutyValue = 128;         // 128/255 ≈ 50%

void setup() {
  Serial.begin(9600);        // 打開序列埠,速度 9600
  pinMode(pwmPin, OUTPUT);
  analogWrite(pwmPin, dutyValue);   // 先輸出 50% 的方波
  Serial.println("輸入 0-255 可以改占空比");
}

void loop() {
  if (Serial.available() > 0) {          // 有人在序列埠打字?
    int newValue = Serial.parseInt();    // 把打的字讀成整數
    if (newValue >= 0 && newValue <= 255) {
      dutyValue = newValue;
      analogWrite(pwmPin, dutyValue);    // 更新占空比
      Serial.print("占空比 = ");
      Serial.print(dutyValue * 100.0 / 255.0);   // 換算成百分比
      Serial.println(" %");
    }
    while (Serial.available() > 0) Serial.read();  // 清掉多餘字元(例如換行)
  }
}

步驟

  1. 先不要接電容,只接 10 kΩ,上傳程式。示波器 CH1 和 CH2 應該都看到一樣的方波(電阻後面沒有電容,沒有濾波效果)。
  2. 把 10 µF 電解電容接上(注意長腳在輸出點、短腳在 GND)。看 CH2 的變化:等大約半秒,它會變成一條幾乎平的線,停在 2.5V 附近。
  3. 用三用電表直流電壓檔量輸出點對 GND,記下來。
  4. 在序列埠監控視窗輸入 64,再輸入 191,看 CH2 的線怎麼移、三用電表怎麼變。
  5. 把 10 µF 換成 100 nF 陶瓷電容(沒有極性,隨便接)。這組是 τ = 1 ms,看 CH2 變成三角波。
  6. 再把 10 kΩ 換成 1 kΩ(還是接 100 nF)。這組是 τ = 0.1 ms,看 CH2 幾乎回到方波,只是邊角變圓。
  7. 把三組的波形畫下來、漣波量下來,填進表格。

你應該看到

  • 10 kΩ + 10 µF:CH1 是 0V/5V 方波,CH2 幾乎是直線,停在 2.5V。把 CH2 的 V/div 調小一點會看到一點點鋸齒狀的小漣波,大約 20–30 mV。
  • 10 kΩ + 100 nF:CH2 是明顯的三角波,在大約 1.3V 到 3.7V 之間來回。
  • 1 kΩ + 100 nF:CH2 看起來像圓角方波,幾乎從 0V 衝到 5V,根本沒濾到什麼。
  • 輸入 64 時平均電壓掉到約 1.25V,輸入 191 時升到約 3.75V。

觀察與記錄

RCτ = R × CCH2 平均電壓(示波器)三用電表讀值漣波 Vpp波形長相
10 kΩ10 µF0.1 s
10 kΩ100 nF1 ms
1 kΩ100 nF0.1 ms
analogWrite 的值占空比(算出來)平均電壓(算出來)三用電表量到(10 kΩ + 10 µF)
64
128
191

實驗 10-2:三鍵電子琴,用示波器驗證音高

材料

  • Arduino UNO、麵包板、杜邦線
  • 無源蜂鳴器 ×1
  • 按鈕開關 ×3
  • 示波器(一支探棒)

接線

 Arduino D8 ──────── 蜂鳴器「+」
 Arduino GND ─────── 蜂鳴器「−」

 Arduino D2 ──┬── 按鈕 1 ──┐
 Arduino D3 ──┼── 按鈕 2 ──┤
 Arduino D4 ──┴── 按鈕 3 ──┴── Arduino GND

 CH1 探棒尖端 → D8,接地夾 → GND

  • 蜂鳴器「+」腳(通常有標示或腳較長)→ Arduino D8;「−」腳 → GND。
  • 三個按鈕各一腳 → D2、D3、D4;另一腳 → GND。按鈕不需要外接電阻,程式會打開 Arduino 內建的上拉電阻(下一章會詳細解釋,現在只要記得:按下去讀到的是 LOW)。
  • 示波器 CH1 探棒尖端夾在 D8 那條線上,接地夾夾 GND。

程式

// 實驗 10-2:三鍵電子琴 Do Re Mi
const int buzzerPin = 8;                 // 蜂鳴器接 D8
const int buttonPins[3] = {2, 3, 4};     // 三個按鈕接 D2、D3、D4
const int noteFreqs[3] = {262, 294, 330};   // Do、Re、Mi 的頻率(Hz)

void setup() {
  pinMode(buzzerPin, OUTPUT);
  for (int i = 0; i < 3; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);   // 內建上拉:沒按是 HIGH,按下是 LOW
  }
}

void loop() {
  bool anyPressed = false;                  // 記錄有沒有任何按鈕被按
  for (int i = 0; i < 3; i++) {
    if (digitalRead(buttonPins[i]) == LOW) {   // 按下去了
      tone(buzzerPin, noteFreqs[i]);           // 發出對應頻率的方波
      anyPressed = true;
      break;                                   // 一次只發一個音
    }
  }
  if (!anyPressed) {
    noTone(buzzerPin);                        // 沒按就安靜
  }
}

步驟

  1. 接好線、上傳程式。按按鈕 1、2、3,應該聽到三個由低到高的音。
  2. 示波器調到 1 ms/div,觸發設在 CH1 上升邊緣。按住按鈕 1 不放,畫面會出現穩定的方波。
  3. 用游標或自動量測的「週期」功能量一個週期的時間,記下來,再用 f = 1 ÷ T 算回頻率。
  4. 換按鈕 2、按鈕 3 重做一次。
  5. 把程式裡的 262 改成 523(高八度的 Do),重新上傳,聽聽看、量量看,週期是不是變成一半。

你應該看到

  • 按鈕 1(262 Hz):週期約 3.82 ms,在 1 ms/div 下,一個週期差不多占 3.8 格。
  • 按鈕 2(294 Hz):約 3.40 ms。按鈕 3(330 Hz):約 3.03 ms。
  • 音越高,方波擠得越密。

觀察與記錄

按鈕音名程式設定頻率(Hz)示波器量到的週期 T(ms)算回來的頻率 1 ÷ T(Hz)和設定差多少?
1Do262
2Re294
3Mi330
1(改程式)高音 Do523

用儀器看看

示波器:前後對照 PWM 與濾波後的輸出(實驗 10-1)

  • 接法:CH1 → D9,CH2 → 輸出點,兩支接地夾 → GND。探棒開關撥到 10×,示波器通道設定也要選 10×。
  • CH1:2 V/div,耦合 DC。
  • CH2:先也用 2 V/div,方便和 CH1 比較。
  • 時間:500 µs/div。一個週期 2 ms 會占 4 格,畫面上看到兩、三個週期。
  • 觸發:來源 CH1,上升邊緣,準位約 2.5V。模式 Auto 或 Normal 都可以。

10 kΩ + 10 µF 的畫面大概像這樣:

 CH1 (D9)
 5V ┤  ┌────┐    ┌────┐    ┌────┐
    │  │    │    │    │    │    │
 0V ┼──┘    └────┘    └────┘    └──
 CH2 (電容端)
 5V ┤
2.5V┤─────────────────────────────── ← 幾乎平的線
 0V ┼───────────────────────────────
     ◄────────►
       約 2 ms

想看清楚那一點點漣波:把 CH2 的耦合改成 AC(把 2.5V 的直流部分去掉,只留下變化的部分),再把 CH2 改成 20 mV/div。你會看到一個小小的三角波,高度大約 1 格多一點(20–30 mV),和算出來的 25 mV 很接近。

換成 10 kΩ + 100 nF 時把 CH2 改回 DC、1 V/div:

 CH2 (10kΩ + 100nF,τ = 1 ms)
 5V ┤
    │   ╱╲    ╱╲    ╱╲    ╱╲
2.5V┤  ╱  ╲  ╱  ╲  ╱  ╲  ╱  ╲      ← 三角波,上下晃約 2.3V
    │ ╱    ╲╱    ╲╱    ╲╱    ╲
 0V ┼──────────────────────────────

用示波器的自動量測功能,可以直接叫出 CH1 的「頻率」「占空比」和 CH2 的「平均值(Mean)」「Vpp」,和自己算的對一下。

示波器:量電子琴的週期(實驗 10-2)

  • 接法:CH1 → D8,接地夾 → GND。
  • CH1:2 V/div。
  • 時間:1 ms/div。
  • 觸發:CH1 上升邊緣,Normal 模式(這樣沒按按鈕時畫面會停住,不會亂跳)。
  • 按住按鈕後,把兩條垂直游標分別放在相鄰兩個上升邊緣,讀出 ΔT 就是週期。

三用電表:它也在「濾波」

把三用電表切到直流電壓檔,直接量 D9 對 GND(濾波前)。你會發現它居然也讀到大約 2.5V,而不是在 0 和 5 之間跳。這是因為三用電表反應慢,它自己就把快速的方波平均掉了,等於內建了一個低通濾波器。這也提醒你:量方波的平均值用電表可以,但想看方波本身的樣子,一定要用示波器。

常見錯誤與除錯

  • CH2 跟 CH1 長得一模一樣,完全沒濾到 → 電容可能沒接到迴路裡,或電容接在 D9 那一側而不是電阻之後 → 檢查電容是不是跨在「輸出點」和 GND 之間。
  • 電容發熱、鼓起甚至爆開 → 電解電容極性接反 → 立刻拔掉 USB,換一顆新電容,長腳(+)接輸出點、短腳(−)接 GND。
  • CH2 的線慢慢爬,等很久才到 2.5V → 這是正常的!τ = 0.1 s 時要等約 0.5 秒 → 如果等超過幾秒都還沒到,檢查電阻值是不是拿成 100 kΩ 或 1 MΩ。
  • 示波器畫面一直左右漂、看不清楚 → 觸發沒設好 → 觸發來源選 CH1,準位拉到 2.5V 附近,邊緣選上升。
  • 示波器的方波頂端只有 0.5V → 探棒撥在 10× 但示波器通道設成 1×(或相反) → 兩邊要一致。
  • 蜂鳴器完全沒聲音 → 用到了有源蜂鳴器(它自己會響,不吃頻率),或正負接反 → 確認是無源蜂鳴器,並檢查 D8 的線。
  • 一直響個不停,放開按鈕也不停 → 按鈕的另一腳沒接到 GND,或按鈕插在麵包板上方向錯(四腳按鈕有兩對腳本來就是通的) → 把按鈕轉 90 度再插一次。
  • 序列埠輸入數字沒反應 → 監控視窗的鮑率不是 9600,或送出時沒按 Enter → 右下角選 9600,並確認「換行」設定。

想一想

  1. 示波器量到一個方波的週期是 5 ms,它的頻率是多少?
參考答案

5 ms = 0.005 秒,f = 1 ÷ 0.005 = 200 Hz。

  1. analogWrite(9, 51) 的占空比是多少?平均電壓是多少?
參考答案

占空比 = 51 ÷ 255 = 0.2 = 20%。平均電壓 = 5V × 0.2 = 1.0V。

  1. 如果把實驗 10-1 的 10 kΩ 換成 100 kΩ(還是接 10 µF),τ 變成多少?輸出會更平還是更不平?有什麼代價?
參考答案

τ = 100000 × 0.00001 = 1 秒,比原來大 10 倍,漣波會小 10 倍(約 2.5 mV),更平。代價是反應更慢:從開機到穩定要等約 5τ = 5 秒;改占空比後也要等好幾秒才跟上。

  1. 1 kΩ + 100 nF 那組為什麼幾乎沒有濾波效果?如果堅持要用 1 kΩ,電容要換成多大,τ 才能和 10 kΩ + 10 µF 那組一樣是 0.1 秒?
參考答案

因為 τ = 0.1 ms 比週期 2 ms 還短,電容在半個週期內就充飽又放光,跟著方波跑。要讓 τ = 0.1 秒:C = τ ÷ R = 0.1 ÷ 1000 = 0.0001 F = 100 µF。器材箱裡剛好有 100 µF 電解電容,可以試試看。

  1. La 的頻率是 440 Hz,週期是多少?高八度的 La 是幾 Hz?
參考答案

T = 1 ÷ 440 = 0.00227 秒 = 2.27 ms。高八度是頻率加倍:880 Hz。

  1. 開放挑戰:器材箱裡只有幾顆按鈕,但你想做一台可以「滑音」的琴,手轉過去音就連續變高。提示:10 kΩ 可變電阻、analogRead()(第 13 章會教,現在可以先查一下)、map()。想想看怎麼接、程式怎麼寫。
參考答案

把可變電阻兩端接 5V 和 GND,中間腳接 A0。analogRead(A0) 會得到 0–1023,用 map(value, 0, 1023, 262, 523) 換算成 262–523 Hz,再丟給 tone()。轉動旋鈕時頻率連續變化,就是滑音。進階:讓示波器一邊看 D8,一邊看 A0 的電壓怎麼變。

本章小結

  • 直流的方向與大小固定;交流的方向會來回變。Arduino 的方波是「會變的直流」,但同樣有週期與頻率。
  • 週期 T 和頻率 f 互為倒數:f = 1 ÷ T。算之前先把 ms 換成秒。
  • 振幅是中線到頂的高度,Vpp 是頂到底的總高度。
  • PWM 用占空比控制平均電壓:V平均 = V高 × (n ÷ 255)。analogWrite(9, 128) ≈ 2.5V,UNO D9 的 PWM 約 490 Hz,週期約 2 ms。
  • RC 低通濾波器讓慢的通過、擋掉快的。τ = R × C 要比週期大很多(50 倍以上)才能磨平;越平就越慢。
  • 10 kΩ + 10 µF(τ = 0.1 s)可以把 PWM 磨成只有約 25 mV 漣波的直流;1 kΩ + 100 nF(τ = 0.1 ms)幾乎沒效。
  • 濾波同時也能去雜訊、去按鈕彈跳;三用電表量方波時其實自己就在平均。
  • 聲音的高低由頻率決定,tone() 輸出指定頻率的方波給無源蜂鳴器;Do = 262 Hz,週期 3.82 ms,高八度是頻率加倍。

名詞表

中文英文一句話解釋
訊號Signal會隨時間變化、用來傳遞資訊的電壓或電流。
直流DC, Direct Current方向固定的電流,電池與 USB 供電都是。
交流AC, Alternating Current方向週期性反過來的電流,家用電與線圈晃磁鐵產生的電都是。
正弦波Sine Wave最平滑、最基本的週期性波形,像連續的山丘與山谷。
週期Period(T)波重複一次所需的時間。
頻率Frequency(f)一秒內重複的次數,單位赫茲(Hz),f = 1 ÷ T。
振幅Amplitude從中線到波峰的高度。
峰對峰值Vpp, Peak-to-Peak Voltage波峰到波谷的總高度。
方波Square Wave在 HIGH 和 LOW 之間跳的波形。
占空比Duty Cycle一個週期裡 HIGH 所占的時間比例。
脈波寬度調變PWM, Pulse Width Modulation用改變占空比來控制平均電壓的方法。
低通濾波器Low-pass Filter讓低頻通過、擋掉高頻的電路,最簡單的是一顆電阻加一顆電容。
漣波Ripple濾波後殘留的小幅上下晃動。
雜訊Noise訊號上不想要的、又快又小的隨機抖動。
無源蜂鳴器Passive Buzzer需要外部給方波才會響的蜂鳴器,頻率決定音高。

第 11 章 數位邏輯

本章目標

  • 學完你會說出數位的 0 與 1 對應到什麼電壓,以及 Arduino 判斷 HIGH/LOW 的門檻在哪裡。
  • 學完你會把 0–255 的十進位數換成 8 位元二進位,也會換回來,並且知道「位元」和「位元組」是什麼。
  • 學完你會寫出 AND、OR、NOT、XOR 的真值表,並用它們組合出「門開 AND 天黑 → 亮燈」這種判斷。
  • 學完你會解釋為什麼按鈕一定要搭配上拉或下拉電阻,並會用 Arduino 內建的 INPUT_PULLUP。
  • 學完你會用示波器或邏輯分析儀親眼看到按鈕彈跳,並用程式把它去掉。

開場:按一下,怎麼算了三次?

社團的學長做了一個「按一下就加一」的計數器:按鈕接到 Arduino,每按一次螢幕上的數字就加 1。看起來很簡單,可是他按了 10 次,螢幕卻顯示 17,有時候又是 13。他把程式檢查了三遍,一個字都沒錯。

另一個同學在做玄關的自動燈:門打開「而且」天黑了才亮,白天開門不用亮。他寫了兩個 if,結果燈不是一直亮,就是完全不亮。

這兩個問題看起來不一樣,其實都跟同一件事有關:電腦的世界裡只有 0 和 1,而真實世界的按鈕、感測器、電線,都沒有那麼乾脆。 這一章我們要學「數位」到底是什麼,怎麼用 0 和 1 算數、怎麼用 0 和 1 做判斷,最後拿示波器去看按鈕按下去的那一瞬間,到底發生了什麼事,你會發現學長的計數器一點錯都沒有,錯的是按鈕。

核心概念

只有兩種狀態:0 與 1

前面幾章的電壓可以是 1.3V、2.75V、4.2V,任何數字都行,這叫類比(Analog),像一個可以無段調整的水龍頭。這一章開始我們講數位(Digital):只有「開」和「關」兩種狀態,像牆上的電燈開關,不是開就是關,沒有「半開」。

數位世界把這兩種狀態叫 0 與 1,在 Arduino 程式裡叫 LOW 與 HIGH。對 5V 的 Arduino UNO 來說:

  • 輸出時:HIGH 就是 5V,LOW 就是 0V。
  • 輸入時:Arduino 不會要求你剛好給 5V 或 0V,它有一條門檻(Threshold)。大致上,低於 1.5V 一定讀成 LOW,高於 3.0V 一定讀成 HIGH,中間 1.5V 到 3.0V 是「灰色地帶」,讀到什麼不保證。
 5V ┤ ═══════════ 一定是 HIGH
    │
3.0V┤ ───────────
    │   灰色地帶(不保證)
1.5V┤ ───────────
    │
 0V ┤ ═══════════ 一定是 LOW

ESP32 是 3.3V 系統,門檻也跟著縮:大約低於 0.8V 是 LOW、高於 2.5V 是 HIGH。

這個「灰色地帶」就是數位厲害的地方:假設一條線本來應該是 5V,因為雜訊變成 4.2V、有時候 4.7V,沒關係,反正都在 3.0V 以上,Arduino 讀到的一樣是 HIGH。數位訊號天生就比類比訊號抗雜訊,這也是為什麼電腦、手機全部都用數位。

二進位:只用 0 和 1 數數

只有 0 和 1,怎麼表示 178 這種數字?想一想我們平常怎麼數:十進位每一位是「個、十、百、千」,每往左一位乘 10。二進位(Binary)一樣,只是每往左一位乘 2,每一位只能是 0 或 1。每一位叫一個位元(bit),8 個位元湊在一起叫一個位元組(Byte)。

8 位元的每一位「值多少錢」如下,從右往左數,最右邊是第 0 位:

位元編號b7b6b5b4b3b2b1b0
這一位的值1286432168421

二進位 → 十進位:哪一位是 1,就把那一位的值加起來。

算一個:10110010 = 128 + 0 + 32 + 16 + 0 + 0 + 2 + 0 = 178。

全部都是 1 的 11111111 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255。所以 8 位元最大就是 255,最小是 00000000 = 0,一共 256 種。這就是為什麼 analogWrite() 的範圍是 0–255:它用一個位元組存。

十進位 → 二進位:從 128 開始往下問「夠不夠減?」,夠就寫 1 並減掉,不夠就寫 0。

算一個:100

  • 128?不夠 → 0
  • 64?夠,100 − 64 = 36 → 1
  • 32?夠,36 − 32 = 4 → 1
  • 16?不夠 → 0
  • 8?不夠 → 0
  • 4?夠,4 − 4 = 0 → 1
  • 2?不夠 → 0
  • 1?不夠 → 0

所以 100 = 01100100。驗算:64 + 32 + 4 = 100,對了。

第 13 章你會看到 analogRead() 的範圍是 0–1023,那是因為它用 10 個位元:最大值是 1024 − 1 = 1023。

邏輯閘:用 0 和 1 做判斷

有了 0 和 1,接下來要「做決定」。做決定的基本零件叫邏輯閘(Logic Gate),每種閘都有一張真值表(Truth Table),列出所有輸入組合的結果。我們用生活情境記住四種:

AND(且):兩把鑰匙的保險箱。 兩把鑰匙都要轉,門才會開。只有「全部是 1」輸出才是 1。

ABA AND B
000
010
100
111

OR(或):前門或後門。 有人從前門進來,或從後門進來,門鈴都會響。只要「有一個是 1」輸出就是 1。

ABA OR B
000
011
101
111

NOT(非):唱反調。 只有一個輸入,輸出永遠相反。

ANOT A
01
10

XOR(互斥或):樓梯燈的雙切開關。 樓上樓下各一個開關,任何一個撥一下,燈的狀態就反過來。兩個輸入「不一樣」時輸出 1,「一樣」時輸出 0。

ABA XOR B
000
011
101
110

在 Arduino 程式裡,這四種分別寫成:

邏輯程式寫法例子
AND&&a && b
OR||a || b
NOT!!a
XOR!=(兩個布林值「不相等」)a != b

把閘串起來就能做更複雜的判斷。開場的自動燈:

門開了(doorOpen)──┐
                    AND ──► 亮燈
天黑了(isDark)────┘

程式就是一行:if (doorOpen && isDark) { digitalWrite(ledPin, HIGH); }。那位同學寫兩個獨立的 if,等於把 AND 拆成了兩個各自獨立的判斷,當然不對。

再進階一點:「門開 AND 天黑 AND NOT 假日」就是 doorOpen && isDark && !isHoliday。

上拉與下拉電阻:別讓腳位「飄」

現在來看真實世界的按鈕。你可能會想:按鈕一腳接 5V、一腳接 D2,按下去 D2 就是 HIGH,不就好了?

問題是:沒按的時候 D2 接到哪裡? 什麼都沒接。這種腳位叫浮接(Floating),像一面沒綁好的旗子,隨風亂飄:旁邊的電線、你的手靠近,它就會在 HIGH 和 LOW 之間亂跳。實驗 11-1 你會親眼看到這個現象。

解法是用一顆電阻把腳位「輕輕拉住」,給它一個預設值:

下拉電阻(Pull-down Resistor):電阻接到 GND,沒按時被拉成 LOW;按鈕接到 5V,按下時變 HIGH。

 5V ──── 按鈕 ────┬──── Arduino D2
                  │
                [10kΩ]  下拉電阻
                  │
                 GND

上拉電阻(Pull-up Resistor):電阻接到 5V,沒按時被拉成 HIGH;按鈕接到 GND,按下時變 LOW。

 5V ────[10kΩ]────┬──── Arduino D2
       上拉電阻    │
                  按鈕
                  │
                 GND

兩種都可以,為什麼本書從這一章開始都用上拉?因為 Arduino 的每個腳位裡面已經內建一顆上拉電阻,程式寫 pinMode(2, INPUT_PULLUP) 就打開它,不用再外接電阻,接線少一半。內建上拉大約 20–50 kΩ。

要記住一件反直覺的事:用上拉時,按下去讀到的是 LOW,放開是 HIGH。 程式裡要寫 if (digitalRead(2) == LOW) 才是「被按下」。

算一下電阻值合不合理:用 10 kΩ 外接上拉,按下時電流 = 5V ÷ 10000 Ω = 0.5 mA,很小,安全又省電。內建上拉若是 30 kΩ,電流只有約 0.17 mA。電阻太小(例如 100 Ω)按下去會流 50 mA,白白浪費電還可能燒腳位;電阻太大(例如 10 MΩ)拉的力氣太弱,又會被雜訊干擾。10 kΩ 是最常見的好選擇。

按鈕彈跳:按一下,其實是按了好幾下

最後解開學長的計數器之謎。按鈕裡面是兩片金屬片,按下去時它們互相碰撞。金屬片有彈性,像跳到彈簧床上,會彈起來、落下、再彈起來,反覆幾次才停。這整個過程大約 1 到 10 毫秒,叫彈跳(Bounce)。

 電壓(上拉,按下時)
 5V ┤ ──────┐  ┌┐ ┌┐
    │       │  ││ ││
 0V ┼       └──┘└─┘└──────────────
          ▲
      手指按下     ◄── 約 1~10 ms ──►

對你的手指來說這是「按了一下」,但 Arduino 一秒可以讀腳位幾十萬次,它看到的是 HIGH→LOW→HIGH→LOW→HIGH→LOW,數了三次。學長的程式沒錯,是按鈕在騙它。

解法叫去彈跳(Debounce),有三種:

  1. 軟體等一下:偵測到按下後,先 delay(30) 等彈跳結束,再確認一次是不是還按著。最簡單,本章用這招。
  2. 硬體濾波:第 10 章的 RC 低通濾波器,把那幾毫秒的快速跳動磨掉。
  3. 記住上一次狀態:只在「上次是放開、這次是按下」的那一刻算一次,而且距離上次變化要超過 30 ms。這是最常見的正式寫法,實驗 11-3 會用到。

動手做

實驗 11-1:浮接的腳位會亂飄,上拉就乖了

材料

  • Arduino UNO 與 USB 線、麵包板、杜邦線
  • 按鈕開關 ×1
  • 10 kΩ 電阻 ×1(給外接上拉用)

接線(分兩階段)

階段一:故意浮接。

 Arduino D2 ──── 一條杜邦線,另一頭什麼都不接(懸空)

階段二:內建上拉加按鈕。

 Arduino D2 ──┬── 按鈕 ──── Arduino GND
              │
         (Arduino 裡面的上拉電阻,程式打開)

  • 階段一:D2 插一條杜邦線,另一頭懸空在麵包板外。
  • 階段二:按鈕一腳 → D2,另一腳 → GND。

程式

// 實驗 11-1:看浮接 vs 上拉
const int buttonPin = 2;     // 按鈕接 D2

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);         // 階段一:純輸入,沒有上拉(會飄)
  // pinMode(buttonPin, INPUT_PULLUP);   // 階段二:改用這行(把上面那行註解掉)
}

void loop() {
  int state = digitalRead(buttonPin);   // 讀腳位,得到 0 或 1
  Serial.println(state);                // 印到序列埠
  delay(50);                            // 每秒印 20 次
}

步驟

  1. 用階段一的接線與程式,上傳後打開序列埠監控視窗(9600)。
  2. 看數字。用手指去摸那條懸空的杜邦線、靠近它、拿走,看數字會不會亂跳。
  3. 把程式改成階段二(INPUT_PULLUP),接上按鈕,重新上傳。
  4. 不按時看數字,按住時看數字。
  5. 進階:把 INPUT_PULLUP 改回 INPUT,但在 D2 和 5V 之間外接一顆 10 kΩ 電阻,看是不是跟內建上拉一樣穩。

你應該看到

  • 階段一:數字可能一直是 0 或 1,但手一靠近就開始 0、1 亂跳,完全不受控制。
  • 階段二:沒按穩穩是 1,按住穩穩是 0,手靠近也不會變。

觀察與記錄

情況沒碰時讀到手靠近時讀到按住按鈕時讀到穩不穩?
浮接(INPUT,懸空)(沒有按鈕)
內建上拉(INPUT_PULLUP)
外接 10 kΩ 上拉(INPUT)

實驗 11-2:用兩個按鈕模擬邏輯閘

材料

  • Arduino UNO、麵包板、杜邦線
  • 按鈕開關 ×2
  • 紅色 LED ×1、220 Ω 電阻 ×1

接線

 Arduino D2 ──── 按鈕 A ──── GND     (輸入 A,內建上拉)
 Arduino D3 ──── 按鈕 B ──── GND     (輸入 B,內建上拉)

 Arduino D9 ──[ 220Ω ]──►|── GND    (輸出:LED)
                        LED

  • 按鈕 A:一腳 → D2,另一腳 → GND。
  • 按鈕 B:一腳 → D3,另一腳 → GND。
  • Arduino D9 → 220 Ω → LED 長腳,LED 短腳 → GND。

程式(在序列埠輸入 a、o、x、n 切換 AND / OR / XOR / NOT)

// 實驗 11-2:邏輯閘模擬器
const int buttonAPin = 2;    // 輸入 A
const int buttonBPin = 3;    // 輸入 B
const int ledPin = 9;        // 輸出 LED
char gateMode = 'a';         // 目前的閘:a=AND, o=OR, x=XOR, n=NOT(A)

void setup() {
  Serial.begin(9600);
  pinMode(buttonAPin, INPUT_PULLUP);   // 按下 = LOW
  pinMode(buttonBPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.println("輸入 a=AND, o=OR, x=XOR, n=NOT 切換模式");
}

void loop() {
  // 有人打字就切換模式
  if (Serial.available() > 0) {
    char c = Serial.read();
    if (c == 'a' || c == 'o' || c == 'x' || c == 'n') {
      gateMode = c;
      Serial.print("切換成:");
      Serial.println(gateMode);
    }
  }

  // 讀按鈕:按下是 LOW,所以用 == LOW 轉成 true(1)
  bool inputA = (digitalRead(buttonAPin) == LOW);
  bool inputB = (digitalRead(buttonBPin) == LOW);
  bool output = false;

  // 依模式計算輸出
  if (gateMode == 'a')      output = inputA && inputB;   // AND
  else if (gateMode == 'o') output = inputA || inputB;   // OR
  else if (gateMode == 'x') output = (inputA != inputB); // XOR
  else if (gateMode == 'n') output = !inputA;            // NOT(只看 A)

  digitalWrite(ledPin, output ? HIGH : LOW);   // 1 就亮,0 就暗

  // 把這一刻的真值表印出來
  Serial.print("A="); Serial.print(inputA);
  Serial.print(" B="); Serial.print(inputB);
  Serial.print(" 模式="); Serial.print(gateMode);
  Serial.print(" 輸出="); Serial.println(output);
  delay(200);                                  // 慢一點,才看得清楚
}

步驟

  1. 接線、上傳,打開序列埠監控視窗。預設是 AND 模式。
  2. 兩個按鈕都不按、只按 A、只按 B、兩個都按,四種組合各試一次,記錄 LED 亮不亮,填進真值表。
  3. 在監控視窗輸入 o 按 Enter,重做四種組合。
  4. 輸入 x,再做一次。
  5. 輸入 n,這時只看按鈕 A:不按時 LED 亮、按下反而暗。
  6. 把你填的表跟核心概念裡的真值表對一下。

你應該看到

  • AND:只有兩個都按時 LED 才亮。
  • OR:有按任何一個就亮。
  • XOR:只按一個時亮,兩個都按反而暗。
  • NOT:不按 A 時亮,按 A 時暗。

觀察與記錄

A(按=1)B(按=1)AND 的 LEDOR 的 LEDXOR 的 LEDNOT A 的 LED
00
01
10
11

實驗 11-3:按鈕計數器,先看它亂數,再把彈跳去掉

材料

  • 和實驗 11-2 相同(只用按鈕 A 與 LED)。

接線

  • 同實驗 11-2,按鈕 A 接 D2 與 GND,LED 接 D9。

程式(先用「沒有去彈跳」的版本)

// 實驗 11-3(版本一):沒有去彈跳的計數器
const int buttonPin = 2;
const int ledPin = 9;
int pressCount = 0;             // 按了幾次
bool lastState = HIGH;          // 上一次讀到的狀態(上拉:沒按是 HIGH)

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  bool nowState = digitalRead(buttonPin);
  // 上次是放開(HIGH)、這次是按下(LOW)→ 算一次
  if (lastState == HIGH && nowState == LOW) {
    pressCount = pressCount + 1;
    Serial.print("次數:");
    Serial.println(pressCount);
    digitalWrite(ledPin, pressCount % 2);   // 奇數次亮、偶數次暗
  }
  lastState = nowState;                     // 記住這次的狀態
}

去彈跳的版本只多了「距離上次變化要超過 30 ms」這個條件:

// 實驗 11-3(版本二):加上去彈跳
const int buttonPin = 2;
const int ledPin = 9;
int pressCount = 0;
bool lastState = HIGH;
unsigned long lastChangeTime = 0;     // 上次狀態改變的時間(毫秒)
const unsigned long debounceDelay = 30;   // 彈跳最多幾毫秒就結束

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  bool nowState = digitalRead(buttonPin);
  // 狀態有變,而且距離上次變化超過 30 ms,才相信它
  if (nowState != lastState && (millis() - lastChangeTime) > debounceDelay) {
    lastChangeTime = millis();          // 記下這次變化的時間
    if (nowState == LOW) {              // 是「按下」這一邊的變化
      pressCount = pressCount + 1;
      Serial.print("次數:");
      Serial.println(pressCount);
      digitalWrite(ledPin, pressCount % 2);
    }
    lastState = nowState;
  }
}

步驟

  1. 上傳版本一,打開監控視窗。用正常力道按 10 下,看最後數字是多少。
  2. 再按 10 下,但這次故意按慢一點、輕一點,看數字。
  3. 上傳版本二,重做步驟 1 和 2。

你應該看到

  • 版本一:按 10 下常常數到 12、15 甚至 20,而且每次都不一樣。
  • 版本二:按 10 下就是 10,LED 也乖乖一亮一暗。

觀察與記錄

版本第一輪按 10 下,顯示第二輪按 10 下,顯示第三輪按 10 下,顯示LED 亮暗正常嗎?
版本一(沒去彈跳)
版本二(去彈跳 30 ms)

用儀器看看

示波器:抓住按下的那一瞬間(彈跳)

按鈕彈跳只發生在按下那幾毫秒,之後就沒了,所以不能用 Auto 模式一直掃,要用 Single(單次)觸發:示波器等著,一看到你要的事件就拍一張、停住。

  • 接法:CH1 探棒尖端 → D2(按鈕 A 那條線),接地夾 → GND。用實驗 11-3 的接線,程式隨便哪個版本都行,重點是 INPUT_PULLUP 要打開。
  • CH1:1 V/div 或 2 V/div,DC 耦合。
  • 時間:先用 1 ms/div,看到彈跳後可以縮到 200 µs/div 看細節。
  • 觸發:來源 CH1,下降邊緣(因為按下時是 HIGH→LOW),準位約 2.5V。
  • 模式:按 Single。畫面會顯示「等待觸發」。
  • 把觸發位置往左移一點(大約留 1 格在觸發點前面),這樣能看到按下前的 5V。

然後按一下按鈕。示波器應該在按下的瞬間抓到畫面並停住:

 5V ┤ ───────┐ ┌─┐  ┌┐
    │        │ │ │  ││
 0V ┼        └─┘ └──┘└──────────────────
             ▲
          觸發點      ◄─ 彈跳約 1~5 ms ─►

多按幾次(每次按 Single 重新等待),你會發現每次彈跳的次數和長度都不一樣,有時候只彈一次,有時候彈五、六次。放開按鈕時也會彈跳,把觸發邊緣改成「上升」就能看到。

也用三用電表量一下 D2 對 GND:沒按是約 5V(內建上拉拉上去的),按住是 0V。

邏輯分析儀:把真值表「錄」下來

邏輯分析儀只看 0 和 1,不看電壓大小,一次可以看 8 條線,剛好拿來看邏輯閘。

  • 接法:CH0 → D2(按鈕 A)、CH1 → D3(按鈕 B)、CH2 → D9(LED 輸出),GND → Arduino GND(一定要接)。用實驗 11-2 的程式。
  • PulseView 設定:取樣率 1 MHz,取樣數 5 M(約 5 秒)。
  • 按下「Run」後,在這 5 秒內慢慢做四種按鈕組合。

畫面上會看到三條線:

 CH0 (A) ─────┐        ┌────┐        ┌──
              └────────┘    └────────┘
 CH1 (B) ──────────┐             ┌───────
                   └─────────────┘
 CH2 (LED, AND) ────────┐   ┌───────────   ← 只有 A、B 都是 0(都按下)時才變 1
                        └───┘

(注意:因為用上拉,按下是 0,所以 AND 的 LED 亮時 A 和 B 都是低電位。)把滑鼠移到 CH0 剛變低的地方放大到 µs 等級,你會在邊緣附近看到一堆密密麻麻的細線,那就是彈跳,邏輯分析儀看得比示波器更清楚。

常見錯誤與除錯

  • 序列埠的數字永遠是 1,按下去也不變 → 按鈕插的方向錯了(四腳按鈕有兩對腳本來就連通),或按鈕另一腳沒接 GND → 把按鈕轉 90 度重插,或用三用電表的蜂鳴檔量按鈕哪兩腳按下才通。
  • 沒按時數字就亂跳 → 忘了寫 INPUT_PULLUP,腳位浮接 → 檢查 pinMode。
  • 邏輯閘的結果全部相反 → 忘記上拉時「按下是 LOW」,程式裡用 == HIGH 當按下 → 改成 == LOW,或像範例一樣先轉成 bool。
  • 輸入 o 之後模式沒切換 → 監控視窗鮑率不是 9600,或「行尾」設定送出了多餘字元 → 設 9600,行尾選「沒有行尾」或「NL」都可以,程式只認 a/o/x/n。
  • 去彈跳後按很快會漏掉 → 30 ms 太長 → 改成 15–20 ms,但不要低於彈跳本身的長度(用示波器量你的按鈕彈多久再決定)。
  • 示波器一直「等待觸發」抓不到 → 觸發邊緣選成上升、或準位設太高 → 下降邊緣、準位 2.5V;也確認探棒真的夾在 D2 那條線上。
  • 邏輯分析儀全部是直線 → GND 沒接,或取樣率太低 → GND 一定要接 Arduino GND;取樣率至少 1 MHz。

想一想

  1. 二進位 01010101 是十進位多少?
參考答案

64 + 16 + 4 + 1 = 85。

  1. 把十進位 200 換成 8 位元二進位。
參考答案

200 − 128 = 72(b7 = 1),72 − 64 = 8(b6 = 1),32 不夠(0),16 不夠(0),8 − 8 = 0(b3 = 1),其餘 0。答案 11001000。驗算:128 + 64 + 8 = 200。

  1. 一個保全系統:「窗戶被打開 OR 門被打開」就要響,但「主人在家」時不要響。請用 AND、OR、NOT 寫出條件,再寫成 Arduino 的 if。
參考答案

(窗開 OR 門開) AND NOT 主人在家。程式:if ((windowOpen || doorOpen) && !ownerHome) { 響警報; }。括號很重要,先算 OR 再算 AND。

  1. 為什麼用 INPUT_PULLUP 時,按鈕要接到 GND 而不是 5V?如果有人把按鈕接到 5V,會發生什麼事?
參考答案

上拉電阻已經把腳位拉到 5V,按鈕接 GND 才能把它拉成 LOW,產生變化。如果按鈕接 5V,沒按是 5V、按下還是 5V,程式永遠讀到 HIGH,按鈕等於沒用。(接 5V 不會燒壞,因為上拉電阻很大,但就是沒反應。)

  1. 實驗 11-3 用 30 ms 去彈跳。如果有人一秒內能按 40 下(每下只隔 25 ms),計數器會發生什麼事?要怎麼改?
參考答案

25 ms 比 30 ms 短,第二下會被當成第一下的彈跳忽略掉,會漏數。可以把 30 改成 10–15 ms(前提是用示波器量過你的按鈕彈跳都在 10 ms 以內),或改用硬體 RC 濾波。但正常人一秒按不到 40 下,30 ms 對大多數應用都夠。

  1. 開放挑戰:用兩顆 LED(接 D9、D10)和一個按鈕,做一個「2 位元計數器」:每按一次,兩顆 LED 以二進位顯示 0、1、2、3,然後回到 0。提示:count % 4、bitRead(count, 0)、bitRead(count, 1)。
參考答案

用實驗 11-3 版本二的去彈跳架構,每次按下 count = (count + 1) % 4,然後 digitalWrite(9, bitRead(count, 0))(b0 亮 LED1)、digitalWrite(10, bitRead(count, 1))(b1 亮 LED2)。按四次會看到:暗暗 → 亮暗 → 暗亮 → 亮亮 → 暗暗。想要 3 位元就加第三顆 LED 和 % 8。

本章小結

  • 數位只有 0(LOW)和 1(HIGH)。UNO 讀輸入時,低於約 1.5V 是 LOW、高於約 3.0V 是 HIGH,中間不保證;這個緩衝區讓數位訊號很抗雜訊。
  • 二進位每往左一位乘 2,8 位元(1 位元組)的值是 128、64、32、16、8、4、2、1,範圍 0–255。十進位轉二進位用「從 128 往下問夠不夠減」。
  • AND 要全部是 1,OR 只要有一個 1,NOT 反過來,XOR 是「不一樣就 1」。程式寫法 &&、||、!、!=。
  • 輸入腳位不能浮接。用上拉或下拉電阻給它預設值;Arduino 的 INPUT_PULLUP 內建上拉,按鈕接 GND,按下是 LOW。
  • 10 kΩ 是上拉/下拉的常用值,按下時只流 0.5 mA。
  • 按鈕按下的瞬間會彈跳 1–10 ms,Arduino 會數成好幾次。用示波器 Single 觸發、下降邊緣就能抓到。
  • 去彈跳:等 30 ms 再相信它、加 RC 濾波、或只在狀態改變且超過 30 ms 時才算一次。

名詞表

中文英文一句話解釋
類比Analog電壓可以是任何數值的訊號,像無段調整的水龍頭。
數位Digital只有 0 和 1 兩種狀態的訊號。
門檻Threshold判斷 HIGH 或 LOW 的電壓分界線。
二進位Binary只用 0 和 1 的計數方式,每往左一位乘 2。
位元bit二進位的一位,只能是 0 或 1。
位元組Byte8 個位元,可以表示 0–255。
邏輯閘Logic Gate對 0 和 1 做判斷的基本單元,如 AND、OR、NOT、XOR。
真值表Truth Table列出所有輸入組合與對應輸出的表格。
且AND全部輸入是 1,輸出才是 1。
或OR任何一個輸入是 1,輸出就是 1。
非NOT把輸入反過來。
互斥或XOR兩個輸入不一樣時輸出 1。
浮接Floating輸入腳位什麼都沒接,狀態隨雜訊亂飄。
上拉電阻Pull-up Resistor接到電源的電阻,讓腳位預設為 HIGH。
下拉電阻Pull-down Resistor接到 GND 的電阻,讓腳位預設為 LOW。
內建上拉INPUT_PULLUPArduino 腳位內建的上拉電阻,用 pinMode 打開。
彈跳Bounce按鈕金屬片碰撞時產生的多次快速開關。
去彈跳Debounce用程式或電路把彈跳濾掉,讓一次按下只算一次。
單次觸發Single Trigger示波器只抓一次事件就停住的模式,用來看不重複的訊號。

第 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()回傳開機到現在經過的毫秒數。

第 13 章 感測器與類比輸入

本章目標

學完這一章,你會:

  • 說出「數位」與「類比」訊號的差別,並知道微控制器為什麼需要 ADC。
  • 用 analogRead() 讀取 0–1023(ESP32 是 0–4095)的數字,並把它換算回真正的電壓。
  • 用光敏電阻加 10kΩ 電阻做出分壓器,讓 Arduino 感覺到「亮」和「暗」。
  • 用 map() 把讀值換成好用的範圍,並用序列繪圖器把感測器的變化畫成曲線。
  • 用 DHT11 和函式庫讀出溫度與濕度,並完成一個會自己開燈的自動夜燈。

開場:Arduino 怎麼知道「天黑了」?

你家樓下的路燈,傍晚天色一暗就自己亮起來,早上又自己關掉。沒有人站在旁邊按開關,那它是怎麼「看到」天黑的?

上一章我們讓 Arduino 用 digitalRead() 讀按鈕,但按鈕只有「按下」和「沒按」兩種狀態,就像問「有沒有」這種是非題。可是天色不是是非題,它會從大亮、微亮、昏暗一路慢慢變到全黑,中間有無數種程度。溫度也是,今天 24.5 度、明天 26.1 度,不是只有「熱」和「冷」。

這一章我們要教 Arduino 回答「有多亮?」「有多熱?」這種需要一個數字的問題。祕密武器是一個藏在晶片裡的小翻譯機,叫做 ADC。學會它之後,光敏電阻、可變電阻、溫濕度感測器,全都可以變成 Arduino 的眼睛和皮膚。

核心概念

數位與類比:樓梯和斜坡

想像兩種上樓的方法:走樓梯,和走斜坡。樓梯只有一階一階,你不是站在第 3 階就是第 4 階,沒有「第 3.5 階」;斜坡則是連續的,你可以站在任何高度。

數位訊號(Digital Signal) 就像樓梯,只有固定幾種狀態,最常見的是只有 0 和 1 兩階(HIGH 和 LOW)。類比訊號(Analog Signal) 就像斜坡,電壓可以是 0V 到 5V 之間的任何值:1.23V、3.8V、4.999V 都可以。

真實世界裡的東西幾乎都是類比的:亮度、溫度、聲音大小、可變電阻轉到哪裡。但微控制器的大腦只懂 0 和 1。所以我們需要一個翻譯機,把「斜坡的高度」翻譯成「一個整數」。

ADC:把電壓翻譯成數字

這個翻譯機叫做類比數位轉換器(Analog-to-Digital Converter,ADC)。它的工作就是看一眼腳位上的電壓,然後回報一個整數。

Arduino UNO 的 ADC 是 10 位元(bit),意思是它用 10 個 0/1 來表示結果,所以總共有 2 的 10 次方 = 1024 種可能,也就是 0 到 1023。0V 回報 0,5V 回報 1023,中間按比例分配。等於把 0–5V 這條斜坡切成 1023 格樓梯,每一格大約是:

5V ÷ 1023 ≈ 0.0049V ≈ 4.9mV

ESP32 的 ADC 是 12 位元,有 4096 種可能(0 到 4095),而且它的滿刻度電壓是 3.3V,所以每一格是 3.3V ÷ 4095 ≈ 0.0008V ≈ 0.8mV,比 UNO 切得更細。

在程式裡,讀 ADC 只要一行:analogRead(A0),它會回傳一個整數。

把讀值換算回電壓

ADC 回報的是「第幾格」,我們常常想知道「幾伏特」。換算公式很簡單,就是按比例:

電壓 = 讀值 × 5 ÷ 1023  (Arduino UNO)

電壓 = 讀值 × 3.3 ÷ 4095 (ESP32)

算一個例子:UNO 的 analogRead() 回傳 512。

電壓 = 512 × 5 ÷ 1023 = 2560 ÷ 1023 ≈ 2.50V

剛好是 5V 的一半。再算一個:回傳 205。

電壓 = 205 × 5 ÷ 1023 = 1025 ÷ 1023 ≈ 1.00V

ESP32 讀到 2048 呢?

電壓 = 2048 × 3.3 ÷ 4095 = 6758.4 ÷ 4095 ≈ 1.65V

也剛好是 3.3V 的一半。注意 ESP32 的類比輸入腳不能超過 3.3V,接 5V 會把它燒壞。

在程式裡寫的時候,記得要用小數(5.0、1023.0),不然整數除法會把小數點後面全部丟掉:

float voltage = raw * 5.0 / 1023.0;   // 正確:會得到 2.50
int wrong = raw * 5 / 1023;           // 錯誤:只會得到 2

感測器大多是「會變的電阻」

很多便宜的感測器,骨子裡只是一個電阻值會跟著環境改變的元件。光敏電阻(Light Dependent Resistor,LDR) 就是最好的例子:光線越亮,它的電阻越小;越暗,電阻越大。亮的時候可能只有 1kΩ,全黑的時候可能超過 100kΩ。

問題來了:ADC 只會量電壓,不會量電阻。怎麼辦?用第 3 章學過的分壓器(Voltage Divider)!把光敏電阻和一個固定的 10kΩ 電阻串在一起,中間那一點的電壓就會跟著光線變化:

 5V ──[ LDR ]──┬──[ 10kΩ ]── GND
               │
              A0

分壓公式:中間點電壓 = 5V × 10kΩ ÷ (LDR + 10kΩ)。來算兩種情況:

  • 亮:LDR ≈ 1kΩ,A0 電壓 = 5 × 10 ÷ (1 + 10) = 50 ÷ 11 ≈ 4.55V,讀值 ≈ 4.55 × 1023 ÷ 5 ≈ 930。
  • 暗:LDR ≈ 100kΩ,A0 電壓 = 5 × 10 ÷ (100 + 10) = 50 ÷ 110 ≈ 0.45V,讀值 ≈ 0.45 × 1023 ÷ 5 ≈ 93。

所以在這種接法下:越亮,讀值越大;越暗,讀值越小。如果你把 LDR 和 10kΩ 的位置對調,結果就會反過來,兩種接法都可以,只要你知道自己接的是哪一種。

可變電阻也是同樣道理,而且更簡單:它本身就是一個分壓器。兩端接 5V 和 GND,中間腳接 A0,轉動旋鈕,A0 的電壓就在 0V 到 5V 之間滑動。

map():把數字換成好用的範圍

讀到 0–1023 的數字之後,我們常常想把它變成別的範圍,例如變成 0–100 的百分比,或是下一章要用的 0–255 亮度。Arduino 內建的 map() 函式就是在做比例換算:

map(值, 原本最小, 原本最大, 新的最小, 新的最大)

例如 map(512, 0, 1023, 0, 255),計算方式是 512 × 255 ÷ 1023 = 130560 ÷ 1023 ≈ 127.6,map() 只保留整數,所以得到 127。再算一個:map(700, 0, 1023, 0, 100) = 700 × 100 ÷ 1023 ≈ 68.4,結果是 68,也就是「68%」。

DHT11:會自己講話的感測器

光敏電阻只是一個電阻,但 DHT11 溫濕度感測器 裡面有一顆小晶片,它會自己量好溫度和濕度,然後用一連串 0 和 1 的脈波「講」給 Arduino 聽。這種訊號我們不用自己解讀,直接使用現成的函式庫(Library) 就好。函式庫就是別人寫好、打包起來的程式,我們只要呼叫它的功能。

DHT11 的規格:溫度 0–50°C(誤差約 ±2°C)、濕度 20–90%(誤差約 ±5%),而且每次讀取之間至少要間隔 1 秒,讀太快它會回傳錯誤。

動手做

實驗 13-1:轉旋鈕,看數字和電壓

材料

  • Arduino UNO 與 USB 線
  • 10kΩ 可變電阻
  • 麵包板、杜邦線(公公)
  • 數位三用電表

接線

 Arduino 5V ──┐
              [ 10kΩ 可變電阻 ]
              │  (中間腳)──── Arduino A0
 Arduino GND ─┘

  • 可變電阻的左腳 → Arduino 5V
  • 可變電阻的右腳 → Arduino GND
  • 可變電阻的中間腳 → Arduino A0

步驟

  1. 照上面接好線,確認 5V 和 GND 沒有接反(接反只是轉動方向相反,不會壞,但先養成習慣)。
  2. 在 Arduino IDE 輸入下面的程式,上傳。
const int potPin = A0;      // 可變電阻中間腳接 A0

void setup() {
  Serial.begin(9600);       // 打開序列埠,速度 9600
}

void loop() {
  int raw = analogRead(potPin);           // 讀 ADC,得到 0~1023
  float voltage = raw * 5.0 / 1023.0;     // 換算成電壓(記得用小數)

  Serial.print("raw = ");
  Serial.print(raw);                      // 印出原始讀值
  Serial.print("   volt = ");
  Serial.print(voltage, 2);               // 印出電壓,保留 2 位小數
  Serial.println(" V");
  delay(200);                             // 每 0.2 秒讀一次
}
  1. 打開「工具 → 序列埠監控視窗」,右下角的速度選 9600。
  2. 慢慢轉動可變電阻,從一端轉到另一端。
  3. 轉到大約一半的位置,拿三用電表(直流電壓檔 20V)紅棒碰 A0 那條線、黑棒碰 GND,把電表讀到的電壓和畫面上的 volt 比一比。

你應該看到 轉到一端時 raw 接近 0、volt 接近 0.00V;轉到另一端時 raw 接近 1023、volt 接近 5.00V。中間位置大約是 512 和 2.50V。三用電表量到的電壓應該和畫面上的數字差不到 0.05V。

觀察與記錄

旋鈕位置raw 讀值程式算出的電壓三用電表量到的電壓
轉到最左
大約 1/4
大約一半
大約 3/4
轉到最右

實驗 13-2:光敏電阻與自動夜燈

這個實驗分兩段:先「觀察」光敏電阻在你的教室裡讀到多少,再用那個數字「決定」夜燈什麼時候該亮。

材料

  • Arduino UNO 與 USB 線
  • 光敏電阻(LDR)1 個
  • 10kΩ 電阻 1 個
  • 220Ω 電阻 1 個
  • 白色 LED 1 個
  • 麵包板、杜邦線

接線

 Arduino 5V ──[ LDR ]──┬──[ 10kΩ ]── Arduino GND
                       │
                  Arduino A0

 Arduino D9 ──[ 220Ω ]──►|── Arduino GND
                        LED

  • Arduino 5V → LDR 一腳;LDR 另一腳 → 麵包板某一列(叫它「分壓點」)
  • 分壓點 → 10kΩ → Arduino GND
  • 分壓點 → Arduino A0
  • Arduino D9 → 220Ω → LED 長腳,LED 短腳 → GND

步驟(第一段:觀察)

  1. 先上傳這個觀察程式:
const int ldrPin = A0;      // 光敏電阻分壓點接 A0

void setup() {
  Serial.begin(9600);       // 打開序列埠
}

void loop() {
  int light = analogRead(ldrPin);   // 讀亮度,越亮數字越大
  Serial.print("light:");           // 標籤加冒號,繪圖器會顯示名稱
  Serial.println(light);
  delay(50);                        // 每 0.05 秒畫一個點
}
  1. 打開「工具 → 序列繪圖器(Serial Plotter)」,右上角速度選 9600。你會看到一條線在畫面上慢慢往左捲動。
  2. 用手掌蓋住光敏電阻,線會往下掉;移開,線又升回來。用手機手電筒照它,線會衝到更高。
  3. 記下三個數字:正常教室亮度、用手蓋住、手電筒照。把它們填進下面的表格。
  4. 決定一個門檻值(Threshold):取「正常亮度」和「手蓋住」的中間值。例如正常是 700、蓋住是 150,門檻就取大約 400。

步驟(第二段:自動夜燈) 6. 把你的門檻值填進下面程式的 threshold,上傳。

const int ldrPin = A0;        // 光敏電阻分壓點接 A0
const int ledPin = 9;         // LED 接 D9
const int threshold = 400;    // 門檻值:先用繪圖器觀察,再改成你的數字

void setup() {
  pinMode(ledPin, OUTPUT);    // D9 設成輸出
  Serial.begin(9600);         // 打開序列埠方便觀察
}

void loop() {
  int light = analogRead(ldrPin);   // 讀亮度

  if (light < threshold) {          // 比門檻暗 → 天黑了
    digitalWrite(ledPin, HIGH);     // 開燈
  } else {                          // 比門檻亮 → 還是白天
    digitalWrite(ledPin, LOW);      // 關燈
  }

  Serial.print("light:");           // 順便印出來,可以用繪圖器看
  Serial.println(light);
  delay(100);                       // 每 0.1 秒判斷一次
}
  1. 用手蓋住光敏電阻,LED 應該亮;移開,LED 應該熄。
  2. 慢慢把手靠近又移開,找到 LED 剛好切換的那個位置,看看繪圖器上的數字是不是正好在門檻附近。

你應該看到 繪圖器上是一條會隨著光線上下起伏的曲線,蓋住時掉到一兩百,照手電筒時衝到九百多。夜燈程式上傳後,蓋住就亮、放開就熄,像路燈一樣。

觀察與記錄

情況light 讀值算出的 A0 電壓(讀值 × 5 ÷ 1023)
正常教室亮度
用手掌蓋住
手機手電筒直射
我決定的門檻值

實驗 13-3:DHT11 讀溫度與濕度

材料

  • Arduino UNO 與 USB 線
  • DHT11 溫濕度感測器(模組版 3 腳,或裸件 4 腳)
  • 10kΩ 電阻(裸件版才需要)
  • 麵包板、杜邦線

接線

 Arduino 5V  ──────────── DHT11 VCC(+)
 Arduino D2  ─────┬────── DHT11 DATA(OUT)
                  │
               [ 10kΩ ]   ← 裸件版才要加,一端接 5V
                  │
 Arduino 5V  ─────┘
 Arduino GND ──────────── DHT11 GND(-)

  • DHT11 VCC → Arduino 5V
  • DHT11 DATA → Arduino D2
  • DHT11 GND → Arduino GND
  • 如果你的 DHT11 是 4 隻腳的裸件(沒有小電路板),要在 DATA 和 5V 之間加一個 10kΩ 上拉電阻;3 腳模組版通常已經內建,不用加。腳位順序請看模組板子上的印刷字(+、OUT、-),不同廠牌順序不一樣。

步驟

  1. 安裝函式庫:Arduino IDE 左側點「函式庫管理員」(或「工具 → 管理程式庫」),搜尋 DHT sensor library(作者 Adafruit),按安裝;它會問你要不要一起裝 Adafruit Unified Sensor,選「全部安裝」。如果沒有問,就再搜尋一次 Adafruit Unified Sensor 自己裝。
  2. 輸入下面程式並上傳:
#include "DHT.h"              // 載入 DHT 函式庫

#define DHTPIN 2              // DATA 接 D2
#define DHTTYPE DHT11         // 我們用的是 DHT11

DHT dht(DHTPIN, DHTTYPE);     // 建立一個叫 dht 的感測器物件

void setup() {
  Serial.begin(9600);         // 打開序列埠
  dht.begin();                // 啟動感測器
}

void loop() {
  delay(2000);                            // DHT11 很慢,每 2 秒讀一次
  float humidity = dht.readHumidity();    // 讀濕度(%)
  float temp = dht.readTemperature();     // 讀溫度(°C)

  if (isnan(humidity) || isnan(temp)) {   // isnan = 不是數字,代表讀失敗
    Serial.println("讀取失敗,檢查接線");
    return;                               // 跳過這一輪
  }

  Serial.print("溫度 = ");
  Serial.print(temp, 1);                  // 保留 1 位小數
  Serial.print(" C   濕度 = ");
  Serial.print(humidity, 0);              // 濕度只印整數
  Serial.println(" %");
}
  1. 打開序列埠監控視窗(9600),每 2 秒會出現一行溫濕度。
  2. 用手指捏住感測器 30 秒,看溫度有沒有慢慢上升。
  3. 對著感測器呵一口氣(像對鏡子哈氣那樣),看濕度跳多少。

你應該看到 室內大約 20–30°C、濕度 50–80%(台灣很潮濕)。捏住後溫度會慢慢爬 1–3 度;呵氣後濕度會瞬間衝到 90% 以上,然後慢慢降回來。DHT11 反應不快,變化要等幾秒才看得到。

觀察與記錄

情況溫度(°C)濕度(%)
一開始
手捏 30 秒後
呵氣後馬上
呵氣後 1 分鐘

ESP32 版本怎麼改

如果你用 ESP32 DevKit V1,有三件事要改:

  1. 類比輸入腳改用 GPIO 34(analogRead(34)),它是「只能輸入」的腳,最適合讀感測器。
  2. 分壓器的電源改接 3.3V,絕對不要把 5V 接進 ADC 腳。
  3. 換算公式改成 raw * 3.3 / 4095.0,讀值範圍是 0–4095。
const int ldrPin = 34;      // ESP32 用 GPIO 34 讀類比

void setup() {
  Serial.begin(115200);     // ESP32 習慣用 115200
}

void loop() {
  int raw = analogRead(ldrPin);            // 0~4095
  float voltage = raw * 3.3 / 4095.0;      // 滿刻度是 3.3V
  Serial.print("raw:");
  Serial.print(raw);
  Serial.print(",volt:");                  // 逗號分隔,繪圖器畫兩條線
  Serial.println(voltage);
  delay(100);
}

ESP32 的 ADC 在接近 0V 和接近 3.3V 的兩端比較不準(會黏在 0 或 4095),這是它的硬體特性,中間範圍是準的。

用儀器看看

用示波器看分壓點電壓「慢慢變」

ADC 讀到的數字到底對不對?我們直接用示波器看 A0 腳上的真實電壓。

  • 接線:示波器 CH1 探棒鉤在 A0(分壓點),黑色接地夾一定夾 Arduino GND。探棒切 10×,示波器上也設定 10×。
  • 設定:耦合選 DC;垂直 1V/div,把 0V 基準線移到畫面最下面一格;水平 500ms/div(或用「滾動模式 Roll」,很多示波器在 s/div 很慢的時候會自動切換成滾動);觸發選「自動(Auto)」。
  • 操作:用手蓋住光敏電阻再放開,重複幾次。

你應該看到一條水平線在上下移動,像這樣:

電壓
 5V ┤
 4V ┤────────╮                 ╭──────────      ← 手移開,亮
 3V ┤        │                 │
 2V ┤        │                 │
 1V ┤        ╰─────────────────╯                ← 手蓋住,暗
 0V ┼──────────────────────────────────── 時間
            500ms/div,整個畫面 5 秒

線的高度就是 A0 的電壓。同時看序列埠監控視窗,把「示波器上的電壓」和「讀值 × 5 ÷ 1023」算出來的數字對照,兩者應該一致。你會發現線不是瞬間跳上跳下,而是有一點點圓角,因為光敏電阻本身反應需要幾十毫秒。

把 CH2 探棒鉤到 D9(LED 腳),你就能同時看到「A0 掉到門檻以下」和「D9 跳到 5V」是幾乎同時發生的。

用三用電表量 DHT11 的供電

DHT11 沒有類比輸出,示波器看它的 DATA 腳只會看到一串快速脈波(下一章之後的邏輯分析儀會更適合解讀)。但你可以用三用電表確認它有吃到電:直流電壓檔,紅棒碰 VCC、黑棒碰 GND,應該量到接近 5V。如果量到 0V,就是電源線沒接到。

常見錯誤與除錯

  • 讀值一直是 0 或一直是 1023 不會變 → A0 線沒接到分壓點,或是分壓點直接接到 GND / 5V → 檢查杜邦線是不是插在同一列,用三用電表量分壓點電壓。
  • 讀值亂跳,沒接東西也有數字 → 類比腳「浮接」(Floating)時會撿到空氣裡的雜訊,這是正常的 → 確定 A0 真的接到分壓器。
  • 換算出來的電壓都是整數(2、3、4) → 用了整數除法 raw * 5 / 1023 → 改成 raw * 5.0 / 1023.0。
  • 序列繪圖器一片空白或畫面亂跳 → 速度(鮑率)沒選 9600,或程式印的不是純數字 → 確認右上角速度,每一行只印「標籤:數字」。
  • 序列繪圖器打不開,說連接埠被占用 → 序列埠監控視窗和繪圖器不能同時開 → 先關掉其中一個。
  • 光敏電阻蓋住反而讀值變大 → 你把 LDR 和 10kΩ 的位置接反了 → 兩種接法都能用,只要把程式的 < 改成 >,或換回本章的接法。
  • DHT11 一直「讀取失敗」 → DATA 腳接錯、沒有上拉電阻(裸件版)、或讀太快 → 看模組印刷字對腳位,delay(2000) 不要改小,裸件版加 10kΩ 上拉。
  • 編譯錯誤說找不到 DHT.h → 函式庫沒裝好 → 重新到函式庫管理員搜尋「DHT sensor library」和「Adafruit Unified Sensor」兩個都裝。
  • ESP32 讀值永遠 4095 → 接了 5V 進 ADC 腳,或分壓器電源接到 5V → 立刻改接 3.3V,確認腳位沒燒壞。

想一想

  1. Arduino UNO 讀到 analogRead() = 819,請問 A0 上大約是幾伏特?
參考答案

819 × 5 ÷ 1023 = 4095 ÷ 1023 ≈ 4.00V。

  1. ESP32 的 GPIO 34 量到 1.1V,analogRead(34) 大約會回傳多少?
參考答案

把公式倒過來:讀值 = 電壓 × 4095 ÷ 3.3 = 1.1 × 4095 ÷ 3.3 = 4504.5 ÷ 3.3 = 1365。

  1. 本章的光敏電阻接法是「5V → LDR → A0 → 10kΩ → GND」。如果把 10kΩ 換成 100kΩ,在同樣的亮度下(LDR = 10kΩ),A0 的電壓會變高還是變低?算算看。
參考答案

原本:5 × 10 ÷ (10 + 10) = 2.5V。換成 100kΩ:5 × 100 ÷ (10 + 100) = 500 ÷ 110 ≈ 4.55V,變高了。下面的電阻越大,分到的電壓越多。換電阻會改變整個讀值範圍,所以門檻值也要重新觀察。

  1. map(300, 0, 1023, 0, 255) 會得到多少?為什麼 map() 不會自動幫你四捨五入?
參考答案

300 × 255 ÷ 1023 = 76500 ÷ 1023 ≈ 74.78,map() 用整數運算,小數直接捨去,得到 74。因為 Arduino 的 map() 是用整數(long)計算的,速度快但不會四捨五入;如果需要精確,自己用 float 算。

  1. 夜燈程式有一個小毛病:當亮度剛好在門檻附近時,LED 會一直閃爍(亮、暗、亮、暗)。想一想為什麼,你能不能改程式讓它不要閃?(提示:用兩個門檻。)
參考答案

因為讀值會有小小的雜訊,在 399 和 401 之間跳來跳去,每跳一次 LED 就切換一次。解法叫「遲滯(Hysteresis)」:用兩個門檻,例如低於 350 才開燈、高於 450 才關燈,中間 350–450 這段維持原狀。程式可以寫成: if (light < 350) digitalWrite(ledPin, HIGH); else if (light > 450) digitalWrite(ledPin, LOW); 中間的情況什麼都不做,LED 就不會抖。另一個方法是連續讀 10 次取平均,把雜訊平掉。

  1. 開放挑戰:把實驗 13-2 和 13-3 合併,做一個「天黑而且溫度低於 20°C 才開燈」的程式。你會用到第 11 章學的哪一個邏輯閘?
參考答案

AND 閘。條件寫成 if (light < threshold && temp < 20.0)。要注意 DHT11 每 2 秒才讀一次,但光敏電阻可以隨時讀,所以可以把溫度存在一個變數裡,每 2 秒更新一次,而亮度每 0.1 秒判斷一次。

本章小結

  • 數位訊號像樓梯只有幾階,類比訊號像斜坡可以是任何值;真實世界大多是類比的。
  • ADC 把電壓翻譯成整數:UNO 是 10 位元(0–1023,滿刻度 5V),ESP32 是 12 位元(0–4095,滿刻度 3.3V)。
  • 換算公式:UNO 電壓 = 讀值 × 5 ÷ 1023;ESP32 電壓 = 讀值 × 3.3 ÷ 4095。程式裡要用小數運算。
  • 光敏電阻是「會變的電阻」,要靠 10kΩ 電阻組成分壓器才能被 ADC 量到;本章接法是越亮讀值越大。
  • map() 做比例換算,只保留整數。
  • 序列繪圖器把數字畫成曲線,是觀察感測器最快的方法;門檻值要先觀察再決定。
  • DHT11 透過函式庫讀取,每次至少間隔 1 秒,讀失敗要用 isnan() 檢查。
  • ESP32 的類比腳絕對不能接 5V。

名詞表

中文英文一句話解釋
類比訊號Analog Signal電壓可以是範圍內任何值的訊號,像斜坡。
數位訊號Digital Signal只有固定幾種狀態(通常是 0 和 1)的訊號,像樓梯。
類比數位轉換器Analog-to-Digital Converter(ADC)把電壓翻譯成整數的電路,藏在微控制器裡。
位元bit一個 0 或 1;10 位元的 ADC 有 1024 種讀值。
解析度ResolutionADC 能分辨的最小電壓差,UNO 約 4.9mV。
光敏電阻Light Dependent Resistor(LDR)越亮電阻越小的元件。
分壓器Voltage Divider兩個電阻串聯,中間點分到一部分電壓。
門檻值Threshold用來判斷「夠暗了沒」的分界數字。
遲滯Hysteresis用兩個門檻避免在分界附近抖動。
函式庫Library別人寫好、打包起來讓你直接呼叫的程式。
序列繪圖器Serial PlotterArduino IDE 裡把序列埠數字畫成曲線的工具。
浮接Floating腳位沒有接任何東西,讀值會亂跳。

第 14 章 PWM 與馬達控制

本章目標

學完這一章,你會:

  • 解釋 PWM 是怎麼用「開開關關」做出「半亮」的效果,並算出占空比與平均電壓。
  • 用 analogWrite()(0–255)做出會呼吸的 LED,並用示波器量出它的頻率和占空比。
  • 用 Servo 函式庫讓 SG90 伺服馬達轉到指定角度,並在示波器上看到 50Hz、脈寬 0.5–2.5ms 的控制訊號。
  • 用 IRLZ44N MOSFET 加飛輪二極體,安全地用 PWM 調整直流馬達的轉速。
  • 知道 ESP32 用 ledcAttach() / ledcWrite() 做 PWM,和 UNO 有什麼不一樣。

開場:Arduino 只會開和關,怎麼做出「半亮」?

上一章你學會讓 Arduino 讀「有多亮」,讀到的是一個 0 到 1023 的數字。那反過來呢?你想讓 LED「亮一半」、讓風扇「轉慢一點」,怎麼辦?

問題是,Arduino 的數位腳只有兩招:HIGH 輸出 5V,LOW 輸出 0V。沒有「2.5V」這個選項。

想像你拿著手電筒在黑暗的房間裡,快速地開、關、開、關。如果每秒開關幾百次,你的眼睛根本跟不上,只會覺得房間「有點亮」。如果開的時間比關的時間長,就覺得比較亮;開得短、關得長,就覺得比較暗。眼睛被騙了,但騙得很有用。

這一章的主角就是這招,叫做 PWM。它能讓 LED 慢慢呼吸、讓伺服馬達精準轉到 90 度、讓直流馬達從慢速平順加到全速。幾乎所有會動、會變亮的電子作品,背後都是 PWM 在工作。

核心概念

PWM:用時間比例騙過眼睛和馬達

脈波寬度調變(Pulse Width Modulation,PWM) 就是用很快的開關,控制「開著的時間」占全部時間的比例。這個比例叫做占空比(Duty Cycle),第 10 章我們已經在示波器上看過它:

占空比 = 高電位時間 ÷ 一個週期的時間 × 100%

占空比 25% 表示每個週期裡有四分之一時間是 5V,四分之三時間是 0V。對 LED 來說,它「平均」收到的電壓就是:

平均電壓 = 5V × 占空比

占空比 25% 的平均電壓是 5 × 0.25 = 1.25V;占空比 75% 是 5 × 0.75 = 3.75V。

      占空比 25%                     占空比 75%
 5V ┤ ┌─┐     ┌─┐     ┌─┐      5V ┤ ┌─────┐ ┌─────┐ ┌─────┐
    │ │ │     │ │     │ │         │ │     │ │     │ │     │
 0V ┼─┘ └─────┘ └─────┘ └──    0V ┼─┘     └─┘     └─┘     └─
      ◄──────►                      ◄──────►
       一個週期                       一個週期

重點:PWM 的電壓從來沒有真的變成 1.25V,它永遠只有 5V 和 0V 兩種,只是時間的比例變了。眼睛和馬達反應慢,感覺不出閃爍,只感覺到平均。

analogWrite():0 到 255

Arduino 用 analogWrite(腳位, 值) 產生 PWM。這個函式名字裡有 analog,但它輸出的其實是數位方波,只是「看起來像類比」。值的範圍是 0 到 255:

  • analogWrite(9, 0):占空比 0%,永遠 0V,LED 全暗。
  • analogWrite(9, 64):占空比 64 ÷ 255 ≈ 25.1%,大約 25%。
  • analogWrite(9, 128):占空比 128 ÷ 255 ≈ 50.2%,大約一半。
  • analogWrite(9, 191):占空比 191 ÷ 255 ≈ 74.9%,大約 75%。
  • analogWrite(9, 255):占空比 100%,永遠 5V,LED 全亮。

為什麼是 255?因為 Arduino 用 8 位元來存這個數字,2 的 8 次方 = 256 種(0–255),這和第 11 章的二進位是同一件事。

UNO 上只有腳位旁邊印著「~」符號的腳才能用 PWM:D3、D5、D6、D9、D10、D11。其他腳叫 analogWrite() 不會有錯誤訊息,但只會變成全開或全關。

PWM 的頻率:UNO 的 490Hz 和 980Hz

PWM 每秒開關幾次?這是頻率(Frequency)。UNO 的 analogWrite() 頻率是固定的:

  • D3、D9、D10、D11:約 490Hz,一個週期 = 1 ÷ 490 ≈ 0.00204 秒 ≈ 2.04ms。
  • D5、D6:約 980Hz,一個週期 = 1 ÷ 980 ≈ 1.02ms。

算一下 D9 用 analogWrite(9, 64) 時,高電位會持續多久:

高電位時間 = 週期 × 占空比 = 2.04ms × 0.251 ≈ 0.51ms

analogWrite(9, 191) 呢?2.04ms × 0.749 ≈ 1.53ms。等一下我們會用示波器直接量到這兩個數字。

490Hz 對 LED 來說夠快,眼睛看不出閃。但馬達在 490Hz 下會發出「嗡」的聲音,因為 490Hz 剛好在人耳聽得到的範圍(接近鋼琴的 Si 音)。這不是壞掉,是 PWM 的特性。

伺服馬達:用脈波寬度說「轉到幾度」

伺服馬達(Servo Motor) 和普通馬達不一樣,它不會一直轉,而是「轉到你指定的角度然後停住」。SG90 是最常見的小型伺服,可以轉 0 到 180 度。它裡面有一個小馬達、一組齒輪、一個可變電阻(用來知道現在轉到哪裡)和一顆控制晶片。

SG90 有三條線:

  • 橘色 = 訊號(接 Arduino 的腳位)
  • 紅色 = 5V
  • 棕色 = GND

你怎麼跟它說「轉到 90 度」?也是用脈波,但規則和 analogWrite() 不一樣。伺服馬達要的是每 20ms 一個脈波(也就是 50Hz),而且它看的是脈波有多寬,不是占空比:

  • 脈寬約 0.5ms → 0 度
  • 脈寬約 1.5ms → 90 度(正中間)
  • 脈寬約 2.5ms → 180 度
 5V ┤ ┌─┐                  ┌─┐                  ┌─┐
    │ │ │                  │ │                  │ │
 0V ┼─┘ └──────────────────┘ └──────────────────┘ └────
      ◄►                   ◄►
     1.5ms(90度)        1.5ms
      ◄────────────────────►
            20ms(50Hz)

換算成占空比的話,1.5ms ÷ 20ms = 7.5%,很小,所以不能用 analogWrite() 來控制伺服馬達,要用 Arduino 內建的 Servo 函式庫,它會幫你產生正確的 50Hz 脈波,你只要說 myServo.write(90) 就好。

注意:在 UNO 上使用 Servo 函式庫之後,D9 和 D10 的 analogWrite() 就不能用了,因為它們共用同一個計時器。同一個程式裡要同時用伺服和 PWM 的話,PWM 改接 D5 或 D6。

直流馬達需要「大水閥」:MOSFET 與飛輪二極體

直流馬達轉起來要幾百毫安培的電流,Arduino 的腳位最多只能給 20mA 左右,直接接會燒壞腳位。第 9 章學過的解法:用電晶體當水閥,小電流控制大電流。這裡我們用 N 通道 MOSFET IRLZ44N,它是「邏輯準位」MOSFET,意思是用 Arduino 的 5V(甚至 ESP32 的 3.3V)就可以把它完全打開,能通過好幾安培。

IRLZ44N 的三隻腳,把印字那面朝向自己,從左到右是 G(閘極)、D(汲極)、S(源極)。G 像水閥的把手,D 和 S 是水管的兩端:G 的電壓夠高,D 和 S 之間就通。

接線的三個重點:

  1. G 前面串 220Ω:MOSFET 的閘極像一個小電容,剛打開的瞬間會吸一股電流,220Ω 把它限制在 5 ÷ 220 ≈ 23mA 以下,保護 Arduino 腳位。
  2. G 到 GND 加 10kΩ 下拉電阻:Arduino 上傳程式或重開機的瞬間,腳位是浮接的,10kΩ 會把閘極拉到 0V,讓馬達乖乖停著,不會突然暴衝。
  3. 馬達兩端並聯 1N4007 飛輪二極體,有色環那端接 5V:第 7 章學過,馬達是電感,突然切斷電流會產生高壓尖波。PWM 每秒切斷幾百次,沒有二極體的話,MOSFET 很快就被尖波打壞。

把 PWM 送到 G,MOSFET 就跟著開開關關,馬達得到的平均電壓隨占空比改變,轉速也就跟著變。

ESP32 的 PWM:ledcAttach 與 ledcWrite

ESP32 的 PWM 硬體比 UNO 強很多,頻率和位元數都可以自己設定,但函式不一樣。ESP32 Arduino core 3.x 版用兩個函式:

ledcAttach(腳位, 頻率, 解析度位元數);   // 設定:這隻腳要用幾 Hz、幾位元
ledcWrite(腳位, 占空比數值);            // 輸出:0 到 (2^位元數 − 1)

例如 ledcAttach(18, 5000, 8) 表示 GPIO 18 用 5000Hz、8 位元(0–255);然後 ledcWrite(18, 128) 就是 50%。如果設定 10 位元,範圍就變成 0–1023,ledcWrite(18, 512) 才是 50%。

如果你的 Arduino IDE 裝的是舊版 ESP32 core(2.x),要用三個函式,而且要先指定一個「通道」:

ledcSetup(0, 5000, 8);      // 通道 0:5000Hz、8 位元
ledcAttachPin(18, 0);       // 把 GPIO 18 接到通道 0
ledcWrite(0, 128);          // 注意:這裡填的是通道,不是腳位

編譯時如果出現「ledcSetup 沒有定義」,代表你是新版,改用 ledcAttach;反過來出現「ledcAttach 沒有定義」,就是舊版。

動手做

實驗 14-1:呼吸燈,然後量它的占空比

材料

  • Arduino UNO 與 USB 線
  • 紅色 LED 1 個、220Ω 電阻 1 個
  • 麵包板、杜邦線
  • 數位三用電表

接線

 Arduino D9 ──[ 220Ω ]──►|── Arduino GND
                        LED

  • Arduino D9 → 220Ω → LED 長腳,LED 短腳 → GND

步驟

  1. 先上傳這個「固定亮度」程式,用來量測:
const int ledPin = 9;         // LED 接 D9(有 ~ 符號,能用 PWM)

void setup() {
  pinMode(ledPin, OUTPUT);    // D9 設成輸出
  analogWrite(ledPin, 64);    // 占空比約 25%
}

void loop() {
  // 什麼都不做,維持固定亮度
}
  1. 拿三用電表(直流電壓檔 20V),紅棒碰 D9、黑棒碰 GND。電表反應慢,它量到的是平均電壓。
  2. 把 64 改成 128、191、255,每改一次就重新上傳、重新量一次,把數字填進表格。
  3. 現在上傳呼吸燈程式:
const int ledPin = 9;               // LED 接 D9

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  for (int level = 0; level <= 255; level++) {    // 從 0 慢慢加到 255
    analogWrite(ledPin, level);                   // 越來越亮
    delay(4);                                     // 每階停 4ms,共約 1 秒
  }
  for (int level = 255; level >= 0; level--) {    // 從 255 慢慢減到 0
    analogWrite(ledPin, level);                   // 越來越暗
    delay(4);
  }
}
  1. 看 LED 是不是在慢慢亮、慢慢暗,像在呼吸。
  2. 把 LED 從 D9 換到 D13(沒有 ~ 的腳),程式裡的 9 改成 13,再上傳一次,看看發生什麼事。

你應該看到 固定亮度程式:analogWrite(64) 時電表量到大約 1.25V,128 約 2.5V,191 約 3.75V,255 約 5V。呼吸燈程式:LED 用約 2 秒完成一次亮暗循環。換到 D13 之後,LED 不會呼吸,只會在全亮和全暗之間跳,因為 D13 不支援 PWM。

觀察與記錄

analogWrite 的值算出的占空比(值 ÷ 255)算出的平均電壓(5V × 占空比)三用電表量到的電壓
64
128
191
255

實驗 14-2:讓 SG90 伺服馬達轉到指定角度

材料

  • Arduino UNO 與 USB 線
  • SG90 伺服馬達 1 個
  • 杜邦線(公公 3 條)
  • (選用)3 號電池盒 4 顆裝(約 6V),伺服抖動時使用

接線

 SG90 橘線(訊號)──── Arduino D9
 SG90 紅線(5V)  ──── Arduino 5V
 SG90 棕線(GND) ──── Arduino GND

  • SG90 橘線 → Arduino D9
  • SG90 紅線 → Arduino 5V
  • SG90 棕線 → Arduino GND
  • SG90 的接頭是母頭,用公公杜邦線一端插進接頭、另一端插 Arduino。

步驟

  1. 上傳下面的程式:
#include <Servo.h>          // 載入內建的 Servo 函式庫

Servo myServo;              // 建立一個伺服物件
const int servoPin = 9;     // 橘線接 D9

void setup() {
  myServo.attach(servoPin); // 告訴函式庫伺服接在哪隻腳
  Serial.begin(9600);
}

void loop() {
  myServo.write(0);         // 轉到 0 度
  Serial.println("0 度,脈寬約 0.5ms");
  delay(1000);              // 等 1 秒讓它轉到位

  myServo.write(90);        // 轉到 90 度
  Serial.println("90 度,脈寬約 1.5ms");
  delay(1000);

  myServo.write(180);       // 轉到 180 度
  Serial.println("180 度,脈寬約 2.5ms");
  delay(1000);
}
  1. 觀察伺服的擺臂是不是每秒換一個位置:0 度、90 度、180 度,然後重頭來。
  2. 把程式裡的三個角度改成 45、90、135,看擺臂移動的範圍是不是變小了。
  3. 用手輕輕推擺臂(不要用力),感覺它「抵抗」你,這是伺服在自動修正角度。

你應該看到 擺臂每秒跳到一個新位置,轉動時會聽到小小的齒輪聲。三個位置之間各相差 90 度。SG90 的 0 度和 180 度可能不會剛好轉滿,差個 5–10 度是正常的。

觀察與記錄

myServo.write() 的角度擺臂實際位置(用量角器或目測)示波器量到的脈寬
0
45
90
135
180

實驗 14-3:用 MOSFET 和 PWM 幫直流馬達調速

材料

  • Arduino UNO 與 USB 線
  • 小直流馬達(3–6V)1 個
  • N 通道 MOSFET IRLZ44N 1 個
  • 220Ω 電阻 1 個、10kΩ 電阻 1 個
  • 整流二極體 1N4007 1 個
  • 10kΩ 可變電阻 1 個
  • 麵包板、杜邦線
  • (選用)3 號電池盒 3 或 4 顆裝(4.5–6V),馬達吃電太多時使用

接線

                       Arduino 5V ─────┬──────────┐
                                       │          │
                                   [ 馬達 ]    ─┴─  1N4007
                                       │       ▲    (色環朝 5V)
                                       │        │
                                       └────────┴──── D(汲極)
                                                       │
 Arduino D9 ──[ 220Ω ]──┬──────────────────────────── G(閘極)  IRLZ44N
                        │                              │
                     [ 10kΩ ]                          S(源極)
                        │                              │
 Arduino GND ───────────┴──────────────────────────────┘

 可變電阻:左腳 → 5V,右腳 → GND,中間腳 → A0

  • Arduino D9 → 220Ω → IRLZ44N 的 G(閘極)
  • IRLZ44N 的 G → 10kΩ → Arduino GND(下拉)
  • IRLZ44N 的 S(源極)→ Arduino GND
  • 馬達一腳 → Arduino 5V;馬達另一腳 → IRLZ44N 的 D(汲極)
  • 1N4007 並聯在馬達兩端:有色環的那端接 5V 那側,沒色環的那端接 D 那側
  • 可變電阻左腳 → 5V、右腳 → GND、中間腳 → A0
  • IRLZ44N 印字面朝自己,三隻腳從左到右是 G、D、S

步驟

  1. 先不要接馬達,接好其他部分,用三用電表確認 G 到 GND 之間是 10kΩ(確定下拉電阻有接到)。
  2. 接上馬達和二極體。再檢查一次二極體方向,色環朝 5V。接反的話一通電就會短路發燙,要立刻拔掉 USB。
  3. 上傳程式:
const int motorPin = 9;     // D9 → 220Ω → MOSFET 閘極
const int potPin = A0;      // 可變電阻中間腳

void setup() {
  pinMode(motorPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int raw = analogRead(potPin);              // 讀旋鈕 0~1023
  int speed = map(raw, 0, 1023, 0, 255);     // 換成 0~255
  analogWrite(motorPin, speed);              // 送 PWM 給 MOSFET

  Serial.print("speed = ");
  Serial.println(speed);                     // 印出目前的速度值
  delay(100);
}
  1. 慢慢轉動可變電阻,從 0 轉到最大。注意馬達是從多少才開始轉的。
  2. 把耳朵靠近馬達(不要碰到轉軸),聽聽看中速時有沒有「嗡」的聲音。
  3. 如果馬達一轉 Arduino 就重開機(序列埠一直重新出現開頭訊息)或 USB 被電腦斷開,表示馬達吃的電流超過 USB 能給的。改用電池盒:電池盒「+」接馬達(取代 Arduino 5V),電池盒「-」接 Arduino GND,一定要共地。

你應該看到 speed 低於大約 50–80 時馬達只會「嗯」一聲但不動(力道不夠克服摩擦),超過之後開始慢慢轉,越轉越快,到 255 全速。中速時會聽到約 490Hz 的嗡嗡聲。摸 MOSFET 應該只有微溫,不會燙。

觀察與記錄

speed 值占空比馬達狀態(不動 / 慢 / 中 / 快)有沒有嗡嗡聲
30
80
128
191
255
馬達開始轉的最小 speed =

ESP32 版本:用 ledcWrite 做呼吸燈

ESP32 板上的 LED 在 GPIO 2,不用接任何東西就能試:

const int ledPin = 2;                 // ESP32 板上 LED

void setup() {
  ledcAttach(ledPin, 5000, 8);        // 新版 core 3.x:5000Hz、8 位元(0~255)
  // 舊版 core 2.x 改成下面兩行:
  // ledcSetup(0, 5000, 8);
  // ledcAttachPin(ledPin, 0);
}

void loop() {
  for (int level = 0; level <= 255; level++) {
    ledcWrite(ledPin, level);         // 新版填腳位;舊版 ledcWrite(0, level) 填通道
    delay(4);
  }
  for (int level = 255; level >= 0; level--) {
    ledcWrite(ledPin, level);
    delay(4);
  }
}

ESP32 的腳位是 3.3V,拿來推 IRLZ44N 也沒問題,因為它是邏輯準位 MOSFET。但 ESP32 不能用內建的 Servo 函式庫,要到函式庫管理員安裝 ESP32Servo,用法幾乎一樣。

用儀器看看

示波器量 PWM 的頻率與占空比

把實驗 14-1 的固定亮度程式(analogWrite(9, 64))重新上傳。

  • 接線:CH1 探棒鉤在 D9(或 LED 的 220Ω 靠 Arduino 那端),黑色接地夾夾 Arduino GND。探棒 10×。
  • 設定:耦合 DC;垂直 2V/div(5V 剛好 2.5 格);水平 500µs/div,這樣一個 2.04ms 的週期大約占 4 格,畫面上可以看到兩個多週期;觸發選 CH1、上升緣(Rising)、準位調到約 2.5V;模式「自動(Auto)」。

你應該看到:

電壓
 5V ┤ ┌──┐        ┌──┐        ┌──┐
    │ │  │        │  │        │  │
 0V ┼─┘  └────────┘  └────────┘  └──── 時間
      ◄─►
     0.51ms
      ◄──────────►
         2.04ms(490Hz)

自動量測法:按 Measure(量測)鍵,加入 Freq(頻率)、Period(週期)、+Duty(正占空比) 和 +Width(正脈寬)。你應該讀到 Freq ≈ 490Hz、Period ≈ 2.04ms、+Duty ≈ 25%、+Width ≈ 0.51ms。

游標法:如果你的示波器沒有 +Duty,用時間游標(Cursor)。把游標 1 放在上升緣、游標 2 放在同一個脈波的下降緣,讀出 Δt 就是高電位寬度;再把游標 2 移到下一個上升緣,讀出週期。占空比 = 高電位寬度 ÷ 週期。例如 0.51ms ÷ 2.04ms = 0.25 = 25%。

接著把程式改成 analogWrite(9, 191),脈波會變寬,+Duty 應該變成約 75%、+Width 約 1.53ms,但 Freq 不變還是 490Hz。這就是 PWM 的本質:頻率不動,只動寬度。

再把 LED 換到 D5、程式改 analogWrite(5, 64),水平改 200µs/div。你會發現 Freq 變成約 980Hz、Period 約 1.02ms,占空比還是 25%。

示波器看伺服馬達的 50Hz 脈波

上傳實驗 14-2 的程式,CH1 探棒鉤在 SG90 的橘線(D9),接地夾夾 GND。

  • 先把水平設成 5ms/div:你會看到每 4 格(20ms)出現一根細細的脈波,這就是 50Hz。
  • 再把水平縮小到 500µs/div,觸發上升緣,讓脈波放大:
      0 度                90 度                180 度
 5V ┤ ┌┐             5V ┤ ┌──┐           5V ┤ ┌────┐
    │ ││                │ │  │              │ │    │
 0V ┼─┘└──────       0V ┼─┘  └─────      0V ┼─┘    └───
      ◄►                  ◄──►                ◄────►
     0.5ms               1.5ms               2.5ms

用 +Width 量測,每秒切換一次角度時,數字會在 0.5ms、1.5ms、2.5ms 附近跳。把量到的值填回實驗 14-2 的表格。

示波器同時看閘極與汲極

實驗 14-3 的馬達電路,CH1 鉤 G(閘極)、CH2 鉤 D(汲極),接地夾夾 GND,兩個通道都 2V/div、500µs/div,觸發 CH1 上升緣。你會看到兩條波形剛好相反:G 是 5V 時 MOSFET 導通、D 被拉到 0V;G 是 0V 時 MOSFET 關閉、D 被馬達拉回 5V。在 D 關閉的瞬間可能看到一個小小的尖角,那就是被二極體壓住的反電動勢;把二極體暫時拔掉(只看一下下就要裝回去),尖角會變成高好幾伏特的尖波。

常見錯誤與除錯

  • LED 不會呼吸,只會全亮全暗 → 接到沒有 ~ 符號的腳 → 換到 D3/D5/D6/D9/D10/D11。
  • 示波器量到的占空比和算的差很多 → 觸發準位不對,或探棒 1×/10× 設定和示波器不符 → 把觸發準位調到波形中間,確認探棒倍率。
  • 示波器波形一直在跑,停不下來 → 觸發源沒選 CH1,或模式在「自動」但準位超出波形範圍 → 選 CH1 上升緣,準位 2.5V。
  • 伺服馬達抖動、嗡嗡響、或 Arduino 一直重開機 → 伺服吃電太多,USB 供電不夠 → 用 4 顆 3 號電池盒(約 6V)供電給紅線,棕線和 Arduino GND 共地。
  • 伺服只往一邊轉到底不停 → 橘線接錯腳,或 attach() 的腳號打錯 → 檢查程式和接線。
  • 程式裡同時用 Servo 和 analogWrite(9),PWM 沒反應 → Servo 函式庫占用了 D9/D10 的計時器 → PWM 改接 D5 或 D6。
  • 馬達完全不轉,MOSFET 不熱 → G 沒有收到訊號,可能 220Ω 沒接到 G,或 G/D/S 三隻腳認錯 → 印字面朝自己,從左到右 G、D、S;用三用電表量 G 腳電壓,PWM 255 時應接近 5V。
  • 馬達一直全速轉,調旋鈕沒用 → D 和 S 接反,或馬達接錯邊 → 對照接線圖重接。
  • MOSFET 或二極體發燙 → 二極體接反變成短路,或馬達卡住 → 立刻拔掉 USB,檢查色環方向。
  • ESP32 編譯錯誤:ledcSetup / ledcAttach 未定義 → core 版本不同 → 新版用 ledcAttach,舊版用 ledcSetup + ledcAttachPin。

想一想

  1. analogWrite(9, 51) 的占空比是多少?平均電壓大約幾伏特?
參考答案

占空比 = 51 ÷ 255 = 0.2 = 20%。平均電壓 = 5V × 0.2 = 1.0V。

  1. 在 D9(490Hz)上輸出 analogWrite(9, 128),示波器上高電位會有多寬?如果改到 D5(980Hz)呢?
參考答案

D9:週期 2.04ms × (128 ÷ 255) = 2.04 × 0.502 ≈ 1.02ms。D5:週期 1.02ms × 0.502 ≈ 0.51ms。占空比一樣是 50%,但週期短一半,所以脈波也窄一半。

  1. 伺服馬達的脈寬 1.5ms 對應 90 度。請問脈寬 1.0ms 大約對應幾度?(假設 0.5ms 到 2.5ms 是線性對應 0 到 180 度。)
參考答案

0.5ms 到 2.5ms 共 2.0ms 對應 180 度,所以每 1ms 對應 90 度。1.0ms 比 0.5ms 多 0.5ms,所以是 0.5 × 90 = 45 度。

  1. 為什麼實驗 14-3 要在閘極加 10kΩ 下拉電阻?如果拿掉它,上傳程式的那幾秒鐘會發生什麼事?
參考答案

上傳程式或重開機時,Arduino 的腳位處於浮接狀態,閘極像天線一樣可能撿到雜訊而半開,馬達會突然抖動或轉動。10kΩ 把閘極牢牢拉到 0V,確保沒有訊號時 MOSFET 一定是關的。這在控制比較大的馬達時非常重要。

  1. 有人說「PWM 占空比 50% 就是輸出 2.5V」,用示波器的角度來看,這句話哪裡不精確?
參考答案

示波器上看到的永遠是 5V 和 0V 的方波,從來沒有 2.5V。「2.5V」是平均值,只有對反應慢的東西(LED 的亮度、馬達的轉速、三用電表的讀數)才成立。如果真的要得到穩定的 2.5V 直流,要像第 10 章那樣加 RC 低通濾波器把方波平均掉。

  1. 開放挑戰:把第 13 章的光敏電阻和本章的呼吸燈結合,做一個「越暗越亮」的智慧夜燈:環境越暗,LED 越亮,而不是只有開和關。提示:用 map(),但要注意方向。
參考答案

讀值越小(越暗)要讓 PWM 越大,所以 map 的目標範圍要反過來:int level = map(light, 0, 1023, 255, 0);,然後 analogWrite(ledPin, level)。更好的做法是先用繪圖器找出教室裡實際的最暗和最亮讀值(例如 100 和 800),用 map(light, 100, 800, 255, 0) 再加 constrain(level, 0, 255) 把超出範圍的值夾住。

本章小結

  • PWM 用「開著的時間比例」騙過眼睛和馬達,占空比 = 高電位時間 ÷ 週期,平均電壓 = 5V × 占空比。
  • analogWrite(腳位, 0–255),64 約 25%、128 約 50%、191 約 75%;UNO 只有 D3/D5/D6/D9/D10/D11 能用。
  • UNO 的 PWM 頻率固定:D3/D9/D10/D11 約 490Hz(週期 2.04ms),D5/D6 約 980Hz(週期 1.02ms)。PWM 改的是寬度,不是頻率。
  • 示波器用 Measure 的 +Duty、+Width、Freq 可以直接量占空比;沒有的話用游標量高電位寬度 ÷ 週期。
  • SG90 伺服馬達:橘=訊號、紅=5V、棕=GND;吃 50Hz(20ms)脈波,脈寬 0.5–2.5ms 對應 0–180 度;用 Servo 函式庫的 write(角度)。
  • 直流馬達要用 IRLZ44N 當開關:D9 → 220Ω → G,G 加 10kΩ 下拉,S 接 GND,馬達接 5V 與 D,馬達兩端並聯 1N4007(色環朝 5V)。
  • ESP32 新版 core 用 ledcAttach(pin, freq, bits) + ledcWrite(pin, duty);舊版用 ledcSetup + ledcAttachPin + ledcWrite(channel, duty)。

名詞表

中文英文一句話解釋
脈波寬度調變Pulse Width Modulation(PWM)用快速開關的時間比例,做出像是「半亮」的效果。
占空比Duty Cycle高電位時間占一個週期的百分比。
脈寬Pulse Width一個脈波高電位持續的時間,伺服馬達靠它判斷角度。
平均電壓Average VoltagePWM 對反應慢的負載來說等效的電壓,= 5V × 占空比。
伺服馬達Servo Motor會轉到指定角度並停住的馬達,SG90 是常見小型款。
閘極 / 汲極 / 源極Gate / Drain / SourceMOSFET 的三隻腳:把手、入口、出口。
邏輯準位 MOSFETLogic-Level MOSFET用 3.3V 或 5V 就能完全打開的 MOSFET,如 IRLZ44N。
下拉電阻Pull-down Resistor把腳位在沒訊號時拉到 0V 的電阻,避免浮接亂動。
飛輪二極體Flyback Diode並聯在馬達兩端,吸收切斷電流時的高壓尖波。
計時器Timer微控制器裡負責產生 PWM 的硬體,Servo 函式庫會占用它。
LEDCLED ControlESP32 產生 PWM 的硬體模組,用 ledcAttach / ledcWrite 操作。

第 15 章 通訊協定與邏輯分析儀

本章目標

學完這一章,你會:

  • 說出晶片之間為什麼要「講話」,以及序列與並列傳輸的差別。
  • 畫出 UART 一個字元的波形:閒置、起始位元、8 個資料位元、停止位元,並算出 9600 鮑率下每個位元有多長。
  • 解釋 I2C 的 SDA/SCL、位址、主從,以及 START、ACK、STOP 在波形上長什麼樣。
  • 安裝 PulseView、接上 USB 邏輯分析儀、設定取樣率、加上解碼器,把 Arduino 送出的 “Hello” 和 OLED 的位址 0x3C 從波形裡「翻譯」出來。
  • 說出示波器和邏輯分析儀各自擅長什麼。

開場:Arduino 跟電腦是怎麼「講話」的?

前面幾章你一直在用 Serial.println() 把數字印到電腦畫面上。你有沒有想過,Arduino 和電腦之間只有一條 USB 線,這條線裡面到底發生了什麼事?Arduino 又不會打字,它怎麼把「Hello」這五個字母送過去?

答案是:它只會送 0 和 1。Arduino 把每一個字母拆成 8 個 0/1,用一條線、按照講好的速度、一個接一個地送出去。電腦照同樣的速度接收,再拼回字母。這種「事先講好的規則」叫做通訊協定(Protocol),就像兩個人要通電話,得先講好用什麼語言、講多快。

同樣的事情也發生在 Arduino 和 OLED 螢幕之間、和溫濕度感測器之間、ESP32 和 Wi-Fi 晶片之間。只要兩顆晶片要交換資料,就一定有一套協定。

問題是,這些 0 和 1 跑得太快了,示波器看得到波形但很難一個一個數。這一章我們要拿出新工具:邏輯分析儀。它能一次錄下好幾條線上的 0 和 1,然後自動幫你翻譯成字母和數字。你會親眼看到 “Hello” 從一堆方波裡跳出來。

核心概念

序列與並列:一條線排隊走,還是八條線一起走

要送一個 8 位元的數字(例如字母 H = 01001000),有兩種方法:

  • 並列(Parallel):用 8 條線,每條線負責一個位元,一次全部送出去。快,但線很多。
  • 序列(Serial):只用 1 條線,8 個位元排隊、一個一個送。線少,但要花 8 倍時間。

就像 8 個人要過一道門:並列是開 8 道門同時走,序列是只開 1 道門排隊走。現代的晶片幾乎都用序列,因為線少、便宜、不容易出錯,而且反正晶片跑得夠快。本章的 UART、I2C、SPI 全都是序列通訊。

UART:最老也最簡單的講話方式

UART(Universal Asynchronous Receiver-Transmitter,通用非同步收發器) 就是 Arduino 和電腦之間用的協定。它只需要兩條線:

  • TX(Transmit):送資料出去。UNO 的 TX 是 D1。
  • RX(Receive):接資料進來。UNO 的 RX 是 D0。

一方的 TX 接另一方的 RX,交叉接,而且兩邊 GND 要接在一起。

UART 沒有時脈線,所以雙方必須事先講好速度,這個速度叫鮑率(Baud Rate),單位是「每秒幾個位元」。Serial.begin(9600) 的 9600 就是鮑率:每秒送 9600 個位元,所以每個位元持續:

1 秒 ÷ 9600 = 0.000104 秒 ≈ 104µs

一個字元怎麼送?規則是這樣(最常見的「8N1」格式):

  1. 沒事的時候線上保持 HIGH(閒置)。
  2. 要送字元了,先把線拉 LOW 一個位元的時間,這叫起始位元(Start Bit),通知對方「要開始了」。
  3. 接著送 8 個資料位元,而且是最低位元(LSB)先送。
  4. 最後把線拉 HIGH 一個位元的時間,這是停止位元(Stop Bit),然後回到閒置。

所以一個字元總共 1 + 8 + 1 = 10 個位元,在 9600 鮑率下要花 10 × 104µs ≈ 1.04ms。Serial.println("Hello") 會送 H、e、l、l、o 再加換行的 \r 和 \n,共 7 個字元,大約 7.3ms。

來畫字母 H 的波形。H 的 ASCII 碼是 0x48,二進位是 0100 1000(從高位 b7 寫到低位 b0)。LSB 先送,所以送出的順序是 b0 到 b7:0、0、0、1、0、0、1、0。

HIGH ────┐               ┌───┐       ┌───┐   ┌─────────
         │               │   │       │   │   │
LOW      └───┴───┴───┴───┘   └───┴───┘   └───┘
   閒置  起始 b0  b1  b2  b3  b4  b5  b6  b7 停止  閒置
          0   0   0   0   1   0   0   1   0   1
         ◄──►
        104µs(9600 鮑率)
         ◄───────────────────────────────────►
                   10 個位元 ≈ 1.04ms

讀的那一方看到線從 HIGH 掉到 LOW,就知道起始位元來了,然後每隔 104µs 偷看一次線的狀態,連看 8 次,就得到 8 個位元,再倒過來排就是 0x48 = H。

如果兩邊鮑率不同會怎樣?送的人每 104µs 送一個位元,收的人卻每 8.7µs 看一次(115200 鮑率),看到的全是錯的,畫面上就會出現一堆亂碼。這就是為什麼序列埠監控視窗右下角的速度一定要和程式一樣。

I2C:兩條線接一堆裝置

UART 只能兩個人講話。如果 Arduino 要同時跟 OLED、溫度感測器、時鐘晶片講話,每個都要兩條線,腳位很快就不夠用。I2C(Inter-Integrated Circuit) 解決這個問題:只用兩條線,就可以接很多裝置。

  • SDA(Serial Data):資料線。UNO 是 A4。
  • SCL(Serial Clock):時脈線。UNO 是 A5。

I2C 有時脈線,所以不需要事先講好速度,SCL 每跳一下,SDA 上就是一個位元。Arduino 的 Wire 函式庫預設 SCL 是 100kHz(每個位元 10µs),很多函式庫會加快到 400kHz。

這麼多裝置共用兩條線,怎麼知道在跟誰講?每個裝置有一個 7 位元的位址(Address),像門牌號碼。我們的 0.96 吋 OLED(SSD1306)位址是 0x3C。發話的那一方叫主機(Master),通常是 Arduino;被叫到的叫從機(Slave),例如 OLED。只有主機可以主動開口。

一次完整的 I2C 對話長這樣:

  1. START:SCL 是 HIGH 的時候,SDA 從 HIGH 掉到 LOW。這個組合平常不會出現,所以大家一看就知道「有人要講話了」。
  2. 主機送 7 位元位址 + 1 個讀寫位元(0 = 寫,1 = 讀),高位元先送(和 UART 相反)。
  3. ACK(Acknowledge):第 9 個時脈時,被叫到的從機把 SDA 拉 LOW,表示「有,我在」。沒人回應的話 SDA 保持 HIGH,叫 NACK。
  4. 主機送一個或多個資料位元組,每個後面都有一個 ACK。
  5. STOP:SCL 是 HIGH 的時候,SDA 從 LOW 升回 HIGH,結束對話。
          START   A6  A5  A4  A3  A2  A1  A0  W   ACK     STOP
SCL  ──────────┐   ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐    ┌─────
               └───┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └────┘
SDA  ────────┐          ┌───────────────┐                  ┌───
             └──────────┘               └──────────────────┘
               ↑        0   1   1   1   1   0   0   0  (從機拉低)  ↑
            SCL 高時     ◄──────── 0x3C ────────►  寫        SCL 高時
            SDA 下降                                       SDA 上升

位址 0x3C 的二進位是 011 1100(7 位元),後面接一個 0(寫),所以 SDA 上依序是 0、1、1、1、1、0、0、0。有個小陷阱:有些工具會把這 8 個位元當成一個位元組來顯示,變成 0111 1000 = 0x78。看到 0x78 不要慌,它就是 0x3C 往左移一位加上寫入位元。

為什麼 SDA 和 SCL 要上拉電阻(Pull-up Resistor)?因為 I2C 的裝置只會「把線拉 LOW」或「放手」,沒有人會主動把線推 HIGH;放手的時候要靠上拉電阻把線拉回 HIGH。通常用 4.7kΩ 接到 5V。好消息是大部分 OLED 模組板上已經焊好上拉電阻,直接接就能用。

SPI:更快,但線更多

SPI(Serial Peripheral Interface) 是第三種常見協定,用 4 條線:MOSI(主機送出)、MISO(主機接收)、SCK(時脈)、CS(選擇哪個裝置)。它比 I2C 快很多(幾 MHz 到幾十 MHz),SD 卡、很多大螢幕都用它,但每多一個裝置就要多一條 CS 線。本書不做 SPI 實驗,知道有這東西就好。

邏輯分析儀:只看 0 和 1 的多通道錄音機

邏輯分析儀(Logic Analyzer) 和示波器一樣是用來看訊號的,但它們的想法完全不同:

示波器邏輯分析儀
看什麼真實的電壓(類比),例如 4.8V、0.2V、尖波、圓角只分 0 和 1(高於約 1.5V 算 1,低於算 0)
通道數通常 2 條8 條(便宜款)到 16 條以上
能錄多久幾千到幾百萬個點可以連續錄好幾秒,全部存進電腦
解碼高階款才有內建 UART、I2C、SPI 等幾十種協定解碼器
擅長看電壓對不對、雜訊、反電動勢、PWM 占空比看「送了什麼資料」、多條線的先後順序
不擅長數幾百個位元看電壓高低、雜訊、波形形狀(它只有方波)

一句話:示波器告訴你訊號「長得怎樣」,邏輯分析儀告訴你訊號「在說什麼」。看 PWM、電容充放電用示波器;看 UART、I2C 用邏輯分析儀。

我們用的 USB 邏輯分析儀有 8 個通道(CH0–CH7)加 GND,最高取樣率 24MHz,搭配免費軟體 PulseView。它只能接 0–5V 的訊號,Arduino 的 5V 和 ESP32 的 3.3V 都可以。

取樣率(Sample Rate) 是邏輯分析儀每秒看幾次訊號。取樣率至少要是訊號速度的 10 倍以上,不然位元的邊界會不準:

  • UART 9600 鮑率 → 用 1MHz(是 9600 的 100 倍,綽綽有餘)。
  • I2C 100kHz → 用 4MHz 以上;Adafruit 的 OLED 函式庫會把 I2C 加快到 400kHz,所以保險起見用 8MHz。

動手做

實驗 15-1:錄下 “Hello”,用邏輯分析儀解碼

材料

  • Arduino UNO 與 USB 線
  • USB 邏輯分析儀(8 通道)與它附的杜邦線(母母)
  • 電腦(已安裝 Arduino IDE)

接線

 邏輯分析儀 CH0 ──── Arduino D1(TX)
 邏輯分析儀 GND ──── Arduino GND

  • 邏輯分析儀 CH0 → Arduino D1(印著 TX→ 的那隻腳)
  • 邏輯分析儀 GND → Arduino GND(一定要接,不接的話完全錄不到東西)
  • 邏輯分析儀的 USB 接電腦;Arduino 的 USB 也接電腦,兩條都要插。

步驟(安裝 PulseView)

  1. 到 sigrok.org 的 Downloads 頁面下載 PulseView,Windows 選 .exe 安裝檔,Mac 選 .dmg。
  2. Windows 第一次接邏輯分析儀要裝驅動:安裝程式會附一個叫 Zadig 的小工具,打開它,從裝置清單選你的邏輯分析儀(通常叫「USB Logic」或「Unknown Device」),右邊驅動選 WinUSB,按 Install。Mac 不用這一步。
  3. 打開 PulseView,上方工具列按「選擇裝置」(看起來像一個插頭的按鈕,或寫著 No Device)→ Connect to Device → 驅動選 fx2lafw(這是這類便宜分析儀共用的驅動)→ 介面選 USB → Scan for devices → 清單出現你的分析儀 → 選它 → OK。
  4. 畫面左邊會出現 D0 到 D7 八條通道。右上角有兩個下拉選單:**取樣數(samples)**設 1 M samples,取樣率設 1 MHz。這樣會錄 1 秒鐘。

步驟(錄訊號) 5. 上傳這個程式到 Arduino:

void setup() {
  Serial.begin(9600);          // 鮑率 9600,每個位元 104µs
}

void loop() {
  Serial.println("Hello");     // 送 H e l l o 加上 \r \n,共 7 個字元
  delay(500);                  // 每 0.5 秒送一次
}
  1. 在 PulseView 按左上角的 Run。等它跑完(約 1 秒),畫面上 D0 會出現幾團密密麻麻的方波,每團相隔 0.5 秒。
  2. 用滑鼠滾輪放大其中一團,你會看到 7 個字元、每個 10 個位元的方波。再放大,單一個位元的寬度大約是 104µs,PulseView 上方的時間尺會顯示。
  3. 加解碼器:按工具列上「Add protocol decoder」(一個黃綠色標籤的按鈕)→ 在搜尋框打 UART → 雙擊它。畫面下方會多一列叫 UART 的軌道。
  4. 點那一列最左邊的「UART」標籤,會跳出設定:RX 選 D0(我們接在 CH0),Baud rate 填 9600,Data bits 8、Parity none、Stop bits 1,Data format 選 ascii。關掉設定視窗。
  5. 再看那一團方波,解碼軌道上會依序出現 H、e、l、l、o,然後是 \r(顯示 CR 或 0x0D)和 \n(LF 或 0x0A)。

步驟(改鮑率看變化) 11. 把程式的 9600 改成 115200,重新上傳,再按一次 Run。 12. 這時解碼器還設在 9600,你會看到它解出一堆亂七八糟的符號,甚至出現「frame error」。這就是鮑率不合的樣子。 13. 把解碼器的 Baud rate 改成 115200,字母又回來了。用滑鼠放大比較:每個位元只剩約 8.7µs,整個 “Hello” 縮短到不到 1ms。

你應該看到 9600 鮑率時,每個字元約 1.04ms,7 個字元約 7.3ms,解碼軌道顯示 Hello。115200 鮑率時波形密了 12 倍,用錯的鮑率解碼會是亂碼。

觀察與記錄

鮑率一個位元的寬度(PulseView 游標量)一個字元(10 位元)的長度解碼看到的字元
9600
115200
9600 的訊號用 115200 解碼——

實驗 15-2:偷聽 Arduino 跟 OLED 講話,找到 0x3C

材料

  • Arduino UNO 與 USB 線
  • 0.96 吋 OLED(SSD1306,I2C 介面,4 腳:GND、VCC、SCL、SDA)
  • USB 邏輯分析儀與杜邦線
  • 麵包板、杜邦線(公母)

接線

 Arduino 5V  ──── OLED VCC
 Arduino GND ──── OLED GND
 Arduino A4  ──┬─ OLED SDA
               └─ 邏輯分析儀 CH0
 Arduino A5  ──┬─ OLED SCL
               └─ 邏輯分析儀 CH1
 Arduino GND ──── 邏輯分析儀 GND

  • OLED VCC → Arduino 5V(大部分模組 3.3–5V 都可以,看模組印刷)
  • OLED GND → Arduino GND
  • OLED SDA → Arduino A4;同一條線再分一條到邏輯分析儀 CH0
  • OLED SCL → Arduino A5;同一條線再分一條到邏輯分析儀 CH1
  • 邏輯分析儀 GND → Arduino GND
  • 用麵包板最方便:把 A4 拉到麵包板某一列,OLED 的 SDA 和分析儀 CH0 都插同一列;A5 同理。

步驟

  1. 安裝函式庫:函式庫管理員搜尋 Adafruit SSD1306 安裝,它會問要不要一起裝 Adafruit GFX Library 和 Adafruit BusIO,選「全部安裝」。
  2. 上傳這個程式:
#include <Wire.h>                 // I2C 函式庫
#include <Adafruit_GFX.h>         // 畫圖函式庫
#include <Adafruit_SSD1306.h>     // OLED 驅動

#define SCREEN_WIDTH 128          // OLED 寬 128 點
#define SCREEN_HEIGHT 64          // OLED 高 64 點
#define OLED_ADDRESS 0x3C         // I2C 位址,等一下要在分析儀上找到它

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
    Serial.println("找不到 OLED,檢查接線與位址");
    while (true);                 // 停在這裡
  }
  display.clearDisplay();         // 清空畫面
  display.setTextSize(2);         // 字放大 2 倍
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello");       // 寫字到記憶體
  display.display();              // 真的送到螢幕(這裡會有一大串 I2C)
}

void loop() {
  delay(1000);
  display.invertDisplay(true);    // 反白:只送一個很短的 I2C 命令
  delay(1000);
  display.invertDisplay(false);   // 恢復:再送一個短命令
}
  1. OLED 上應該出現大大的 Hello,而且每秒反白一次。如果沒有,先看序列埠監控視窗有沒有印「找不到 OLED」。
  2. PulseView:取樣率改成 8 MHz,取樣數 10 M samples(大約錄 1.25 秒)。按 Run。
  3. 畫面上 D0(SDA)和 D1(SCL)每隔 1 秒會出現一小團方波,那就是 invertDisplay() 送出的命令。放大其中一團。
  4. 加解碼器:Add protocol decoder → 搜尋 I2C → 雙擊。點 I2C 標籤設定:SCL 選 D1,SDA 選 D0。
  5. 解碼軌道會依序顯示:Start → Address write: 3C → ACK → Data write: 00 → ACK → Data write: A7(反白)或 A6(恢復)→ ACK → Stop。
  6. 把游標放在 SCL 的兩個上升緣之間,量一個時脈週期,算算看 I2C 跑多快。
  7. 想看更長的對話:按 Arduino 的 Reset 鍵同時按 Run,錄到開機時 display.begin() 和 display.display() 送出的一長串初始化命令和 1024 個位元組的畫面資料。

你應該看到 每一次 I2C 對話都是先 Start、位址 3C、寫入,從機 ACK,接著是 00(意思是「後面是命令」),然後是命令本身,最後 Stop。SCL 的週期約 2.5µs(400kHz)。如果你的解碼器把位址顯示成 78,去 I2C 解碼器設定裡把 Address format 改成 unshifted(未位移)就會變成 3C。

觀察與記錄

項目你量到 / 看到的
Start 時 SDA 的變化(SCL 是 HIGH 還是 LOW?)
解碼器顯示的位址
位址後面的讀寫位元(Write 還是 Read)
從機有沒有 ACK
invertDisplay(true) 送的命令位元組
SCL 一個週期的時間 → 換算頻率

用儀器看看

用示波器看 UART,和邏輯分析儀比一比

同一個 “Hello” 訊號,我們也用示波器看一次,體會兩種儀器的差別。

  • 接線:CH1 探棒鉤在 Arduino D1(TX),接地夾夾 GND,探棒 10×。上傳實驗 15-1 的 9600 程式。
  • 設定:耦合 DC;垂直 2V/div;水平 100µs/div,這樣 10 個位元(1.04ms)剛好橫跨 10 格;觸發選 CH1、下降緣(Falling)、準位 2.5V;模式選 單次(Single),因為訊號 0.5 秒才來一次,用單次才能把它凍結在畫面上。
  • 按 Single,等 Arduino 送出下一個 Hello,畫面就會停住。

你應該看到:閒置時線在 5V,從左邊第一格開始掉到 0V(起始位元),接著每一格一個位元,最右邊回到 5V。對照本章的 H 波形圖,你應該能自己數出 0、0、0、1、0、0、1、0。但你會發現:方波的角落不是完全直角,電壓也不是剛好 5V 和 0V,可能是 4.9V 和 0.1V,還有一點點小抖動。這些細節邏輯分析儀全部看不到,它只告訴你 0 和 1。

反過來,示波器一次只能看兩條線、畫面只有 10 格,要看完 7 個字元、解出每個字母,你得自己一格一格數。這就是邏輯分析儀的價值:8 條線、錄好幾秒、自動解碼。

用示波器看 I2C 的 SDA 和 SCL

CH1 鉤 SDA(A4)、CH2 鉤 SCL(A5),兩個通道都 2V/div,水平 5µs/div,觸發 CH1 下降緣、單次。你會抓到一次對話的開頭:先看到 CH1(SDA)在 CH2(SCL)還是 HIGH 時掉下來,這就是 START;接著 SCL 開始規律地跳動,SDA 在每個時脈之間切換。用游標量 SCL 兩個上升緣的距離,約 2.5µs,也就是 400kHz。你也會看到 SDA 和 SCL 的上升緣比下降緣「圓」一點,那是因為 HIGH 是靠上拉電阻慢慢拉上去的,而 LOW 是晶片直接拉下來的,這個細節也只有示波器看得到。

常見錯誤與除錯

  • PulseView 找不到裝置 → 驅動沒裝(Windows)或選錯驅動 → 用 Zadig 裝 WinUSB;Connect to Device 時驅動選 fx2lafw。
  • 按 Run 之後全部通道都是一直線 → 邏輯分析儀的 GND 沒接 Arduino GND,或 CH0 接錯腳 → 檢查 GND 線,TX 是 D1 不是 D0。
  • 看得到方波,但解碼器什麼都沒顯示 → 解碼器的通道沒選到 D0,或鮑率填錯 → 點解碼器標籤重新設定。
  • 解碼出亂碼或 frame error → 鮑率不合 → 程式和解碼器要一樣(9600 對 9600)。
  • 方波看起來歪歪的、位元寬度不整齊 → 取樣率太低 → UART 至少 1MHz,I2C 至少 4MHz(Adafruit 函式庫用 8MHz)。
  • I2C 什麼都錄不到 → OLED 沒有回應,Arduino 卡在「找不到 OLED」 → 看序列埠訊息;SDA/SCL 是不是接反(A4 = SDA、A5 = SCL)。
  • I2C 位址顯示 78 而不是 3C → 解碼器用「位移」格式顯示 → 設定改成 unshifted,或自己換算:0x78 ÷ 2 = 0x3C。
  • 錄到一半 PulseView 說取樣率太高、裝置不支援 → 8 通道全開時最高取樣率會下降 → 在通道設定裡把沒用到的 D2–D7 關掉,只留 D0、D1。
  • 示波器用 Auto 模式看 UART 一直閃過去抓不到 → 訊號 0.5 秒才來一次 → 改用 Single(單次)或 Normal(一般)模式,觸發下降緣。

想一想

  1. 鮑率 19200 時,一個位元持續多久?一個字元(8N1,10 個位元)要多久?
參考答案

1 ÷ 19200 ≈ 0.0000521 秒 = 52.1µs。一個字元 = 10 × 52.1µs ≈ 521µs,大約是 9600 鮑率的一半時間。

  1. 字母 A 的 ASCII 碼是 0x41 = 0100 0001。用 UART 送出時,起始位元之後的 8 個資料位元依序是什麼?
參考答案

LSB 先送,所以把 0100 0001 從右邊讀到左邊:1、0、0、0、0、0、1、0。整個字元是:起始 0 → 1 0 0 0 0 0 1 0 → 停止 1。

  1. 9600 鮑率下,Serial.println("Hello") 要花約 7.3ms。如果 loop 裡把 delay(500) 拿掉,Arduino 每秒最多能送出幾個 “Hello”?
參考答案

1000ms ÷ 7.3ms ≈ 137 次。實際上 Arduino 有一個小小的發送緩衝區,程式會比這個稍快一點就被卡住等待,所以大約 130 多次。換成 115200 鮑率的話每個字元只要 86.8µs,7 個字元約 0.6ms,每秒可以送 1600 多次。

  1. I2C 用 7 位元位址,一條線上最多可以接幾個不同位址的裝置?為什麼實際上接不到那麼多?
參考答案

7 位元 = 2 的 7 次方 = 128 個,扣掉幾個保留位址大約 112 個。但實際上很多裝置的位址是出廠固定的(例如所有 SSD1306 OLED 幾乎都是 0x3C 或 0x3D),兩個相同位址的裝置不能接在同一條線上;而且線越長、裝置越多,上拉電阻要把線拉回 HIGH 就越吃力,速度會變慢。

  1. 為什麼 UART 不需要時脈線,而 I2C 需要?如果 I2C 也拿掉時脈線,會出什麼問題?
參考答案

UART 靠「事先講好鮑率」加上「起始位元」來對時:看到起始位元就開始數,每 104µs 讀一次。I2C 讓主機用 SCL 告訴從機「現在讀」,所以主機可以隨時變速、甚至暫停,從機不用事先知道速度。如果拿掉 SCL,所有從機就必須事先約好速度,而且要像 UART 一樣加起始位元,還要處理很多裝置共用一條線的問題,就變成另一種協定了。

  1. 開放挑戰:把第 13 章的 DHT11 程式和邏輯分析儀結合。DHT11 的 DATA 腳也是一種序列協定(它用脈波的「寬度」表示 0 和 1,不是 UART)。把 CH0 接到 DATA 腳,錄下一次讀取,試著不用解碼器,自己看出哪些是 0、哪些是 1。提示:DHT11 的規則是每個位元先 LOW 50µs,然後 HIGH 約 26–28µs 代表 0、HIGH 約 70µs 代表 1,總共 40 個位元。
參考答案

取樣率設 1MHz 以上。錄到的波形會先有一段 Arduino 拉低約 18ms 的「開始」訊號,然後 DHT11 回應兩個約 80µs 的 LOW/HIGH,接著是 40 個位元。用游標量每個 HIGH 的寬度:短的(約 27µs)是 0、長的(約 70µs)是 1。前 8 個位元是濕度整數,第 17–24 位元是溫度整數,可以和序列埠印出來的數字對照。PulseView 其實也有 DHT11 解碼器(搜尋 dht11),自己數完再用它驗證。

本章小結

  • 晶片之間交換資料要靠事先講好的規則,叫通訊協定;現代幾乎都用序列(一條線排隊送)而不是並列。
  • UART 用 TX/RX 兩條線交叉接、GND 共地,沒有時脈,雙方要講好鮑率。9600 鮑率每個位元 104µs,一個字元(起始 + 8 資料 + 停止)約 1.04ms,資料位元 LSB 先送。
  • I2C 用 SDA/SCL 兩條線接很多裝置,靠 7 位元位址認人(OLED 是 0x3C),有時脈線,SDA/SCL 需要上拉電阻(OLED 模組多半內建)。對話順序:START → 位址 + 讀寫 → ACK → 資料 + ACK → STOP。
  • SPI 用 4 條線、速度更快,SD 卡和大螢幕常用。
  • 邏輯分析儀只看 0 和 1,但通道多、錄得久、能自動解碼;示波器看真實電壓和波形形狀。看「說了什麼」用邏輯分析儀,看「長怎樣」用示波器。
  • PulseView 流程:選裝置(fx2lafw)→ 設取樣率(訊號速度 10 倍以上:UART 用 1MHz、I2C 用 4–8MHz)→ 接 GND 與訊號線 → Run → 加解碼器 → 設通道與參數。
  • 鮑率不合就是亂碼;解碼器和程式的設定一定要一樣。

名詞表

中文英文一句話解釋
通訊協定Protocol晶片之間事先講好的講話規則。
序列 / 並列Serial / Parallel一條線排隊送 / 多條線同時送。
通用非同步收發器UART用 TX/RX 兩條線、靠鮑率對時的最簡單序列協定。
鮑率Baud Rate每秒送幾個位元,例如 9600。
起始位元 / 停止位元Start Bit / Stop BitUART 每個字元前面的 LOW 和後面的 HIGH,用來對齊。
最低位元Least Significant Bit(LSB)二進位數最右邊那一位,UART 先送它。
I2CInter-Integrated Circuit用 SDA/SCL 兩條線接很多裝置、靠位址認人的協定。
位址AddressI2C 裝置的門牌號碼,7 位元,OLED 是 0x3C。
主機 / 從機Master / SlaveI2C 裡主動開口的一方 / 被叫到才回應的一方。
ACKAcknowledge從機在第 9 個時脈把 SDA 拉 LOW,表示「收到」。
上拉電阻Pull-up Resistor把 SDA/SCL 在沒人拉低時拉回 HIGH 的電阻,常用 4.7kΩ。
SPISerial Peripheral Interface用 MOSI/MISO/SCK/CS 四條線的高速序列協定。
邏輯分析儀Logic Analyzer同時錄多條線上 0 和 1、並自動解碼的儀器。
取樣率Sample Rate邏輯分析儀每秒看訊號幾次,至少要是訊號速度的 10 倍。
解碼器Protocol DecoderPulseView 裡把方波翻譯成字元或位址的功能。
PulseViewPulseViewsigrok 計畫的免費邏輯分析儀軟體。

第 16 章 ESP32 與無線

本章目標

  • 學完你會說出 ESP32 和 Arduino UNO 的四個主要差別,並且知道「3.3V 邏輯」代表什麼。
  • 學完你會在 Arduino IDE 裡安裝 ESP32 開發板,上傳第一個程式,並處理「卡在 Connecting」的狀況。
  • 學完你會讓 ESP32 連上 Wi-Fi、印出 IP 位址,並用手機打開一個網頁來開關 LED。
  • 學完你會把 DHT11 的溫濕度同時顯示在網頁和 OLED 上。
  • 學完你會用示波器比較 ESP32 的 3.3V 和 UNO 的 5V 高電位,並能說出 MQTT 與深度睡眠大概是做什麼用的。

開場:那顆會自己上網的小板子

你有沒有想過,家裡的智慧插座、空氣清淨機、掃地機器人,為什麼可以用手機 App 遙控?它們裡面並沒有一台電腦,也沒有插網路線。打開外殼,你多半會看到一片指甲大小、銀色外殼上印著「ESP32」或「ESP8266」的小模組。這些模組來自深圳的一家公司樂鑫(Espressif),價格只要幾十塊台幣,卻內建了 Wi-Fi 和藍牙。

前面幾章我們用 Arduino UNO 讀感測器、控制馬達、跟 OLED 講話。可是 UNO 是一座孤島:它量到的溫度只能印在電腦螢幕上,你人不在電腦前就看不到。想躺在床上用手機看房間溫濕度,或出門前用手機關電風扇,UNO 做不到。

這一章我們換一塊板子:ESP32 DevKit V1。它跟 UNO 一樣用 Arduino IDE 寫程式,同樣有 setup() 和 loop(),同樣用 digitalWrite() 點 LED,但它會上網。本章結束時,你的手機會多出一個「網頁遙控器」,而且是你自己寫的。

核心概念

ESP32 跟 UNO 差在哪裡?

比喻:UNO 像一輛可靠的腳踏車,構造簡單、好修、怎麼摔都不太會壞。ESP32 像一台電動滑板車:速度快、功能多、還有無線通訊,但需要注意的地方也多一點。

項目Arduino UNOESP32 DevKit V1
工作電壓(邏輯電位)5V3.3V
處理器速度16 MHz,單核心240 MHz,雙核心(Dual Core)
程式記憶體32 KB4 MB
無線沒有Wi-Fi(2.4 GHz)+藍牙(Bluetooth)
類比輸入6 腳,0–1023(10 位元)多腳,0–4095(12 位元)
PWM 輸出6 腳,analogWrite()幾乎所有腳,ledcWrite()
價格中便宜

「雙核心」的意思是板子裡有兩個處理器同時工作,其中一個通常在忙著處理 Wi-Fi,另一個跑你寫的程式。你暫時不需要管它,Arduino 的函式庫會幫你安排。

最重要的差別是第一列:ESP32 的所有腳位都是 3.3V。它輸出 HIGH 的時候是 3.3V,不是 5V;它的輸入腳也只能承受最高 3.3V。

3.3V 邏輯:為什麼不能接 5V 訊號?

比喻:UNO 的腳位像一條設計給大卡車走的橋,ESP32 的腳位像一條只給機車走的小橋。機車(3.3V)開上大橋沒問題;大卡車(5V)開上小橋,橋會垮。

ESP32 的輸入腳位最高只能承受大約 3.6V。如果你把 UNO 的 5V 輸出直接接到 ESP32 的輸入腳,多出來的電壓會從晶片內部不該走的路衝進去,輕則讀值錯亂,重則腳位燒壞。

反過來卻沒問題:ESP32 輸出 3.3V 給 UNO 讀,UNO 要多高才算 HIGH?第 11 章學過,UNO 的門檻大約是 3V(5V 的 0.6 倍)。3.3V 高於 3V,所以 UNO 讀得到。

那如果非要把 5V 訊號餵給 ESP32 怎麼辦?用第 3 章的分壓器就行。拿兩個相同的電阻串聯:

 UNO 5V 訊號 ──[ 10kΩ ]──┬──[ 10kΩ ]── GND
                         │
                      ESP32 輸入腳(這裡是 2.5V)

算一下:V_out = 5V × 10kΩ ÷ (10kΩ + 10kΩ) = 5V × 0.5 = 2.5V。2.5V 低於 3.3V,安全;而且高於 ESP32 判定 HIGH 的門檻(大約 3.3V × 0.75 ≈ 2.5V,實際上大多數板子 2.5V 已能讀到 HIGH,如果不穩可以把下面那顆換成 15kΩ,得到 3V)。第 17 章的迷你示波器專題就會用到這招。

哪些腳位可以用、哪些不行?

ESP32 DevKit V1 有 30 支腳(有些版本是 36 支)。下面是你最常用的,以及要避開的:

                ┌──────────────────────┐
         3V3 ───┤ 3.3V 輸出(最多約 500mA)  VIN ├─── 5V 輸入(USB 供電時這裡有 5V)
         GND ───┤                          GND ├───
     GPIO 36 ───┤ 只能輸入(VP)         GPIO 23 ├───
     GPIO 39 ───┤ 只能輸入(VN)         GPIO 22 ├─── I2C SCL(OLED)
     GPIO 34 ───┤ 只能輸入 ★類比輸入預設  GPIO 21 ├─── I2C SDA(OLED)
     GPIO 35 ───┤ 只能輸入               GPIO 19 ├───
     GPIO 32 ───┤                        GPIO 18 ├─── ★PWM 輸出預設
     GPIO 33 ───┤                         GPIO 5 ├───
     GPIO 25 ───┤                        GPIO 17 ├───
     GPIO 26 ───┤                        GPIO 16 ├───
     GPIO 27 ───┤                         GPIO 4 ├─── DHT11 預設
     GPIO 14 ───┤                         GPIO 2 ├─── ★板上藍色 LED
     GPIO 12 ───┤ 開機時必須是 LOW          GPIO 15 ├───
         GND ───┤                         GND ├───
     GPIO 13 ───┤                   [EN]  [BOOT] │  ← 兩顆按鈕
                └──────────[ USB ]────────────┘

規則整理:

  1. GPIO 34、35、36、39 只能當輸入,不能 digitalWrite(),也沒有內建上拉電阻。它們很適合接光敏電阻、可變電阻這種類比訊號。
  2. GPIO 6–11 絕對不要接。它們連到板子內部的快閃記憶體(Flash),一碰程式就會當掉。30 腳的 DevKit V1 根本沒把它們拉出來;如果你的板子有標示 CLK、CMD、SD0–SD3 的腳,那就是它們,跳過。
  3. GPIO 2 接著板上的藍色 LED,就像 UNO 的 D13。本書 ESP32 的 LED 預設用它。
  4. GPIO 0、2、12、15 在開機瞬間會被板子「偷看」來決定開機模式。平常用沒關係,但不要在這些腳接上拉或下拉電阻(例如 GPIO 12 接上拉會讓板子開不了機)。
  5. 兩顆按鈕:EN 是重置(跟 UNO 的 RESET 一樣),BOOT 是上傳程式時用的,等一下會用到。

Wi-Fi 是怎麼連上的?

比喻:Wi-Fi 分享器(路由器)像一棟公寓的管理員。每一台想進公寓的裝置都要先報上名字和密碼(SSID 和密碼),管理員確認後會分配一個「門牌號碼」給它,這就是 IP 位址(IP Address),長得像 192.168.1.57。同一棟公寓裡的住戶,只要知道門牌就能互相敲門。

所以手機要控制 ESP32,條件只有兩個:

  1. 手機和 ESP32 連到同一個 Wi-Fi。
  2. 你知道 ESP32 的 IP 位址(它會從序列埠印給你)。

注意:ESP32 只支援 2.4 GHz 的 Wi-Fi。很多家用分享器同時有 2.4 GHz 和 5 GHz 兩個名字,連錯就永遠連不上。用手機開熱點也可以,但要在熱點設定裡選「2.4 GHz」或「相容模式」。

網頁伺服器:ESP32 怎麼「給你一個網頁」?

比喻:網頁伺服器(Web Server)像一間小店。瀏覽器(顧客)走進來說「我要 /on 這個東西」,店員(你的程式)就把對應的商品(一段 HTML 文字)遞出去。

你在手機瀏覽器輸入 http://192.168.1.57/on,意思是「敲 192.168.1.57 這個門牌,跟它要 /on」。ESP32 收到後會執行你指定的函式(例如把 LED 點亮),再回傳一段文字給瀏覽器顯示。整個流程只有三步:

  1. server.on("/on", handleOn);:告訴伺服器「有人要 /on 時,呼叫 handleOn()」。
  2. server.begin();:開店。
  3. 在 loop() 裡不停呼叫 server.handleClient();:店員顧店,看有沒有顧客進來。

第三點很重要。loop() 裡如果有一個很長的 delay(5000),店員就會睡著五秒鐘,顧客怎麼敲門都沒人理。所以後面的程式會用 millis() 來計時,而不是 delay()。

動手做

實驗 16-1:安裝 ESP32 並點亮板上 LED

材料

  • ESP32 DevKit V1 ×1
  • Micro USB 傳輸線 ×1(要能傳資料的,有些只能充電)
  • 電腦(已安裝 Arduino IDE)
  • 數位三用電表 ×1

接線

這個實驗只用 USB 線接電腦,不用麵包板。

 電腦 USB ════ Micro USB ════ [ ESP32 DevKit V1 ]
                                   GPIO 2 ──►|── 板上藍色 LED(已內建,不用接)

步驟

  1. 打開 Arduino IDE,進入「檔案 → 偏好設定」(Mac 是「Arduino IDE → Settings」)。
  2. 找到「額外的開發板管理員網址」欄位,貼上這一行,按「確定」:
    https://espressif.github.io/arduino-esp32/package_esp32_index.json
    
    如果欄位裡已經有別的網址,用逗號隔開再貼。
  3. 進入「工具 → 開發板 → 開發板管理員」,在搜尋框輸入 esp32,找到 esp32 by Espressif Systems,按「安裝」。這會下載幾百 MB,請耐心等待。
  4. 用 USB 線接上 ESP32。進入「工具 → 開發板 → esp32」,在很長的清單裡選 ESP32 Dev Module。
  5. 「工具 → 連接埠」選擇新出現的那一個(Windows 是 COMx,Mac 是 /dev/cu.usbserial-xxxx)。如果沒有出現,你的電腦可能需要安裝 CP2102 驅動程式,請老師協助。
  6. 把下面的程式貼進去,按「上傳」。
// 實驗 16-1:ESP32 第一個程式,閃爍板上 LED
const int ledPin = 2;   // ESP32 DevKit V1 的板上藍色 LED 接在 GPIO 2

void setup() {
  pinMode(ledPin, OUTPUT);     // 把 GPIO 2 設成輸出
  Serial.begin(115200);        // ESP32 習慣用 115200,比 UNO 的 9600 快
  Serial.println("ESP32 準備好了!");
}

void loop() {
  digitalWrite(ledPin, HIGH);  // 點亮
  delay(500);                  // 等 0.5 秒
  digitalWrite(ledPin, LOW);   // 熄滅
  delay(500);
}
  1. 看 IDE 下方的黑色輸出區。當你看到 Connecting........_____....._____ 一直重複時,按住板子上的 BOOT 鍵不放,直到文字變成 Writing at 0x00001000... 再放開。這是 DevKit V1 最常見的小脾氣,不是壞掉。
  2. 上傳完成後,打開序列埠監控視窗,右下角鮑率選 115200。

你應該看到

藍色 LED 每秒閃一次。序列埠監控視窗印出「ESP32 準備好了!」。如果看到一堆亂碼,多半是鮑率沒選 115200。

  1. 拿三用電表切到直流電壓檔(20V),黑棒接 GND 腳,紅棒分別接 3V3 腳和 VIN 腳,記錄數值。

觀察與記錄

量測點預期你量到的
3V3 腳對 GND約 3.3V
VIN 腳對 GND(USB 供電時)約 5V
GPIO 2 對 GND(LED 亮時)約 3.3V
GPIO 2 對 GND(LED 暗時)約 0V

實驗 16-2:連上 Wi-Fi,印出 IP 位址

材料

  • 實驗 16-1 的全部
  • 一個 2.4 GHz 的 Wi-Fi 名稱與密碼(教室的分享器或手機熱點)

接線

同實驗 16-1,只用 USB 線。

步驟

  1. 把程式裡的 你的Wi-Fi名稱 和 你的Wi-Fi密碼 換成真的。大小寫要一模一樣。
  2. 上傳,打開序列埠監控視窗(115200)。
// 實驗 16-2:ESP32 連上 Wi-Fi 並印出 IP 位址
#include <WiFi.h>              // ESP32 內建的 Wi-Fi 函式庫

const char* ssid     = "你的Wi-Fi名稱";   // 分享器的名字(SSID)
const char* password = "你的Wi-Fi密碼";   // 密碼,不要把它上傳到網路上給別人看

void setup() {
  Serial.begin(115200);
  delay(500);                            // 給序列埠一點時間開起來
  Serial.print("正在連線到:");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);                   // STA 模式 = 當一台「客戶端」去連分享器
  WiFi.begin(ssid, password);            // 開始連線

  int tries = 0;
  while (WiFi.status() != WL_CONNECTED) { // 還沒連上就一直等
    delay(500);
    Serial.print(".");
    tries++;
    if (tries > 40) {                    // 等了 20 秒還沒連上,印提示
      Serial.println();
      Serial.println("連不上,請檢查名稱、密碼,以及是不是 2.4GHz");
      tries = 0;
    }
  }

  Serial.println();
  Serial.println("連上了!");
  Serial.print("IP 位址:");
  Serial.println(WiFi.localIP());        // 把這串數字記下來,等一下手機要用
  Serial.print("訊號強度 RSSI:");
  Serial.print(WiFi.RSSI());             // 負數,越接近 0 代表訊號越強
  Serial.println(" dBm");
}

void loop() {
  // 這個實驗 loop 不用做事
}

你應該看到

序列埠印出一排點點,幾秒後出現「連上了!IP 位址:192.168.x.x」。RSSI 大約在 -40(很強)到 -80(很弱)之間。

  1. 拿手機,確認手機連到同一個 Wi-Fi,打開瀏覽器輸入 ESP32 的 IP。現在會顯示「無法連線」,這是正常的,因為我們還沒開店。下一個實驗就要開了。

觀察與記錄

項目你的紀錄
Wi-Fi 名稱
ESP32 的 IP 位址
RSSI(dBm)
把 ESP32 拿到走廊再量一次 RSSI

實驗 16-3:用手機網頁開關 LED

材料

  • 實驗 16-2 的全部
  • (可選)紅色 LED ×1、220Ω 電阻 ×1、麵包板、杜邦線:想看外接 LED 的話加上這組

接線

用板上 LED 就不必接線。想接外接 LED 的話:

 ESP32 GPIO 2 ──[ 220Ω ]──►|── GND
                          LED

文字說明:ESP32 GPIO 2 → 220Ω → LED 長腳,LED 短腳 → ESP32 GND。GPIO 2 同時會點亮板上 LED 和外接 LED。

步驟

  1. 填入 Wi-Fi 名稱和密碼,上傳。
// 實驗 16-3:ESP32 網頁伺服器,用手機開關 LED
#include <WiFi.h>
#include <WebServer.h>          // ESP32 內建的簡易網頁伺服器

const char* ssid     = "你的Wi-Fi名稱";
const char* password = "你的Wi-Fi密碼";

const int ledPin = 2;           // 板上 LED
bool ledOn = false;             // 記住目前狀態,網頁要顯示

WebServer server(80);           // 80 是網頁的標準「門」(埠號)

// 組出一段 HTML 網頁文字,手機瀏覽器會把它畫出來
String makePage() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";  // 手機上字不會太小
  html += "<title>ESP32 LED</title></head>";
  html += "<body style='font-family:sans-serif;text-align:center;margin-top:40px'>";
  html += "<h1>ESP32 LED 遙控器</h1>";
  html += "<p style='font-size:1.5em'>目前狀態:";
  html += ledOn ? "<b style='color:orange'>亮</b>" : "<b style='color:gray'>暗</b>";
  html += "</p>";
  // 兩顆按鈕,按下去會連到 /on 或 /off
  html += "<p><a href='/on'><button style='font-size:2em;padding:20px'>開燈</button></a> ";
  html += "<a href='/off'><button style='font-size:2em;padding:20px'>關燈</button></a></p>";
  html += "</body></html>";
  return html;
}

// 有人連到「/」(首頁)時執行
void handleRoot() {
  server.send(200, "text/html; charset=utf-8", makePage());  // 200 代表「成功」
}

// 有人連到「/on」時執行
void handleOn() {
  ledOn = true;
  digitalWrite(ledPin, HIGH);                  // 真的點亮 LED
  Serial.println("收到 /on,開燈");
  server.send(200, "text/html; charset=utf-8", makePage());
}

// 有人連到「/off」時執行
void handleOff() {
  ledOn = false;
  digitalWrite(ledPin, LOW);
  Serial.println("收到 /off,關燈");
  server.send(200, "text/html; charset=utf-8", makePage());
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);                  // 連 Wi-Fi,跟實驗 16-2 一樣
  Serial.print("連線中");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("請用手機瀏覽器打開:http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);                  // 登記三條路:誰來要什麼,就叫誰處理
  server.on("/on", handleOn);
  server.on("/off", handleOff);
  server.begin();                              // 開店
  Serial.println("網頁伺服器已啟動");
}

void loop() {
  server.handleClient();                       // 顧店:一直檢查有沒有人敲門
  // 注意:這裡不要放長的 delay(),不然店員會睡著
}
  1. 打開序列埠監控視窗,記下 IP。
  2. 手機瀏覽器輸入 http:// 加上那個 IP(例如 http://192.168.1.57)。
  3. 按「開燈」、「關燈」,同時看板子和序列埠。

你應該看到

手機出現一個有兩顆大按鈕的網頁。按「開燈」,網址列變成 .../on,藍色 LED 亮,序列埠印「收到 /on,開燈」。按「關燈」則相反。同學的手機只要連同一個 Wi-Fi,也能控制你的 LED。

觀察與記錄

動作網址列變成LED 狀態序列埠印出
輸入 IP 按 Enter
按「開燈」
按「關燈」
在網址後面手動加 /on

實驗 16-4:溫濕度顯示在網頁與 OLED

材料

  • ESP32 DevKit V1 ×1
  • DHT11 溫濕度感測器 ×1(三腳或四腳模組皆可)
  • 0.96 吋 OLED(SSD1306,I2C)×1
  • 10kΩ 電阻 ×1(如果 DHT11 是裸元件四腳版才需要;三腳模組已內建)
  • 麵包板、杜邦線

接線

                 ┌─────────────────┐
     3V3 ────────┤ VCC    DHT11    │
     GPIO 4 ─────┤ DATA            │   (裸元件版:DATA 與 VCC 之間加 10kΩ 上拉)
     GND ────────┤ GND             │
                 └─────────────────┘

                 ┌─────────────────┐
     3V3 ────────┤ VCC    OLED     │
     GND ────────┤ GND   SSD1306   │
     GPIO 21 ────┤ SDA             │
     GPIO 22 ────┤ SCL             │
                 └─────────────────┘

文字說明:

  • DHT11 VCC → ESP32 3V3;DHT11 DATA → ESP32 GPIO 4;DHT11 GND → ESP32 GND。
  • OLED VCC → ESP32 3V3;OLED GND → ESP32 GND;OLED SDA → ESP32 GPIO 21;OLED SCL → ESP32 GPIO 22。
  • 兩個元件都用 3V3,不要接 VIN 的 5V。OLED 模組雖然多半能吃 5V,但它的 SDA/SCL 訊號會回到 ESP32,統一用 3.3V 最安全。

步驟

  1. 確認已安裝函式庫:「工具 → 管理程式庫」搜尋並安裝 DHT sensor library(Adafruit)、Adafruit SSD1306、Adafruit GFX Library。第 13 章和第 15 章應該已經裝過。
  2. 填入 Wi-Fi 名稱和密碼,上傳。
// 實驗 16-4:DHT11 溫濕度同時顯示在網頁和 OLED
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>                 // Adafruit 的 DHT 函式庫
#include <Wire.h>                // I2C
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const char* ssid     = "你的Wi-Fi名稱";
const char* password = "你的Wi-Fi密碼";

#define DHTPIN  4                // DHT11 資料腳接 GPIO 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#define OLED_SDA 21
#define OLED_SCL 22
Adafruit_SSD1306 display(128, 64, &Wire, -1);  // 128×64 像素,沒有 reset 腳

WebServer server(80);

float temperature = 0.0;         // 最近一次讀到的溫度(°C)
float humidity    = 0.0;         // 最近一次讀到的濕度(%)
unsigned long lastReadTime = 0;  // 上次讀感測器的時間(毫秒)

// 讀 DHT11,讀失敗就保留上一次的值
void readSensor() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (!isnan(t) && !isnan(h)) {  // isnan = 不是數字,代表讀失敗
    temperature = t;
    humidity = h;
  } else {
    Serial.println("DHT11 讀取失敗,用上一次的值");
  }
}

// 把數值畫到 OLED 上(OLED 預設字型沒有中文,所以用英文)
void showOnOled() {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("IP: ");
  display.println(WiFi.localIP());        // 第一行顯示 IP,手機要用

  display.setTextSize(2);                 // 字放大兩倍
  display.setCursor(0, 20);
  display.print("T:");
  display.print(temperature, 1);          // 小數一位
  display.println(" C");
  display.setCursor(0, 44);
  display.print("H:");
  display.print(humidity, 0);             // 整數
  display.println(" %");
  display.display();                      // 真的送到螢幕
}

// 網頁:每 5 秒自動重新整理一次
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<meta http-equiv='refresh' content='5'>";   // 瀏覽器每 5 秒自己重新載入
  html += "<title>ESP32 氣象站</title></head>";
  html += "<body style='font-family:sans-serif;text-align:center;margin-top:40px'>";
  html += "<h1>教室溫濕度</h1>";
  html += "<p style='font-size:3em'>" + String(temperature, 1) + " &deg;C</p>";
  html += "<p style='font-size:3em'>" + String(humidity, 0) + " %</p>";
  html += "<p style='color:gray'>每 5 秒自動更新</p>";
  html += "</body></html>";
  server.send(200, "text/html; charset=utf-8", html);
}

void setup() {
  Serial.begin(115200);
  dht.begin();                                  // 啟動 DHT11

  Wire.begin(OLED_SDA, OLED_SCL);               // 指定 I2C 腳位
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // OLED 位址 0x3C
    Serial.println("找不到 OLED,檢查接線或位址");
    while (true) delay(10);                     // 停在這裡
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Connecting WiFi...");
  display.display();

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("網頁在 http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.begin();

  readSensor();                                 // 先讀一次,網頁才有東西
  showOnOled();
}

void loop() {
  server.handleClient();                        // 顧店

  // 每 2 秒讀一次感測器(DHT11 最快只能每 1–2 秒讀一次)
  if (millis() - lastReadTime >= 2000) {
    lastReadTime = millis();
    readSensor();
    showOnOled();
    Serial.print("T=");
    Serial.print(temperature);
    Serial.print("  H=");
    Serial.println(humidity);
  }
}
  1. 看 OLED,第一行會出現 IP,手機瀏覽器輸入它。
  2. 用手指捏住 DHT11 十秒鐘,或對它呵氣,同時看 OLED 和手機。

你應該看到

OLED 顯示 IP 和大字的溫度、濕度。手機網頁每 5 秒自動更新。對 DHT11 呵氣後,濕度會明顯上升(可能從 60% 跳到 80% 以上),溫度慢慢上升一兩度,再慢慢回來。

觀察與記錄

情況OLED 溫度OLED 濕度網頁溫度網頁濕度
靜置 1 分鐘
手指捏住 10 秒
呵氣 3 次
放開 1 分鐘後

概念介紹:MQTT,物聯網的「公布欄」

剛才的網頁伺服器有個限制:手機必須主動去「敲門」才拿得到資料,而且手機和 ESP32 要在同一個 Wi-Fi 底下。如果你想在學校看家裡的溫度,網頁伺服器就不夠了。

物聯網(IoT, Internet of Things)常用另一種方法:MQTT。

比喻:MQTT 像學校的公布欄。公布欄放在一個大家都能到的地方(這台機器叫代理人,Broker,通常在網路上)。ESP32 把溫度寫在「教室溫度」這一欄(這叫發布,Publish,欄位名稱叫主題,Topic)。任何想知道教室溫度的人,只要跟公布欄說「教室溫度這欄有更新就通知我」(這叫訂閱,Subscribe)。ESP32 不需要知道誰在看,看的人也不需要知道 ESP32 在哪裡,大家只要都找得到公布欄就好。

 ESP32 ──發布「教室/溫度 = 27.5」──►┌──────────┐
                                   │  Broker  │──通知──► 手機 App
 手機 ──發布「教室/風扇 = 開」──────►│ (公布欄)│──通知──► ESP32(開風扇)
                                   └──────────┘

MQTT 的優點是訊息很小、很省電,而且 ESP32 可以放在任何有網路的地方。Arduino 有現成的 PubSubClient 函式庫,網路上也有免費的公開 Broker(例如 test.mosquitto.org)讓你練習。本書不深入教,但你已經會 Wi-Fi 了,剩下的只是多裝一個函式庫、多學三個指令:connect()、publish()、subscribe()。

概念介紹:深度睡眠,讓電池撐幾個月

ESP32 開著 Wi-Fi 的時候大約吃 80–160 mA。用第 4 章學的方法算一下:一顆 9V 電池大約 500 mAh,500 ÷ 100 = 5 小時就沒電了。這樣的氣象站放在陽台撐不過一個下午。

比喻:深度睡眠(Deep Sleep)像冬眠的熊。熊醒著一天要吃很多東西,但冬眠時幾乎不消耗能量,只留一個「生理時鐘」等春天叫醒牠。ESP32 進入深度睡眠時幾乎把所有東西都關掉,只剩一個小小的計時器,耗電降到大約 0.01 mA,是醒著的萬分之一。

典型用法:醒來 → 連 Wi-Fi → 讀溫度 → 送出去 → 睡 10 分鐘 → 醒來……。醒著 5 秒、睡 600 秒,平均電流大約 100 mA × 5 ÷ 605 ≈ 0.8 mA,同一顆 9V 電池可以撐 500 ÷ 0.8 ≈ 625 小時,差不多 26 天。

有兩件事要知道:

  1. 深度睡眠醒來時,程式會從 setup() 重新開始,像按了一次重置。一般變數的值會不見。
  2. 想跨越睡眠記住東西,變數前面要加 RTC_DATA_ATTR,它會存在那個不會關掉的小角落裡。

下面是一個最小的範例,每 10 秒醒來閃一下 LED,並記錄自己醒來第幾次:

// 深度睡眠示範:醒來閃一下 LED、印出次數,再睡 10 秒
#define SLEEP_SECONDS 10
RTC_DATA_ATTR int wakeCount = 0;   // 這個變數睡覺時不會被清掉

void setup() {
  Serial.begin(115200);
  delay(300);
  wakeCount++;                     // 每醒來一次加 1
  Serial.print("第 ");
  Serial.print(wakeCount);
  Serial.println(" 次醒來");

  pinMode(2, OUTPUT);              // 閃一下板上 LED 表示「我醒了」
  digitalWrite(2, HIGH);
  delay(300);
  digitalWrite(2, LOW);

  Serial.println("要去睡了...");
  esp_sleep_enable_timer_wakeup((uint64_t)SLEEP_SECONDS * 1000000ULL);  // 單位是微秒
  esp_deep_sleep_start();          // 從這一行開始,板子就睡著了
}

void loop() {
  // 永遠不會執行到這裡,因為 setup() 最後就睡著了
}

上傳後你會看到序列埠每 10 秒印一次「第 N 次醒來」,N 一直增加。如果把 RTC_DATA_ATTR 拿掉,N 會永遠是 1。

用儀器看看

示波器:3.3V 和 5V 擺在一起看

這是本章最值得看的一個畫面。我們讓 UNO 和 ESP32 各閃一顆 LED,用示波器的兩個通道同時看它們的腳位電壓。

接線

  1. 把第 12 章的 Blink 程式上傳到 UNO,但把腳位改成 D9,delay 改成 500 毫秒。ESP32 跑實驗 16-1 的程式。
  2. 用一條杜邦線把 UNO 的 GND 和 ESP32 的 GND 接在一起(兩塊板子要有共同的 0V,才能比較)。
  3. 探棒 CH1 鉤 UNO D9,CH2 鉤 ESP32 GPIO 2。兩支探棒的黑色鱷魚夾都夾到 GND(夾任何一塊板子的 GND 都可以,因為剛才接在一起了)。
 UNO D9 ───────────── CH1 探棒尖端
 UNO GND ──┬───────── CH1 鱷魚夾
           │
 ESP32 GND ┴───────── CH2 鱷魚夾
 ESP32 GPIO 2 ─────── CH2 探棒尖端

設定

  • 兩個通道都 1 V/div,探棒 10×(記得示波器通道設定也要選 10×)。
  • 把 CH2 的基準線往下移一點,讓兩條線不要疊在一起。
  • 時間 200 ms/div。
  • 觸發:CH1,上升緣,觸發電位 2.5V。

畫面應該像這樣

電壓
 5V ┤ ┌─────┐     ┌─────┐     ┌─────┐       ← CH1:UNO D9
    │ │     │     │     │     │     │
 0V ┼─┘     └─────┘     └─────┘     └────
    │
3.3V┤   ┌────┐    ┌────┐    ┌────┐         ← CH2:ESP32 GPIO 2
    │   │    │    │    │    │    │
 0V ┼───┘    └────┘    └────┘    └─────── 時間
      ◄──────────►
         1 秒(一個週期)

兩條都是方波,週期都是 1 秒,但高度差了 1.7V。用示波器的自動量測功能量 CH1 和 CH2 的「最大值(Max)」,把數字填進去:

通道板子量到的 HIGH 電壓量到的 LOW 電壓
CH1UNO D9
CH2ESP32 GPIO 2

ESP32 的 HIGH 可能只有 3.2V 左右而不是剛好 3.3V,這是正常的,腳位內部有一點點電阻。兩塊板子的方波起點不會對齊,因為它們各自按自己的時鐘走。

示波器:看 Wi-Fi 在吃電

ESP32 跑實驗 16-3。探棒 CH1 鉤 3V3 腳,鱷魚夾接 GND,設定 50 mV/div(有「AC 耦合」就打開,把 3.3V 直流濾掉只看抖動)、10 ms/div。你會看到每隔一段時間出現一小串往下的毛刺,那是 Wi-Fi 發射瞬間抽走大電流、讓 3.3V 下陷的痕跡。毛刺超過 200 mV 代表供電不夠力,這就是「Brownout」錯誤的來源。

邏輯分析儀:看 ESP32 跟 OLED 講話

第 15 章我們看過 UNO 和 OLED 的 I2C 訊號。現在把邏輯分析儀的 CH0 接 GPIO 21(SDA)、CH1 接 GPIO 22(SCL),GND 接 ESP32 GND,跑實驗 16-4,用 PulseView 的 I2C 解碼器看。你應該同樣看到位址 0x3C。不同的是訊號高電位變成 3.3V,邏輯分析儀的門檻(通常 1.5V 左右)仍然輕鬆判斷得出來。

常見錯誤與除錯

  • 上傳一直卡在 Connecting........_____ → DevKit V1 沒有自動進入下載模式 → 看到 Connecting 時按住 BOOT 鍵不放,到出現 Writing 再放開。
  • 上傳時出現 Failed to connect to ESP32: Timed out → USB 線只能充電不能傳資料,或連接埠選錯 → 換一條線、確認「工具 → 連接埠」選的是 ESP32 的那一個。
  • 連接埠裡找不到板子 → 電腦缺 CP2102 或 CH340 驅動程式 → 看板子上 USB 旁邊的小晶片是哪一種,請老師協助安裝驅動。
  • 序列埠印一堆亂碼 → 鮑率不對 → 監控視窗右下角改 115200。
  • 一直印點點,連不上 Wi-Fi → SSID 或密碼打錯、連到 5 GHz 的名字、或熱點沒開 2.4 GHz → 重新檢查大小寫、改連 2.4 GHz。
  • 序列埠印 Brownout detector was triggered 然後一直重開 → 供電不足 → 換短一點的 USB 線、換電腦的 USB 孔、不要透過 USB 集線器。
  • IP 印出來了,但手機打不開網頁 → 手機不在同一個 Wi-Fi、或手機用了行動網路 → 手機關掉行動數據、確認連同一個 SSID。有些學校的 Wi-Fi 會禁止裝置互連,改用手機熱點試試。
  • 網頁按了沒反應,但序列埠沒印出收到 → loop() 裡有長 delay(),店員睡著了 → 改用 millis() 計時。
  • OLED 一片黑,序列埠印「找不到 OLED」 → 接線錯或位址是 0x3D → 用三用電表確認 VCC 有 3.3V;把程式的 0x3C 改成 0x3D 試試。
  • DHT11 一直讀取失敗 → DATA 腳接錯、裸元件缺上拉電阻、或讀太頻繁 → 檢查接線、加 10kΩ 上拉、讀取間隔至少 2 秒。
  • 把感測器從 UNO 搬到 ESP32 後讀值怪怪的 → 感測器輸出 5V 訊號接進 3.3V 腳 → 改用 3V3 供電,或加分壓器。
  • 接了東西之後板子開不了機 → 接在 GPIO 0、2、12、15 的元件影響了開機判斷 → 拔掉重開確認,換別的腳位。

想一想

  1. ESP32 的 digitalWrite(2, HIGH) 會讓 GPIO 2 變成幾伏特?UNO 的 digitalWrite(9, HIGH) 呢?
參考答案

ESP32 約 3.3V,UNO 約 5V。這是兩塊板子最重要的差別。

  1. 小明想把 UNO 的 D9 訊號接到 ESP32 的 GPIO 34 讀,可以直接接嗎?如果不行,要怎麼改?
參考答案

不能直接接,5V 超過 ESP32 腳位能承受的 3.3V。用兩個 10kΩ 串聯做分壓器,從中間接到 GPIO 34,得到 2.5V。反過來(ESP32 輸出給 UNO 讀)則可以直接接,因為 3.3V 高於 UNO 判定 HIGH 的 3V。

  1. 下面哪些腳位可以用來 digitalWrite() 點亮 LED?GPIO 2、GPIO 18、GPIO 34、GPIO 6。
參考答案

GPIO 2 和 GPIO 18 可以。GPIO 34 只能輸入,不能輸出。GPIO 6 連到快閃記憶體,絕對不要用。

  1. 手機已經連上 Wi-Fi,也輸入了正確的 IP,但網頁一直轉圈圈打不開。列出三個你會檢查的地方。
參考答案

(任三個)手機是不是連到跟 ESP32 相同的 Wi-Fi 名稱;手機的行動數據有沒有關掉;ESP32 序列埠有沒有印出「網頁伺服器已啟動」;loop() 裡有沒有長 delay() 讓 handleClient() 跑不到;學校 Wi-Fi 是否禁止裝置互連;IP 有沒有打錯(例如 ESP32 重開後拿到新的 IP)。

  1. 一個 ESP32 氣象站用 3 顆 3 號電池(大約 2000 mAh)供電。如果它每小時醒來 10 秒(醒著時 120 mA)、其他時間深度睡眠(0.01 mA),大約可以撐幾天?
參考答案

每小時耗電量:醒著 120 mA × 10 秒 ÷ 3600 秒 ≈ 0.33 mAh,睡著 0.01 mA × 3590 秒 ÷ 3600 秒 ≈ 0.01 mAh,合計約 0.34 mAh/小時。2000 ÷ 0.34 ≈ 5900 小時 ≈ 245 天。實際上電池會自己慢慢漏電、電壓也會下降,所以可能是幾個月,但遠比不睡覺的 2000 ÷ 120 ≈ 17 小時好太多了。

  1. 開放挑戰:把實驗 16-3 和 16-4 合併,做一個網頁同時顯示溫濕度又能開關 LED。進一步,讓它在濕度超過 80% 時自動點亮 LED(當作「要除濕了」的警示)。想一想,這個「自動」的判斷應該寫在 loop() 的哪裡?
參考答案

把實驗 16-3 的 handleOn、handleOff 和按鈕 HTML 加進 16-4 的程式。自動判斷寫在 loop() 裡「每 2 秒讀感測器」的那個 if 區塊內,讀完之後加一行 if (humidity > 80) digitalWrite(ledPin, HIGH);。這樣不管有沒有人開網頁,判斷都會持續進行;如果寫在 handleRoot() 裡,就只有有人開網頁時才會判斷。

本章小結

  • ESP32 是 3.3V 邏輯的板子:輸出 HIGH 是 3.3V,輸入腳不可以接 5V 訊號,需要的話用分壓器降壓。
  • 安裝:偏好設定加入 Espressif 的網址 → 開發板管理員安裝 esp32 → 選「ESP32 Dev Module」。上傳卡在 Connecting 就按住 BOOT。
  • GPIO 34–39 只能輸入;GPIO 6–11 不能用;GPIO 2 接板上 LED;序列埠用 115200。
  • Wi-Fi 連線只支援 2.4 GHz。連上後 ESP32 會拿到一個 IP 位址,手機要在同一個 Wi-Fi 才找得到它。
  • 網頁伺服器三步驟:server.on() 登記路徑、server.begin() 開店、loop() 裡不停 server.handleClient()。loop() 不能有長 delay()。
  • DHT11 接 GPIO 4、OLED 接 SDA=21、SCL=22,兩者都用 3V3 供電;OLED 位址 0x3C。
  • 示波器雙通道對照可以親眼看到 5V 和 3.3V 的差距;兩塊板子要共 GND 才能比較。
  • MQTT 是用「公布欄」轉發訊息的物聯網方法;深度睡眠讓 ESP32 平常只吃 0.01 mA,電池可以撐好幾個月。

名詞表

中文英文一句話解釋
ESP32ESP32樂鑫公司出的微控制器,內建 Wi-Fi 與藍牙,3.3V 邏輯。
3.3V 邏輯3.3V logic腳位的 HIGH 是 3.3V,輸入也只能承受 3.3V 的規格。
雙核心Dual Core晶片裡有兩個處理器同時工作。
快閃記憶體Flash存放程式的記憶體,斷電不會消失;ESP32 的 GPIO 6–11 接著它。
只能輸入腳位Input-only pinGPIO 34–39,不能輸出,也沒有內建上拉。
BOOT 鍵BOOT button按住它可以讓 ESP32 進入下載模式,上傳程式用。
開發板管理員Boards ManagerArduino IDE 裡安裝新板子支援的地方。
SSIDService Set IdentifierWi-Fi 網路的名字。
IP 位址IP Address網路上每台裝置的門牌號碼,例如 192.168.1.57。
訊號強度RSSIWi-Fi 訊號強度,負數,越接近 0 越強。
網頁伺服器Web Server等瀏覽器來「要東西」然後回傳網頁的程式。
埠號Port同一個 IP 上不同服務的「門」,網頁用 80。
HTMLHyperText Markup Language描述網頁長什麼樣子的文字格式。
路徑Route / Path網址後面的 /on、/off,告訴伺服器你要哪個東西。
物聯網IoT, Internet of Things讓各種裝置都能上網互相傳資料的概念。
MQTTMessage Queuing Telemetry Transport用「公布欄」(Broker)轉發小訊息的物聯網通訊方式。
代理人BrokerMQTT 裡負責收發訊息的中央伺服器。
發布/訂閱Publish / Subscribe往主題貼訊息,與登記「這個主題有更新就通知我」。
主題TopicMQTT 訊息的分類名稱,例如「教室/溫度」。
深度睡眠Deep SleepESP32 幾乎全部關機、只留計時器的省電模式。
欠壓偵測Brownout detector供電不足時讓板子重開的保護機制。

第 17 章 專題製作

本章目標

  • 學完你會照著「問題 → 規劃 → 接線 → 程式 → 測試 → 展示」六個步驟,把一個想法變成會動的作品。
  • 學完你會獨立完成五個專題中的至少兩個:一個用 UNO、一個用 ESP32。
  • 學完你會用示波器或邏輯分析儀「證明」你的作品真的照你想的方式在運作,而不是只看它會不會動。
  • 學完你會寫一份有量測數據的專題報告,並在三分鐘內把作品講清楚。

開場:從「會動」到「我知道它為什麼會動」

社團成果發表會前兩週,小安把一個夜燈接好了:天黑 LED 就亮,天亮就暗。她很開心,直到隔壁的學長問了一句:「你的燈是漸漸變亮,還是一下子跳亮?」她愣住了。肉眼看起來好像是漸漸的……但她沒辦法確定,也說不出 LED 收到的訊號到底長什麼樣。

學長把示波器探棒鉤上去,螢幕上出現一串方波,寬窄正在慢慢變化。「這叫占空比,你第 14 章學過。你的燈的確是漸亮的,而且從全暗到全亮花了大概 2.5 秒。把這張波形放進報告,評審一看就知道你不只是接對線,你還懂它。」

這一章就是要帶你走到那一步。前面十六章你學了元件、儀器和程式;現在要把它們組合成完整的作品,而且每一個作品都要能用儀器拿出證據。五個專題難度由淺到深,你可以挑一個做,也可以全部做完。最後我們會談怎麼寫報告、怎麼上台。

核心概念

專題的六個步驟

比喻:做專題像蓋一間樹屋。你不會一開始就釘木板,而是先想「要給誰用、要多大」(問題),畫個草圖、列材料(規劃),再搭骨架(接線)、裝門窗(程式),爬上去跳一跳看會不會垮(測試),最後邀朋友來參觀(展示)。

 ┌──────┐   ┌──────┐   ┌──────┐   ┌──────┐   ┌──────┐   ┌──────┐
 │ 問題 │──►│ 規劃 │──►│ 接線 │──►│ 程式 │──►│ 測試 │──►│ 展示 │
 └──────┘   └──────┘   └──────┘   └──────┘   └──┬───┘   └──────┘
                 ▲                                │
                 └────── 測試不過就回頭改 ─────────┘

1. 問題:用一句話說清楚「誰、在什麼情況下、需要什麼」。例如:「晚上起床上廁所的人,需要一盞不刺眼、會自己亮的小燈。」寫不出這句話,後面都會很模糊。

2. 規劃:把問題拆成「輸入 → 處理 → 輸出」三格,再把每一格填上你會的元件。

輸入(感測)處理(微控制器做判斷)輸出(動作)
光敏電阻量亮度太暗就慢慢調高 PWMLED 漸亮

填好以後,列材料清單,並且翻回前面的章節確認每個元件你都接過。這一步最常被跳過,也最常導致後面卡住。

3. 接線:先接電源和 GND,再接輸入,最後接輸出。每接完一部分就用三用電表量一下該有電壓的地方有沒有電壓。一次只接一個部分。

4. 程式:先寫「最小可動版本」,例如只讀感測器印到序列埠;確認數字合理,再加判斷;最後加輸出。每加一段就上傳一次。千萬不要一口氣寫完 100 行才第一次上傳。

5. 測試:分三層。第一層「看起來會動」;第二層「序列埠印出的數字合理」;第三層「用示波器或邏輯分析儀量到的波形跟程式設定的一樣」。本章每個專題都會做到第三層。

6. 展示:準備一張海報或三張投影片、一段兩分鐘的現場操作、一份附量測數據的報告。章末會細講。

專題程式的共同骨架

五個專題的程式看起來很長,但骨架都一樣:

// 1. 腳位與常數:所有數字集中放在最上面,要調整時不用到處找
// 2. 全域變數:記住「現在的狀態」,例如 LED 亮度、風扇段速
// 3. 小函式:每個函式只做一件事(讀感測器、更新螢幕、處理網頁)
// 4. setup():設定腳位、啟動序列埠、連 Wi-Fi、初始化螢幕
// 5. loop():用 millis() 排程,不要用長 delay()

第 5 點在 ESP32 專題裡特別重要:網頁伺服器需要 loop() 一直跑 server.handleClient(),一個 delay(2000) 就會讓手機按鈕兩秒沒反應。寫法是記住「上次做這件事的時間」,每圈 loop() 檢查「現在減上次」有沒有超過間隔:

if (millis() - lastReadTime >= 2000) {   // 距離上次讀已經 2 秒了嗎?
  lastReadTime = millis();               // 記住這次的時間
  readSensor();                          // 做該做的事
}

除錯的三個習慣

  1. 先量電,再看程式:七成的「不會動」是接線問題。三用電表量 VCC 和 GND 之間有沒有正確電壓,是第一件事。
  2. 每個關鍵數值都 Serial.print():感測器讀值、算出來的 PWM 值、收到的網頁路徑。看得到數字才知道哪一段出錯。
  3. 一次只改一個地方:改了接線就不要同時改程式。不然你不知道是哪個改動讓它好起來或壞掉。

動手做

每個專題的結構都一樣:目標 → 材料 → 接線 → 程式 → 測試方法 → 延伸挑戰。「測試方法」裡至少有一項要用示波器或邏輯分析儀,請把量到的數字填進表格,這些就是你報告裡的證據。

實驗 17-1:專題一 智慧夜燈

目標

做一盞用光敏電阻感應環境亮度的夜燈。環境越暗,LED 越亮;而且亮度是漸漸變化的,不會一下子跳亮或跳暗。整個過程用示波器證明 PWM 占空比真的在連續變化。

材料

  • Arduino UNO ×1
  • 光敏電阻(LDR)×1
  • 10kΩ 電阻 ×1
  • 白色 LED ×1(紅色也可以,但夜燈用白色或暖色比較像真的)
  • 220Ω 電阻 ×1
  • 麵包板、杜邦線

接線

 UNO 5V ────[ LDR ]────┬────[ 10kΩ ]──── GND
                       │
                    UNO A0

 UNO D9 ──[ 220Ω ]──►|── GND
                    白色 LED

文字說明:

  • UNO 5V → 光敏電阻一腳;光敏電阻另一腳 → A0,同一點 → 10kΩ → GND。
  • UNO D9 → 220Ω → LED 長腳;LED 短腳 → GND。

光敏電阻在亮的時候電阻小(幾百歐姆),暗的時候電阻大(幾十 kΩ 以上)。這個分壓器讓 A0 在亮的時候電壓高、暗的時候電壓低,第 13 章做過。

程式

// 專題一:智慧夜燈(UNO)
// 天暗 → LED 漸亮;天亮 → LED 漸暗

const int ldrPin = A0;         // 光敏電阻分壓點
const int ledPin = 9;          // PWM 腳位,接 LED

// 這兩個數值要依你的教室調整:先看序列埠,記下「蓋住」和「正常光」的讀值
const int darkValue   = 200;   // 低於這個算全暗 → LED 全亮
const int brightValue = 700;   // 高於這個算全亮 → LED 全暗

int currentBrightness = 0;     // 目前 LED 的 PWM 值(0–255)
const int fadeStepDelay = 10;  // 每 10 毫秒調整 1,全程 255 步 ≈ 2.5 秒

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("smart night light start");
}

void loop() {
  int light = analogRead(ldrPin);                    // 0–1023,越亮越大

  // 把亮度讀值對應成「目標 LED 亮度」:暗 → 255,亮 → 0
  int target = map(light, darkValue, brightValue, 255, 0);
  target = constrain(target, 0, 255);               // 超出範圍就夾在 0–255

  // 每圈只往目標走一步,所以變化是漸漸的
  if (currentBrightness < target) {
    currentBrightness++;
  } else if (currentBrightness > target) {
    currentBrightness--;
  }
  analogWrite(ledPin, currentBrightness);           // 輸出 PWM

  // 印成「名稱:數值」格式,序列繪圖器會畫成兩條線
  Serial.print("light:");
  Serial.print(light);
  Serial.print(",led:");
  Serial.println(currentBrightness);

  delay(fadeStepDelay);
}

步驟

  1. 接線完成後,先用三用電表量 A0 對 GND:正常光線下應該有 2–4V,用手蓋住光敏電阻會掉到 1V 以下。沒有變化就是分壓器接錯了。
  2. 上傳程式,打開序列繪圖器(工具 → 序列繪圖器,鮑率 9600)。
  3. 看 light 那條線,在正常光線和蓋住的情況各記一個數值,填進程式的 brightValue 和 darkValue,重新上傳。
  4. 用手慢慢蓋住光敏電阻,看 LED 和 led 那條線。

你應該看到

蓋住光敏電阻後,light 線立刻往下掉,但 led 線是一條斜斜往上爬的線,花大約 2.5 秒才到 255;LED 也跟著慢慢變亮。放開手則反過來。

測試方法(示波器)

探棒鉤 D9,鱷魚夾接 GND。設定 2 V/div、500 µs/div、觸發 CH1 上升緣 2.5V。

電壓(LED 全暗,占空比 0%)
 5V ┤
 0V ┼──────────────────────────── 時間

電壓(半亮,占空比約 50%)
 5V ┤  ┌────┐    ┌────┐    ┌────┐
 0V ┼──┘    └────┘    └────┘    └─

電壓(LED 全亮,占空比 100%)
 5V ┤──────────────────────────────
 0V ┼
      ◄────────►
       約 2.04 ms(490 Hz)

用手慢慢蓋住光敏電阻,你會看到方波的「高的部分」慢慢變寬,直到整條線貼在 5V。用示波器的自動量測功能讀「頻率」和「正占空比(+Duty)」,填表:

情況序列埠的 led 值示波器占空比算出來的 led 值(占空比 × 255)頻率
正常光線
半蓋住
全蓋住

舉例:如果示波器讀到占空比 40%,0.40 × 255 = 102,應該跟序列埠印的 led 值差不多。頻率應該接近 490 Hz,這是 UNO D9 的 PWM 頻率。

延伸挑戰

  • 加一顆按鈕(D2,INPUT_PULLUP):按一下切換「自動/強制關燈」,半夜不想被亮到的時候可以關掉。
  • 把 LED 換成 2N2222 電晶體驅動三顆白色 LED 並聯(第 9 章接法),亮度夠照亮床邊。
  • 加一個「亮了 30 分鐘就自動變暗」的功能,用 millis() 計時。

實驗 17-2:專題二 溫濕度氣象站

目標

做一台放在教室的氣象站:OLED 顯示目前溫濕度和今天的最高、最低溫;手機打開網頁可以看到目前數值和最近 24 筆溫度的長條圖。用邏輯分析儀證明 ESP32 確實用 I2C 在跟 OLED 講話。

材料

  • ESP32 DevKit V1 ×1
  • DHT11 溫濕度感測器 ×1
  • 0.96 吋 OLED(SSD1306,I2C)×1
  • 10kΩ 電阻 ×1(裸元件四腳版 DHT11 才需要)
  • 麵包板、杜邦線
  • USB 邏輯分析儀(測試用)

接線

                 ┌─────────────────┐
     3V3 ────────┤ VCC    DHT11    │
     GPIO 4 ─────┤ DATA            │
     GND ────────┤ GND             │
                 └─────────────────┘
                 ┌─────────────────┐
     3V3 ────────┤ VCC    OLED     │
     GND ────────┤ GND   SSD1306   │
     GPIO 21 ────┤ SDA             │
     GPIO 22 ────┤ SCL             │
                 └─────────────────┘

文字說明:跟第 16 章實驗 16-4 完全一樣。DHT11 DATA → GPIO 4;OLED SDA → GPIO 21、SCL → GPIO 22;兩個元件都用 3V3 和 GND。

程式

// 專題二:溫濕度氣象站(ESP32)
// OLED 顯示目前值與最高最低溫,網頁顯示數值與最近 24 筆長條圖
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const char* ssid     = "你的Wi-Fi名稱";
const char* password = "你的Wi-Fi密碼";

#define DHTPIN 4
DHT dht(DHTPIN, DHT11);
Adafruit_SSD1306 display(128, 64, &Wire, -1);
WebServer server(80);

float temperature = 0, humidity = 0;      // 目前值
float tempMax = -100, tempMin = 100;      // 開機以來的最高、最低溫

const int HISTORY_SIZE = 24;              // 記最近 24 筆
float tempHistory[HISTORY_SIZE];
int historyCount = 0;                     // 目前記了幾筆
// 展示時可以把 60000 改成 5000(每 5 秒一筆),長條圖很快就會長出來
const unsigned long HISTORY_INTERVAL = 60000UL;
unsigned long lastHistoryTime = 0;
unsigned long lastReadTime = 0;

// 讀感測器並更新最高最低
void readSensor() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (isnan(t) || isnan(h)) {             // 讀失敗就跳過這次
    Serial.println("DHT11 read failed");
    return;
  }
  temperature = t;
  humidity = h;
  if (t > tempMax) tempMax = t;           // 更新紀錄
  if (t < tempMin) tempMin = t;
}

// 把目前溫度加進歷史紀錄,滿了就把最舊的擠掉
void addHistory() {
  if (historyCount < HISTORY_SIZE) {
    tempHistory[historyCount] = temperature;
    historyCount++;
  } else {
    for (int i = 0; i < HISTORY_SIZE - 1; i++) {
      tempHistory[i] = tempHistory[i + 1]; // 全部往前移一格
    }
    tempHistory[HISTORY_SIZE - 1] = temperature;
  }
}

// OLED 畫面
void showOnOled() {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("http://");
  display.println(WiFi.localIP());        // 第一行印網址

  display.setTextSize(2);
  display.setCursor(0, 16);
  display.print(temperature, 1);
  display.print("C ");
  display.print(humidity, 0);
  display.println("%");

  display.setTextSize(1);                 // 第三行印最高最低
  display.setCursor(0, 44);
  display.print("Max ");
  display.print(tempMax, 1);
  display.print("  Min ");
  display.println(tempMin, 1);
  display.setCursor(0, 56);
  display.print("Up ");
  display.print(millis() / 60000);        // 開機幾分鐘
  display.println(" min");
  display.display();
}

// 網頁:目前值、最高最低、長條圖
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<meta http-equiv='refresh' content='10'>";
  html += "<title>教室氣象站</title></head>";
  html += "<body style='font-family:sans-serif;margin:20px'>";
  html += "<h1>教室氣象站</h1>";
  html += "<p style='font-size:2.5em;margin:0'>" + String(temperature, 1) + " &deg;C</p>";
  html += "<p style='font-size:2.5em;margin:0'>" + String(humidity, 0) + " %</p>";
  html += "<p>最高 " + String(tempMax, 1) + " &deg;C 最低 " + String(tempMin, 1) + " &deg;C";
  html += " 已開機 " + String(millis() / 60000) + " 分鐘</p>";
  html += "<h2>最近 " + String(historyCount) + " 筆溫度</h2>";

  // 每一筆畫一條長條:溫度 10°C = 0 像素,40°C = 300 像素
  for (int i = 0; i < historyCount; i++) {
    int width = (int)((tempHistory[i] - 10.0) * 10.0);
    width = constrain(width, 2, 300);
    html += "<div style='display:flex;align-items:center;margin:2px'>";
    html += "<div style='background:#4a90e2;height:14px;width:" + String(width) + "px'></div>";
    html += "<span style='margin-left:6px'>" + String(tempHistory[i], 1) + "</span></div>";
  }
  html += "</body></html>";
  server.send(200, "text/html; charset=utf-8", html);
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  Wire.begin(21, 22);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED not found");
    while (true) delay(10);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Connecting WiFi...");
  display.display();

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.begin();

  delay(1500);                              // DHT11 開機要一點時間
  readSensor();
  addHistory();                             // 第一筆
  showOnOled();
}

void loop() {
  server.handleClient();

  if (millis() - lastReadTime >= 2000) {    // 每 2 秒讀一次、更新 OLED
    lastReadTime = millis();
    readSensor();
    showOnOled();
  }
  if (millis() - lastHistoryTime >= HISTORY_INTERVAL) {  // 定時記一筆
    lastHistoryTime = millis();
    addHistory();
    Serial.print("history ");
    Serial.print(historyCount);
    Serial.print(" : ");
    Serial.println(temperature);
  }
}

步驟

  1. 填入 Wi-Fi 名稱密碼,上傳。
  2. OLED 第一行出現網址,手機輸入。
  3. 展示時把 HISTORY_INTERVAL 改成 5000,讓長條圖在兩分鐘內長出 24 條;正式使用再改回 60000。
  4. 用手捏住 DHT11 一分鐘,看最高溫紀錄會不會更新。

你應該看到

OLED 顯示三行:網址、大字溫濕度、最高最低與開機時間。網頁每 10 秒更新,長條圖一條一條增加,捏住感測器後長條變長。

測試方法(邏輯分析儀)

邏輯分析儀 CH0 → GPIO 21(SDA),CH1 → GPIO 22(SCL),GND → ESP32 GND。PulseView 取樣率 2 MHz、取樣 2 秒,加入 I2C 解碼器(SDA=CH0、SCL=CH1)。

SCL ─┐ ┌┐ ┌┐ ┌┐ ┌┐ ┌┐ ┌┐ ┌┐ ┌┐ ┌─
      └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘
SDA ─┐   ┌──┐  ┌─────┐     ┌──  ...
      └───┘  └──┘     └─────┘
      S  0  1  1  1  1  0  0  W  A   ← 解碼器顯示:位址 0x3C,寫入,ACK

每 2 秒應該出現一大串 I2C 封包(那是 display.display() 把整個畫面 1024 個位元組送過去)。填表:

項目你量到的
解碼出的 OLED 位址(應該是 0x3C)
兩串封包之間的間隔(應該約 2 秒)
一串封包總共多長(毫秒)
SCL 一個週期的時間 → 算出 I2C 時脈頻率

舉例:如果 SCL 一個週期是 10 µs,頻率就是 1 ÷ 0.00001 = 100 kHz,這是 I2C 的標準速度。

延伸挑戰

  • 加入濕度的長條圖,用不同顏色。
  • 用第 16 章的深度睡眠,改成電池供電版本:醒來 10 秒把數值印在 OLED 上,然後睡 5 分鐘。
  • 濕度超過 80% 時讓 GPIO 2 的 LED 閃爍提醒。

實驗 17-3:專題三 手機 Wi-Fi 遙控風扇

目標

做一台可以用手機網頁控制「關/低/中/高」四段速的小風扇。ESP32 輸出 PWM,經 IRLZ44N MOSFET 驅動直流馬達。用示波器量 MOSFET 閘極與汲極的波形,證明三段速真的是三種占空比。

材料

  • ESP32 DevKit V1 ×1
  • N 通道 MOSFET IRLZ44N ×1
  • 小直流馬達(3–6V)×1,可以在軸上黏一片紙板當扇葉
  • 整流二極體 1N4007 ×1(飛輪二極體)
  • 220Ω 電阻 ×1(閘極電阻)
  • 10kΩ 電阻 ×1(閘極下拉)
  • 3 號電池盒(3 顆,4.5V)×1
  • 麵包板、杜邦線

接線

                              IRLZ44N(正面看,腳位由左到右 G D S)
 ESP32 GPIO 18 ──[ 220Ω ]──┬── G
                           │
                        [ 10kΩ ]
                           │
                          GND

 電池盒 +4.5V ──┬───( 馬達 )───┬── D
               │              │
               └───|◄─────────┘        1N4007:有條紋的那端朝電池正極
                 1N4007

 S ── GND ──┬── 電池盒 −
            └── ESP32 GND(一定要跟電池盒負極接在一起)

文字說明:

  • ESP32 GPIO 18 → 220Ω → IRLZ44N 閘極(G);G 另外 → 10kΩ → GND(確保 ESP32 還沒開機時 MOSFET 是關的)。
  • 電池盒正極 → 馬達一腳;馬達另一腳 → IRLZ44N 汲極(D)。
  • 1N4007 跨接在馬達兩端:有條紋的一端接電池正極那側,另一端接汲極那側。沒有它,關掉馬達時的尖波會打壞 MOSFET(第 7 章看過)。
  • IRLZ44N 源極(S)→ GND。電池盒負極、ESP32 GND、MOSFET 的 S 三個點要接在一起。
  • 不要用 ESP32 的 3V3 腳供電給馬達,馬達啟動電流會讓 ESP32 重開。

程式

// 專題三:手機 Wi-Fi 遙控風扇(ESP32 + IRLZ44N)
#include <WiFi.h>
#include <WebServer.h>

const char* ssid     = "你的Wi-Fi名稱";
const char* password = "你的Wi-Fi密碼";

const int fanPin   = 18;          // PWM 輸出 → MOSFET 閘極
const int PWM_FREQ = 1000;        // 1 kHz,馬達不會發出刺耳的聲音
const int PWM_RES  = 8;           // 8 位元 → 0–255

int fanLevel = 0;                 // 0 關、1 低、2 中、3 高
const int levelDuty[4] = {0, 110, 180, 255};   // 各段的 PWM 值;低速太小馬達會轉不動
const char* levelName[4] = {"關", "低", "中", "高"};

WebServer server(80);

// 設定風扇段速
void setFan(int level) {
  fanLevel = constrain(level, 0, 3);
  ledcWrite(fanPin, levelDuty[fanLevel]);     // 輸出對應的占空比
  Serial.print("fan level ");
  Serial.print(fanLevel);
  Serial.print(" duty ");
  Serial.println(levelDuty[fanLevel]);
}

// 網頁:四顆大按鈕
String makePage() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<title>Wi-Fi 風扇</title></head>";
  html += "<body style='font-family:sans-serif;text-align:center;margin-top:30px'>";
  html += "<h1>Wi-Fi 風扇</h1>";
  html += "<p style='font-size:1.5em'>目前:<b>" + String(levelName[fanLevel]) + "</b>";
  html += "(PWM " + String(levelDuty[fanLevel]) + "/255)</p>";
  const char* paths[4] = {"/off", "/low", "/mid", "/high"};
  for (int i = 0; i < 4; i++) {
    html += "<p><a href='" + String(paths[i]) + "'><button style='font-size:1.8em;width:60%;padding:15px";
    if (i == fanLevel) html += ";background:orange";   // 目前段速的按鈕上色
    html += "'>" + String(levelName[i]) + "</button></a></p>";
  }
  html += "</body></html>";
  return html;
}

void sendPage() {
  server.send(200, "text/html; charset=utf-8", makePage());
}
void handleRoot() { sendPage(); }
void handleOff()  { setFan(0); sendPage(); }
void handleLow()  { setFan(1); sendPage(); }
void handleMid()  { setFan(2); sendPage(); }
void handleHigh() { setFan(3); sendPage(); }

void setup() {
  Serial.begin(115200);

  // 設定 PWM(esp32 核心 3.x 的寫法)
  ledcAttach(fanPin, PWM_FREQ, PWM_RES);
  // 如果你的 esp32 核心是 2.x,編譯會說找不到 ledcAttach,請改用下面三行:
  // ledcSetup(0, PWM_FREQ, PWM_RES);
  // ledcAttachPin(fanPin, 0);
  // 並把 setFan 裡的 ledcWrite(fanPin, ...) 改成 ledcWrite(0, ...)
  setFan(0);                                   // 一開機先確定風扇是關的

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/off", handleOff);
  server.on("/low", handleLow);
  server.on("/mid", handleMid);
  server.on("/high", handleHigh);
  server.begin();
}

void loop() {
  server.handleClient();                       // 不要加 delay
}

步驟

  1. 先不要裝電池。接好所有線後,用三用電表確認 ESP32 GND 和電池盒負極之間是 0Ω(通路)。
  2. 上傳程式,看序列埠拿到 IP。
  3. 裝上電池,手機打開網頁,依序按「低、中、高、關」。
  4. 用手摸 IRLZ44N 的外殼,跑一分鐘高速後應該只是微溫。如果燙手,檢查是不是 G、D、S 接反了。

你應該看到

按「低」馬達慢慢轉(有時候要用手撥一下才會啟動,這是正常的),「中」明顯變快,「高」最快,「關」停下來。網頁上目前段速的按鈕會變橘色。

測試方法(示波器,雙通道)

CH1 探棒鉤 IRLZ44N 的 G(閘極),CH2 鉤 D(汲極),兩個鱷魚夾都接 GND。設定 CH1 2 V/div、CH2 2 V/div、時間 200 µs/div,觸發 CH1 上升緣 1.5V。

CH1 閘極(中速,占空比約 70%)
3.3V ┤ ┌───────┐   ┌───────┐   ┌───────┐
  0V ┼─┘       └───┘       └───┘       └──

CH2 汲極(跟閘極相反:閘極 HIGH 時 MOSFET 導通,汲極被拉到 0V)
4.5V ┤─┐       ┌───┐       ┌───┐       ┌──
  0V ┼ └───────┘   └───────┘   └───────┘
       ◄─────────►
          1 ms(1 kHz)

填表:

段速程式的 PWM 值示波器 CH1 占空比PWM 值 ÷ 255 × 100%頻率CH2 的 HIGH 電壓
低11043%
中18071%
高255100%

舉例:中速 180 ÷ 255 = 0.706,示波器應該讀到大約 70%。CH2 的 HIGH 電壓會接近電池電壓 4.5V,LOW 時接近 0V,而且 CH2 和 CH1 剛好相反:這就是第 9 章學的「開關反相」。如果你在 CH2 上看到馬達關掉瞬間有小小的尖波,那是二極體還沒完全壓下去的部分;沒有二極體的話尖波會高到十幾伏特。

延伸挑戰

  • 把四顆按鈕換成一條滑桿(HTML 的 <input type='range'>),讓風速可以無段調整。提示:路徑可以用 /set?duty=123 這種帶參數的形式,用 server.arg("duty") 讀取。
  • 加上 DHT11,溫度超過 28°C 自動開到中速,形成「智慧風扇」。
  • 加一個定時:按「高」之後 10 分鐘自動關。

實驗 17-4:專題四 ESP32 迷你示波器

目標

用 ESP32 的類比輸入快速取樣,把波形畫在 Arduino IDE 的序列繪圖器上,並自動算出頻率和電壓範圍。訊號源是 UNO 的 tone() 方波,經過分壓器降到 2.5V 以下再送進 ESP32。最後用真的示波器量同一個訊號,比較兩邊的結果,看看你的迷你示波器準不準。

材料

  • ESP32 DevKit V1 ×1
  • Arduino UNO ×1(當訊號產生器)
  • 10kΩ 電阻 ×2
  • 麵包板、杜邦線
  • 示波器(比對用)

接線

 UNO D8 ──[ 10kΩ ]──┬──[ 10kΩ ]── GND
  (tone 方波 0–5V)  │
                    ├────────────── ESP32 GPIO 34(0–2.5V)
                    │
                    └────────────── 示波器 CH1 探棒(比對用)

 UNO GND ──────────── ESP32 GND ──── 示波器鱷魚夾

文字說明:

  • UNO D8 → 10kΩ → 分壓點;分壓點 → 10kΩ → GND。
  • 分壓點 → ESP32 GPIO 34。
  • UNO GND → ESP32 GND,用一條杜邦線直接接。沒接共地,讀值會亂飄。
  • 分壓器把 5V 降成 2.5V,這樣 ESP32 的輸入腳才安全(第 16 章講過)。

程式(UNO:訊號產生器)

// 專題四(UNO 端):產生 440 Hz 方波當訊號源
const int tonePin = 8;

void setup() {
  tone(tonePin, 440);     // 440 Hz,就是鋼琴的 A 音
}

void loop() {
  // 什麼都不用做,tone() 會自己持續輸出
}

程式(ESP32:迷你示波器)

// 專題四(ESP32 端):迷你示波器
// plotMode = true  → 給序列繪圖器畫波形
// plotMode = false → 給序列監控視窗印頻率、電壓等數據
const bool plotMode = true;

const int probePin = 34;           // 只能輸入的腳,適合當探棒
const int SAMPLES  = 400;          // 一次抓 400 個點
uint16_t buffer[SAMPLES];          // 存取樣值(0–4095)

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);        // 12 位元:0–4095
  analogSetAttenuation(ADC_11db);  // 量測範圍最大約 3.3V
  pinMode(probePin, INPUT);
}

void loop() {
  // 1. 盡可能快地連續取樣,並記錄花了多久
  unsigned long t0 = micros();
  for (int i = 0; i < SAMPLES; i++) {
    buffer[i] = analogRead(probePin);
  }
  unsigned long t1 = micros();
  float dtMicros = (float)(t1 - t0) / SAMPLES;     // 每兩個點之間的時間(µs)

  // 2. 找最大值、最小值
  int vMaxRaw = 0, vMinRaw = 4095;
  for (int i = 0; i < SAMPLES; i++) {
    if (buffer[i] > vMaxRaw) vMaxRaw = buffer[i];
    if (buffer[i] < vMinRaw) vMinRaw = buffer[i];
  }
  float vMax = vMaxRaw * 3.3 / 4095.0;             // 換算成伏特
  float vMin = vMinRaw * 3.3 / 4095.0;

  // 3. 算頻率:數波形從下面穿過中線往上的次數
  int mid = (vMaxRaw + vMinRaw) / 2;
  int margin = 100;                                // 留一點空間避免雜訊重複計數
  int crossings = 0;
  int firstCross = -1, lastCross = -1;
  bool wasLow = buffer[0] < mid;
  for (int i = 1; i < SAMPLES; i++) {
    if (wasLow && buffer[i] > mid + margin) {      // 由低變高
      crossings++;
      if (firstCross < 0) firstCross = i;
      lastCross = i;
      wasLow = false;
    } else if (!wasLow && buffer[i] < mid - margin) {
      wasLow = true;
    }
  }
  float freq = 0;
  if (crossings >= 2) {
    // 第一次到最後一次上升之間有 (crossings-1) 個完整週期
    float spanSeconds = (lastCross - firstCross) * dtMicros / 1000000.0;
    freq = (crossings - 1) / spanSeconds;
  }

  // 4. 輸出
  if (plotMode) {
    for (int i = 0; i < SAMPLES; i++) {
      Serial.println(buffer[i] * 3.3 / 4095.0, 2);   // 每行一個電壓值
    }
  } else {
    Serial.print("sample interval: ");
    Serial.print(dtMicros, 1);
    Serial.print(" us   sample rate: ");
    Serial.print(1000000.0 / dtMicros / 1000.0, 1);
    Serial.println(" kHz");
    Serial.print("Vmax: ");
    Serial.print(vMax, 2);
    Serial.print(" V   Vmin: ");
    Serial.print(vMin, 2);
    Serial.print(" V   Vpp: ");
    Serial.print(vMax - vMin, 2);
    Serial.println(" V");
    Serial.print("frequency: ");
    Serial.print(freq, 1);
    Serial.println(" Hz");
    Serial.println("------");
    delay(1000);
  }
}

步驟

  1. UNO 上傳訊號產生器程式。ESP32 上傳迷你示波器程式(plotMode = true)。
  2. 打開 ESP32 的序列繪圖器(115200)。
  3. 看到方波後,把 plotMode 改成 false,重新上傳,改開序列監控視窗,抄下取樣間隔、Vmax、Vmin、頻率。
  4. 把示波器探棒鉤在分壓點,設定 1 V/div、1 ms/div、觸發上升緣 1.2V,用自動量測讀頻率和 Vpp。

你應該看到

序列繪圖器出現一串整齊的方波,高的地方約 2.5V、低的地方約 0V。序列監控視窗印出取樣間隔大約 20–60 µs(不同版本的 esp32 核心差很多)、Vpp 約 2.4–2.5V、頻率在 430–450 Hz 之間。

序列繪圖器畫面(示意)
2.5V ┤  ┌───┐   ┌───┐   ┌───┐   ┌───┐
     │  │   │   │   │   │   │   │   │
  0V ┼──┘   └───┘   └───┘   └───┘   └──
        ◄───────►
      大約 50 個點 = 一個週期

測試方法(示波器比對)

這個專題的測試就是「跟真的示波器打對台」。填表:

項目迷你示波器真示波器差多少
頻率(Hz)
最高電壓(V)
最低電壓(V)
Vpp(V)
取樣間隔(µs)(示波器顯示的取樣率倒數)

算一個例子:如果迷你示波器的取樣間隔是 50 µs,取樣率就是 1 ÷ 0.00005 = 20 kHz,也就是每秒 20,000 個點。440 Hz 的方波一個週期是 2.27 ms = 2270 µs,2270 ÷ 50 ≈ 45 個點,畫出來很清楚。真示波器的取樣率通常是幾百 MHz,是你的幾萬倍,這就是為什麼它能看高頻訊號而你的不行。

一個有趣的實驗:把 UNO 的 tone(tonePin, 440) 改成 tone(tonePin, 5000)。5000 Hz 一個週期只有 200 µs,用 50 µs 取樣只能抓到 4 個點,畫出來會歪七扭八;改成 tone(tonePin, 19000) 的話,甚至會畫出一個完全錯誤的慢波。這叫混疊(Aliasing):取樣太慢的時候看到的是假象。所以經驗法則是,一個週期至少要取 10 個點,你的迷你示波器大概只能相信 1000 Hz 以下的訊號。

延伸挑戰

  • 讓 UNO 每 3 秒換一個頻率(220、440、880 Hz),看迷你示波器算的頻率跟不跟得上。
  • 把分壓點加上第 10 章的 RC 低通濾波器(10kΩ + 100nF),用迷你示波器看方波變成圓角的樣子。
  • 加上「觸發」:在印出 buffer 之前,先找到第一個上升沿的位置,從那裡開始印。這樣每次畫出來的波形起點都一樣,不會左右亂跳,就像真示波器的觸發功能。

實驗 17-5:專題五 反應遊戲與電子琴

目標

用三顆按鈕、三顆 LED 和一顆蜂鳴器做一台雙用途的機器。開機時按住按鈕 1 進入「電子琴模式」:三顆按鈕各發一個音。直接開機則進入「反應遊戲模式」:隨機等幾秒後隨機亮一顆燈並嗶一聲,玩家要盡快按對應的按鈕,機器算出反應時間,五回合後公布最佳成績。用邏輯分析儀獨立量出「燈亮到按下」的時間,驗證程式算的反應時間是對的。

材料

  • Arduino UNO ×1
  • 按鈕開關 ×3
  • LED(紅、綠、藍)各 1
  • 220Ω 電阻 ×3
  • 無源蜂鳴器 ×1
  • 麵包板、杜邦線
  • USB 邏輯分析儀(測試用)

接線

 UNO D2 ───┬── 按鈕 1 ── GND       (內建上拉:沒按 = HIGH,按下 = LOW)
 UNO D3 ───┬── 按鈕 2 ── GND
 UNO D4 ───┬── 按鈕 3 ── GND

 UNO D9  ──[ 220Ω ]──►|── GND    紅 LED(對應按鈕 1)
 UNO D10 ──[ 220Ω ]──►|── GND    綠 LED(對應按鈕 2)
 UNO D11 ──[ 220Ω ]──►|── GND    藍 LED(對應按鈕 3)

 UNO D8 ──( 蜂鳴器 + )
          ( 蜂鳴器 − )── GND

文字說明:

  • 三顆按鈕各一腳接 D2、D3、D4,另一腳接 GND。程式用 INPUT_PULLUP,不用外接電阻。
  • D9 → 220Ω → 紅 LED 長腳,短腳 → GND;D10 綠、D11 藍同樣接法。
  • 蜂鳴器正極(長腳或標 + 的那端)→ D8,負極 → GND。
  • 把三顆按鈕和三顆 LED 由左到右排整齊,紅配按鈕 1、綠配按鈕 2、藍配按鈕 3,玩家才不會搞混。

程式

// 專題五:反應遊戲 + 電子琴(UNO)
// 開機時按住按鈕 1 → 電子琴模式;否則 → 反應遊戲模式

const int buttonPins[3] = {2, 3, 4};      // 三顆按鈕(INPUT_PULLUP,按下 = LOW)
const int ledPins[3]    = {9, 10, 11};    // 三顆 LED
const int buzzerPin     = 8;
const int notes[3]      = {262, 330, 392}; // Do、Mi、Sol 的頻率(Hz)

const int ROUNDS = 5;                     // 一局幾回合
bool pianoMode = false;

// 讀第 i 顆按鈕,按下回傳 true
bool isPressed(int i) {
  return digitalRead(buttonPins[i]) == LOW;
}

// 等所有按鈕都放開
void waitAllReleased() {
  while (isPressed(0) || isPressed(1) || isPressed(2)) {
    delay(5);
  }
  delay(30);                              // 等彈跳結束
}

// 三顆 LED 全關
void allLedsOff() {
  for (int i = 0; i < 3; i++) digitalWrite(ledPins[i], LOW);
}

// 嗶一聲:頻率、長度
void beep(int freq, int ms) {
  tone(buzzerPin, freq, ms);
  delay(ms);
}

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    pinMode(ledPins[i], OUTPUT);
  }
  pinMode(buzzerPin, OUTPUT);
  randomSeed(analogRead(A0));             // 用沒接東西的 A0 的雜訊當亂數種子

  delay(50);
  pianoMode = isPressed(0);               // 開機時按住按鈕 1 → 電子琴
  if (pianoMode) {
    Serial.println("piano mode");
    for (int i = 0; i < 3; i++) {         // 三顆燈依序閃一下表示進入電子琴
      digitalWrite(ledPins[i], HIGH);
      beep(notes[i], 150);
      digitalWrite(ledPins[i], LOW);
    }
    waitAllReleased();
  } else {
    Serial.println("reaction game: press the button that lights up");
    beep(880, 200);
  }
}

// ===== 電子琴模式 =====
void pianoLoop() {
  bool anyPressed = false;
  for (int i = 0; i < 3; i++) {
    if (isPressed(i)) {
      tone(buzzerPin, notes[i]);          // 按著就一直響
      digitalWrite(ledPins[i], HIGH);
      anyPressed = true;
    } else {
      digitalWrite(ledPins[i], LOW);
    }
  }
  if (!anyPressed) noTone(buzzerPin);     // 全放開就安靜
  delay(10);
}

// ===== 反應遊戲模式 =====
void playOneRound(int roundNumber, unsigned long &bestTime) {
  allLedsOff();
  waitAllReleased();

  // 隨機等 1–4 秒,期間偷按就算犯規
  unsigned long waitMs = random(1000, 4000);
  unsigned long waitStart = millis();
  while (millis() - waitStart < waitMs) {
    if (isPressed(0) || isPressed(1) || isPressed(2)) {
      Serial.println("too early!");
      beep(150, 400);                     // 低沉的犯規聲
      waitAllReleased();
      waitStart = millis();               // 重新等
    }
  }

  // 隨機亮一顆燈並嗶一聲,同時開始計時
  int target = random(0, 3);
  digitalWrite(ledPins[target], HIGH);
  tone(buzzerPin, 880, 80);
  unsigned long startTime = millis();

  // 等玩家按(最多等 3 秒)
  int pressed = -1;
  while (millis() - startTime < 3000) {
    for (int i = 0; i < 3; i++) {
      if (isPressed(i)) { pressed = i; break; }
    }
    if (pressed >= 0) break;
  }
  unsigned long reaction = millis() - startTime;
  digitalWrite(ledPins[target], LOW);

  Serial.print("round ");
  Serial.print(roundNumber);
  Serial.print(": ");
  if (pressed < 0) {
    Serial.println("timeout");
    beep(150, 400);
  } else if (pressed != target) {
    Serial.println("wrong button");
    beep(150, 400);
  } else {
    Serial.print(reaction);
    Serial.println(" ms");
    beep(1200, 100);
    if (reaction < bestTime) bestTime = reaction;   // 更新最佳成績
  }
  waitAllReleased();
  delay(500);
}

void gameLoop() {
  unsigned long bestTime = 99999;
  for (int r = 1; r <= ROUNDS; r++) {
    playOneRound(r, bestTime);
  }
  Serial.print("best: ");
  Serial.print(bestTime);
  Serial.println(" ms");
  // 結束動畫:三顆燈一起閃三下
  for (int k = 0; k < 3; k++) {
    for (int i = 0; i < 3; i++) digitalWrite(ledPins[i], HIGH);
    beep(notes[k], 150);
    allLedsOff();
    delay(150);
  }
  delay(2000);                            // 兩秒後自動開始下一局
}

void loop() {
  if (pianoMode) {
    pianoLoop();
  } else {
    gameLoop();
  }
}

步驟

  1. 接好線,先上傳程式,直接開機(不按按鈕)。
  2. 打開序列埠監控視窗(9600),等燈亮就按對應按鈕,看印出來的毫秒數。玩完五回合會印「best」。
  3. 按一下 UNO 的 RESET 鍵,同時按住按鈕 1 不放,三顆燈依序閃並發出 Do Mi Sol,就進入電子琴模式。

你應該看到

反應遊戲:等 1–4 秒後隨機一顆燈亮、嗶一聲,按對會印出像「round 1: 243 ms」的反應時間,按錯或超過 3 秒會低鳴一聲。人類的反應時間大約 200–300 毫秒;偷按會被抓到「too early!」。電子琴:按哪顆按鈕就亮哪顆燈、響哪個音,可以彈出簡單的旋律。

測試方法(邏輯分析儀 + 示波器)

邏輯分析儀:CH0 → D9(紅 LED)、CH1 → D10、CH2 → D11、CH3 → D2(按鈕 1)、CH4 → D3、CH5 → D4、GND → UNO GND。PulseView 取樣率 100 kHz、取樣 10 秒,按「執行」後開始玩一回合。

CH0 紅 LED ───────┐       ┌─────────────────────────────────┐
                  └───────┘                                 └────
CH3 按鈕 1 ───────────────────────────────┐ ┌┐┌───────┐
                                          └─┘└┘        └─────────
                  ◄───────────────────────►
                     燈亮到按下 = 反應時間(用游標量)

在 PulseView 用兩個游標夾住「LED 由低變高」和「按鈕由高變低的第一個下降緣」,讀出時間差,跟序列埠印的反應時間比對。順便放大看按鈕那一段,你會看到第 11 章講的彈跳:按下的瞬間有好幾個很短的上下跳動。

示波器:探棒鉤 D8,鱷魚夾接 GND,1 V/div、1 ms/div,進入電子琴模式按住按鈕 1,量頻率。

項目程式設定/印出儀器量到差多少
反應時間(毫秒)序列埠印的邏輯分析儀游標
按鈕彈跳持續時間(無)
按鈕 1 的音高(Hz)262示波器頻率
按鈕 3 的音高(Hz)392

程式算的反應時間和邏輯分析儀量的應該只差幾毫秒。差的來源是 loop() 裡檢查按鈕的那個 for 迴圈需要一點點時間,以及彈跳的第一下和程式認定的那一下可能不是同一下。

延伸挑戰

  • 加入 OLED(第 15 章的接法,UNO 的 SDA=A4、SCL=A5)顯示每回合的反應時間和最佳成績。
  • 做成「記憶遊戲」:機器依序亮 3 顆燈,玩家要照順序按;每成功一次就多加一顆。
  • 雙人對戰:按鈕 1 和按鈕 3 各屬於一個玩家,中間的綠燈亮時比誰先按。
  • 電子琴加入「和弦」:同時按兩顆按鈕時,用更高頻率的 tone() 表示(蜂鳴器一次只能發一個音,想想怎麼取捨)。

收尾:專題報告與上台展示

作品會動只是一半,另一半是讓別人在三分鐘內看懂你做了什麼、為什麼成功。

專題報告格式(兩到四頁)

 1. 題目與一句話說明      例:「智慧夜燈:天暗自動漸亮的 LED 燈」
 2. 問題                  誰、在什麼情況、需要什麼
 3. 規劃                  輸入 → 處理 → 輸出 表格 + 材料清單
 4. 接線圖                ASCII 或手繪,標清楚每個腳位
 5. 程式說明              不要貼全部程式,只貼最關鍵的 5–10 行並解釋
 6. 測試與量測數據        ★至少一張示波器或邏輯分析儀的畫面(拍照)
                          ★至少一張填好的量測表格
                          ★程式設定值 vs 儀器量測值的比較
 7. 遇到的問題與解法      列 2–3 個真的卡住過的地方
 8. 延伸與反思            如果有更多時間會改什麼

第 6 點是整份報告的核心,也是本章每個專題都附「測試方法」的原因。「我的夜燈 PWM 頻率是 490 Hz,示波器量到 489.6 Hz」這一句,比「夜燈運作正常」有說服力一百倍。

第 7 點很多人會跳過,覺得寫出問題很丟臉。其實評審最想看的就是這段,因為它證明你真的動手做過,而不是抄來的。

上台展示要點(三分鐘)

  1. 第一句話講問題,不要講技術:「晚上起床找燈的開關很麻煩,所以我做了……」比「我用 Arduino UNO 的 PWM……」好得多。
  2. 現場操作一定要成功:上台前一小時再完整跑一次;帶備用電池、備用 USB 線;手機先連好 Wi-Fi 並把網頁開在畫面上。ESP32 的專題要事先確認場地的 Wi-Fi 是 2.4 GHz,不確定就帶自己的手機熱點。
  3. 用一張波形圖證明:把示波器畫面拍下來放在投影片或海報上,指著它說「這裡可以看到占空比從 0 變到 100%」。
  4. 講一個卡住的故事:「一開始馬達關掉時 MOSFET 會發燙,後來加了二極體就好了。」這種故事比任何技術細節都讓人記得住。
  5. 準備被問的三個問題:「為什麼選這個元件?」「如果要用電池可以撐多久?」「下一步想加什麼?」照本章的內容你都答得出來。
  6. 時間控制:問題 30 秒、作品示範 90 秒、量測證據 30 秒、問題與延伸 30 秒。練習時用手機計時。

用儀器看看

本章的儀器操作已經分散在五個專題的「測試方法」裡。這裡整理成一張表,方便你規劃測試,也方便你在報告裡寫清楚設定:

專題儀器接哪裡設定要量的東西預期值
一 智慧夜燈示波器CH1→UNO D92 V/div、500 µs/div、上升緣 2.5V占空比、頻率占空比隨光線 0–100%,約 490 Hz
二 氣象站邏輯分析儀CH0→GPIO 21、CH1→GPIO 222 MHz、I2C 解碼器位址、封包間隔、SCL 頻率0x3C、2 秒、約 100 kHz
三 風扇示波器CH1→閘極、CH2→汲極2 V/div、200 µs/div、上升緣 1.5V三段占空比、反相、頻率43%/71%/100%,1 kHz
四 迷你示波器示波器CH1→分壓點1 V/div、1 ms/div、上升緣 1.2V頻率、Vpp,與 ESP32 比對440 Hz、約 2.5V
五 反應遊戲邏輯分析儀+示波器LA:LED 與按鈕腳;示波器→D8100 kHz、10 秒;1 V/div、1 ms/div反應時間、彈跳、音高與序列埠相符;262/330/392 Hz

把示波器畫面變成報告裡的證據

示波器通常有「儲存畫面」的功能(存到 USB 隨身碟),沒有的話用手機拍也可以。拍的時候請確認畫面上看得到:V/div、s/div、觸發設定、以及自動量測的數字。報告裡每一張波形圖旁邊都要寫一句「這張圖證明了什麼」,例如:

圖 3:風扇中速時閘極波形。占空比 70.2%、頻率 1.00 kHz,與程式設定的 180/255 = 70.6% 一致。

雙通道的共地提醒

專題三和專題四都用到兩塊板子或兩個通道。兩支探棒的鱷魚夾都要夾 GND,而且兩塊板子的 GND 要用杜邦線接在一起。鱷魚夾夾錯地方(例如夾到電池正極)會造成短路,這是本書從第 6 章一直強調的規矩。

常見錯誤與除錯

  • 夜燈 LED 一直全亮或一直全暗,不會變 → darkValue、brightValue 沒有依教室光線調整 → 看序列繪圖器的 light 值,重新填這兩個數字。
  • 夜燈 LED 突然跳亮,不是漸亮 → fadeStepDelay 太小,或程式直接 analogWrite(target) 沒有走一步一步 → 確認 currentBrightness 每圈只加減 1。
  • 氣象站長條圖一直只有一條 → HISTORY_INTERVAL 是 60 秒,要等很久 → 展示時改成 5000。
  • 氣象站最低溫顯示 100 → 開機後 DHT11 第一次讀取失敗,tempMin 沒更新 → 等 2 秒後自然會更新;或在 setup() 裡多等 1.5 秒再讀。
  • 風扇按「低」不轉,按「中」才轉 → 小馬達啟動需要較高電壓 → 把 levelDuty[1] 從 110 調到 130 或 150。
  • 風扇一開就 ESP32 重開機 → 馬達電流從 ESP32 供電 → 馬達一定要用獨立電池盒,只有 GND 跟 ESP32 共接。
  • 編譯錯誤 ledcAttach was not declared → esp32 核心版本是 2.x → 改用程式註解裡的 ledcSetup、ledcAttachPin 三行寫法。
  • MOSFET 發燙 → G、D、S 接反,或閘極沒接 10kΩ 下拉讓它半開半關 → 對照腳位圖重接,確認 10kΩ 在閘極和 GND 之間。
  • 迷你示波器波形亂跳、全部貼在最高或最低 → 沒共地,或分壓器接錯讓 GPIO 34 吃到 5V → 先拔掉訊號,用三用電表確認分壓點是 2.5V 左右,確認 UNO GND 接到 ESP32 GND。
  • 迷你示波器頻率算出 0 → 訊號太小或沒接,crossings 不到 2 → 檢查 UNO 有沒有在 tone();把 margin 從 100 改小一點試試。
  • 序列繪圖器波形只看到一小段 → 繪圖器一次顯示的點數有限 → 把 SAMPLES 改成 100,或在繪圖器設定裡調大顯示點數。
  • 反應遊戲一開機就說 too early → 按鈕接錯成「沒按是 LOW」,或 pinMode 忘了 INPUT_PULLUP → 用三用電表量 D2 沒按時應該是 5V。
  • 反應遊戲每次亮的燈都一樣 → randomSeed(analogRead(A0)) 的 A0 接了東西,雜訊不夠 → 確認 A0 空接;或改用 randomSeed(micros()) 在第一次按鈕後呼叫。
  • 電子琴按兩顆按鈕只響一個音 → 蜂鳴器用 tone() 一次只能一個頻率 → 這是正常的,看延伸挑戰。
  • 邏輯分析儀量的反應時間和序列埠差很多(超過 20 ms) → 游標夾的是彈跳的最後一下,不是第一下 → 放大看按鈕訊號,把游標移到第一個下降緣。

想一想

  1. 專題一的夜燈從全暗到全亮花多少時間?如果想改成 1 秒,要改哪個數字、改成多少?
參考答案

255 步 × 10 毫秒 = 2550 毫秒 ≈ 2.5 秒。想改成 1 秒,把 fadeStepDelay 改成 4(255 × 4 = 1020 毫秒)。

  1. 專題三的風扇,如果把 PWM_FREQ 從 1000 改成 100,示波器上會看到什麼不同?馬達會有什麼變化?
參考答案

示波器上方波的週期從 1 ms 變成 10 ms(要把時間調到 2 ms/div 才看得到幾個週期)。占空比不變,所以平均轉速差不多,但 100 Hz 在人耳聽得到的範圍,馬達會發出明顯的嗡嗡聲,而且低速時可能一頓一頓的。

  1. 專題四的迷你示波器,取樣間隔是 40 µs。它最高大概能可靠地看到幾 Hz 的方波?請用「一個週期至少 10 個點」的法則算。
參考答案

10 個點 × 40 µs = 400 µs 是最短的可靠週期,頻率 = 1 ÷ 0.0004 = 2500 Hz。超過這個頻率,波形會變形,再高就會出現混疊的假波形。

  1. 專題五用邏輯分析儀量到的反應時間比序列埠印的少了 3 毫秒。可能的原因是什麼?這算是程式有錯嗎?
參考答案

程式用 millis() 計時,而 millis() 只有 1 毫秒的解析度;再加上 loop() 裡用 for 迴圈輪流檢查三顆按鈕,從按下到程式「發現」會慢一點點;彈跳也可能讓儀器和程式認定的「按下瞬間」不同。差 3 毫秒對反應遊戲來說完全可以接受,不算錯,但在報告裡要誠實寫出來並解釋原因。

  1. 你想把專題二的氣象站改成放在陽台用電池跑一個月。列出至少三件需要改動的事。
參考答案

(任三個)用第 16 章的深度睡眠,每 5–10 分鐘醒來一次而不是一直開著 Wi-Fi;OLED 只在醒來那幾秒顯示,或拿掉 OLED;資料不能只存在 ESP32 的記憶體裡(睡覺會不見),要用 RTC_DATA_ATTR 或送到網路上(例如 MQTT);網頁伺服器在睡覺時無法回應,要改成 ESP32 主動把資料送出去;做防水外殼;用 3 顆 3 號電池接 VIN(4.5V 對 DevKit V1 的穩壓器來說有點低,可能要 4 顆)。

  1. 開放挑戰:從五個專題裡挑兩個,把它們合併成一個新作品,寫下那句「誰、在什麼情況、需要什麼」的問題描述,和「輸入 → 處理 → 輸出」表格。
參考答案

範例:合併專題二和專題三:「夏天午睡的人,需要一台房間太熱時會自己開、涼了會自己關的風扇。」輸入:DHT11 溫度;處理:高於 28°C 開中速、高於 30°C 開高速、低於 26°C 關閉,並在網頁上顯示目前溫度與段速、允許手動覆蓋;輸出:IRLZ44N 驅動馬達、OLED 顯示狀態。另一個例子是合併一和五:天黑後用按鈕反應遊戲當「晚安儀式」,玩完燈才慢慢暗下來。答案不唯一,重點是問題描述要具體,表格的每一格都要是你接過的元件。

本章小結

  • 專題六步驟:問題 → 規劃 → 接線 → 程式 → 測試 → 展示;測試不過就回頭改,這是正常流程不是失敗。
  • 規劃時把題目拆成「輸入 → 處理 → 輸出」三格,每一格都填上你在前面章節接過的元件。
  • 接線先接電源再接輸入最後接輸出,每接一段就用三用電表量一次;程式先寫最小可動版本,每加一段就上傳一次。
  • 專題程式的骨架:常數放最上面、小函式各做一件事、loop() 用 millis() 排程不用長 delay()。
  • 五個專題各自用儀器驗證了一件事:PWM 占空比隨光線變化(示波器)、I2C 位址 0x3C 與封包間隔(邏輯分析儀)、三段占空比與汲極反相(雙通道示波器)、迷你示波器 vs 真示波器的頻率與 Vpp(示波器比對)、反應時間與按鈕彈跳(邏輯分析儀)。
  • 取樣率決定你看得到多快的訊號:一個週期至少 10 個點,太慢會混疊出假波形。
  • 馬達一定要獨立供電、加飛輪二極體、閘極加下拉電阻;ESP32 的 GPIO 34 吃 5V 訊號前一定要分壓。
  • 報告的核心是「程式設定值 vs 儀器量測值」的比較;上台第一句講問題不講技術,現場示範上台前一小時再跑一次。

名詞表

中文英文一句話解釋
專題Project把多個元件和程式組合起來解決一個具體問題的作品。
最小可動版本Minimum working version功能最少但已經能跑的第一版程式,之後再一段一段加。
輸入/處理/輸出Input / Process / Output規劃專題時把題目拆成感測、判斷、動作三格的方法。
占空比Duty cyclePWM 方波裡 HIGH 所占的時間比例,決定 LED 亮度或馬達轉速。
閘極下拉電阻Gate pull-down resistor接在 MOSFET 閘極與 GND 之間的電阻,確保沒訊號時 MOSFET 關閉。
飛輪二極體Flyback diode跨接在馬達兩端的二極體,吸收關掉時的反電動勢尖波。
共地Common ground兩塊板子或儀器的 GND 接在一起,讓它們有相同的 0V 基準。
取樣率Sampling rate每秒取幾個點,決定能看到多快的訊號。
取樣間隔Sampling interval兩個取樣點之間的時間,是取樣率的倒數。
混疊Aliasing取樣太慢時看到的假波形。
觸發Trigger示波器或程式從波形固定的位置(例如上升緣)開始畫,讓畫面不亂跳。
歷史紀錄History buffer用陣列存最近 N 筆資料,滿了就擠掉最舊的。
亂數種子Random seed讓 random() 每次開機產生不同序列的起始值。
反應時間Reaction time從刺激出現到做出動作的時間,人類大約 200–300 毫秒。
量測證據Measurement evidence報告裡用儀器數據證明作品照設計運作的部分。

附錄 A 器材清單與採購建議

這一份清單把全書用到的東西整理成三張表:必備(沒有就做不了大部分實驗)、進階(第二部以後的章節才會用到)、儀器(示波器、邏輯分析儀這類可以好幾組共用的設備)。

幾個使用上的約定:

  • 「建議數量」是以 1 組學生 2 人 來算,而且已經多算了一點點備品,因為 LED 燒掉、杜邦線斷掉是很正常的事。
  • 「用在哪幾章」只列主要的章節。像麵包板、杜邦線、電阻這種東西其實每一章都會用到。
  • 「採購提示」寫的是台灣電子材料行(例如台北光華商場周邊、各縣市的電子材料行)或網購平台(蝦皮、露天、PChome)上常見的商品名稱,你照著打進搜尋框通常就找得到。
  • 全書只用 12V 以下的直流電,所以這份清單裡沒有任何需要插家用插座的東西(示波器和電腦本身除外)。

A.1 必備器材

品項規格/型號建議數量用在哪幾章採購提示
麵包板(Breadboard)830 孔(俗稱 MB-102)或 400 孔半尺寸1 片(830 孔)全書搜「麵包板 830 孔」。買白色底、有紅藍電源軌的。太便宜的孔會鬆,杜邦線插了會掉。
杜邦線 公對公(Male–Male)20 cm,40 條一排1 排(40 條)全書搜「杜邦線 公公 20cm 40P」。彩色排線可以一條一條撕開。
杜邦線 公對母(Male–Female)20 cm,40 條一排1 排(40 條)第 13–17 章(接模組)搜「杜邦線 公母 20cm 40P」。DHT11、OLED、伺服馬達都要靠它接到麵包板。
數位三用電表(Digital Multimeter)可量直流電壓、直流電流(mA 檔)、電阻、有蜂鳴通斷檔1 台全書搜「數位三用電表」或「數位電錶」。入門款就夠,但一定要有 mA 電流檔 和 通斷蜂鳴。
電阻包1/4 W、±5% 碳膜,10 Ω–1 MΩ 常用值,至少包含 220 Ω、330 Ω、1 kΩ、4.7 kΩ、10 kΩ、100 kΩ1 包(每種值 10–20 顆)全書搜「電阻包 1/4W 常用值」。買有分格標示的包裝,省掉每次讀色碼的時間(但第 2 章還是要學會讀)。
陶瓷電容(Ceramic Capacitor)100 nF(標示 104)10 顆第 5、10、11、13 章搜「陶瓷電容 104」或「0.1uF 電容」。沒有極性,怎麼插都可以。
電解電容(Electrolytic Capacitor)10 µF、100 µF、470 µF、1000 µF,耐壓 16 V 或 25 V每種 4 顆第 5、7、10、16 章搜「電解電容 100uF 25V」。有極性,長腳是正極、側面有白色條紋的那腳是負極。耐壓買 16 V 以上。
LED(Light-Emitting Diode)5 mm,紅、綠、藍、白每色 10 顆第 1–5、8、11–14、16、17 章搜「5mm LED 紅」。買「散光/霧面」的看得比較清楚。一包 100 顆很便宜,多買。
整流二極體(Rectifier Diode)1N400710 顆第 7、8、9、14、17 章搜「1N4007」。黑色身體、一端有銀色環(陰極)。給馬達、繼電器當飛輪二極體。
小訊號二極體(Signal Diode)1N414810 顆第 8、15 章搜「1N4148」。橘紅色玻璃身體、一端黑環。
按鈕開關(Tactile Switch)6×6 mm 四腳按鈕6 顆第 11、12、17 章搜「輕觸開關 6x6」。四腳的可以直接插麵包板跨中央溝。
可變電阻(Potentiometer)10 kΩ,直插式或附旋鈕2 顆第 3、13、14 章搜「可變電阻 10K 直插」或「電位器 B10K」。買腳距能插麵包板的(有些要另外焊線)。
9 V 電池與電池扣9 V 方型電池(碳鋅或鹼性)+ 電池扣(附導線)電池 2 顆、電池扣 2 個第 1–5 章搜「9V 電池扣 帶線」。注意 9 V 電池扣接到麵包板時正負極不要互碰(會短路發熱)。
3 號電池盒4 顆裝(6 V)與 2 顆裝(3 V),附導線各 1 個,電池 6 顆第 1、4、7、9、14 章搜「3號電池盒 4節 帶線」。驅動馬達時用 4 顆裝比 9 V 電池更耐用。
Arduino UNOUNO R3(原廠或相容板)1 片(含 USB-B 方頭線)第 5、6、8–15、17 章搜「Arduino UNO R3」。相容板用 CH340 晶片,Windows 可能要另外裝驅動程式(第 12 章有說明)。確認有附 USB 線。
電腦能裝 Arduino IDE、PulseView,有 USB 孔1 台第 12 章以後學校電腦教室或筆電都可以。只有 USB-C 孔的筆電要準備轉接頭。

A.2 進階器材

品項規格/型號建議數量用在哪幾章採購提示
電感(Inductor)100 µH、1 mH,直插色環式或工字型每種 2 顆第 7、10 章搜「色環電感 100uH」「工字電感 1mH」。長得像胖一點的電阻,沒有極性。
漆包線+鐵釘漆包線 0.3–0.5 mm 線徑,約 5 公尺;大鐵釘或螺絲 1 支1 份第 7 章搜「漆包線 0.4mm」。五金行買 10 公分長鐵釘。用來自己繞電磁鐵和發電線圈。
磁鐵小塊釹磁鐵或強力磁鐵2 顆第 7 章搜「釹磁鐵 10mm」。拿來在線圈旁邊晃,讓三用電表看到 mV 的感應電壓。冰箱磁鐵效果弱很多。
NPN 電晶體(Transistor)2N2222(或 PN2222、P2N2222A,TO-92 包裝)5 顆第 9、14、17 章搜「2N2222 TO-92」。腳位 E-B-C 見附錄 C。
N 通道 MOSFETIRLZ44N(TO-220 包裝,邏輯準位可驅動)2 顆第 9、14、17 章搜「IRLZ44N」。注意是 IRLZ,不是 IRFZ。IRFZ 用 5 V 推不飽和,ESP32 的 3.3 V 更推不動。
光敏電阻(LDR)5 mm 或 5537 型3 顆第 13、17 章搜「光敏電阻 5537」。兩腳沒有極性。
DHT11 溫濕度感測器3 腳模組版(已含上拉電阻)或 4 腳裸件1 顆第 13、16、17 章搜「DHT11 模組」。模組版接線最簡單;裸件要自己加 4.7 kΩ–10 kΩ 上拉電阻(附錄 C)。
無源蜂鳴器(Passive Buzzer)5 V,直插式2 顆第 9、10、17 章搜「無源蜂鳴器」。一定要無源(Passive),有源的(Active)只會叫一個音,做不了電子琴。
小直流馬達(DC Motor)3–6 V 玩具馬達(130 型)2 顆第 7、9、14、17 章搜「130 馬達 3V-6V」。可以多買幾顆小風扇葉片套在軸上,專題用。
SG90 伺服馬達(Servo)9 g 微型伺服,180°1 顆第 14、17 章搜「SG90 伺服馬達」。附三種塑膠搖臂。棕 GND/紅 5 V/橘訊號。
5 V 繼電器模組(Relay Module)單路、5 V、附光耦與指示燈1 片第 7、9 章搜「5V 繼電器模組 1路」。買模組版就不用自己接飛輪二極體。只拿它切換 12 V 以下的東西。
ESP32 DevKit V130 腳版,CP2102 或 CH340 晶片1 片(含 Micro-USB 線)第 13、14、16、17 章搜「ESP32 DevKit V1 30pin」。30 腳的剛好能插麵包板兩側各留一排孔;38 腳版太寬,插了就沒地方接線。
0.96 吋 OLED 顯示器SSD1306、128×64、I2C、4 腳1 片第 15、16、17 章搜「0.96吋 OLED I2C 4針 SSD1306」。買 4 腳 I2C 的,不要買 7 腳 SPI 的。

A.3 儀器

品項規格/型號建議數量用在哪幾章採購提示
示波器(Oscilloscope)數位、雙通道、頻寬 50–100 MHz,附 2 支 1×/10× 探棒每 2–3 組共用 1 台第 5–15 章搜「數位示波器 雙通道」。常見入門機型如 Rigol DS1054Z、Siglent SDS1104X-E、Hantek DSO2C10 系列。二手教學機也可以,功能都夠用。買的時候確認有附探棒。
USB 邏輯分析儀(Logic Analyzer)8 通道、24 MHz,可用 PulseView(sigrok)或 Saleae Logic 軟體每組 1 支(很便宜)第 11、15、16 章搜「USB 邏輯分析儀 24M 8CH」。通常附一排 10 條公母杜邦線。Windows 要用 Zadig 裝驅動(附錄 D)。
示波器備用探棒1×/10× 可切換,100 MHz每台示波器多 1 支第 6 章起搜「示波器探棒 100MHz」。探棒的鱷魚夾很容易弄丟,買備用。
三用電表備用測試線香蕉頭對探針每 3 組 1 副全書搜「三用電表 測試線」。學生用力扯會斷,備一副。

A.4 在家自學的採購建議

  1. 先買必備表,再買進階表。 第 1–4 章只要必備表就能做,趁這幾週再買進階器材。
  2. 電阻、LED、杜邦線用分格收納盒裝,每格貼上數值標籤。 找零件的時間會少很多,也會順便記住色碼。
  3. ESP32 的 USB 線要特別檢查。 很多便宜的 Micro-USB 線只有充電功能、沒有資料線,插上電腦完全找不到裝置。買的時候搜「Micro USB 傳輸線」而不是「充電線」。
  4. 準備一本實驗筆記本。 每章的「觀察與記錄」表格抄進去或印出來貼上,做完全書就是一本自己的實驗紀錄。
  5. 零件多買一倍。 LED、電阻、電晶體一定會燒掉幾顆,這是正常的學習成本,手邊有備品才不會卡住。

附錄 B 公式與單位速查

這一頁把全書用到的公式集中在一起。每一條都有「公式長什麼樣」「每個符號是什麼、單位是什麼」和「一個算例」。忘記公式的時候翻這裡,但如果連公式在講什麼都忘了,請回去看對應的章節,那裡有比喻和實驗。

算之前先做一件事:把所有數字換成基本單位(V、A、Ω、F、H、秒),算完再換回好讀的單位(mA、kΩ、µF、ms)。附錄最後的 B.4 教你怎麼換。


B.1 直流電路基本公式

公式符號意義與單位算例
歐姆定律(Ohm’s Law)
V = I × R
V:電壓,伏特(V)
I:電流,安培(A)
R:電阻,歐姆(Ω)
20 mA 的電流流過 220 Ω 電阻,電阻兩端的電壓是多少?
I = 20 mA = 0.02 A
V = 0.02 × 220 = 4.4 V
歐姆定律:求電流
I = V ÷ R
同上9 V 電池接 1 kΩ 電阻,電流多少?
I = 9 ÷ 1000 = 0.009 A = 9 mA
歐姆定律:求電阻
R = V ÷ I
同上某個東西接 5 V 時流 50 mA,它的電阻多少?
R = 5 ÷ 0.05 = 100 Ω
功率(Power)
P = V × I
P:功率,瓦特(W)
V:伏特(V)
I:安培(A)
LED 兩端 2 V、流 20 mA。
P = 2 × 0.02 = 0.04 W = 40 mW
功率:只知道電壓和電阻
P = V² ÷ R
同上,V² 就是 V × V9 V 直接接 100 Ω 電阻。
P = 9 × 9 ÷ 100 = 0.81 W → 超過 1/4 W 電阻的 0.25 W,會燙到冒煙(第 4 章)。
功率:只知道電流和電阻
P = I² × R
同上100 mA 流過 10 Ω。
P = 0.1 × 0.1 × 10 = 0.1 W,1/4 W 電阻還撐得住。
串聯總電阻(Series)
R總 = R1 + R2
R1、R2:兩顆電阻,Ω220 Ω 串 1 kΩ:
R總 = 220 + 1000 = 1220 Ω
並聯總電阻(Parallel,兩顆)
R總 = (R1 × R2) ÷ (R1 + R2)
同上。結果一定比較小的那顆還小。1 kΩ 並 1 kΩ:
R總 = (1000 × 1000) ÷ (1000 + 1000) = 1,000,000 ÷ 2000 = 500 Ω
(兩顆一樣的並聯 = 一半)
分壓器(Voltage Divider)
Vout = Vin × R2 ÷ (R1 + R2)
Vin:輸入電壓(V)
R1:接在 Vin 和輸出點之間
R2:接在輸出點和 GND 之間
Vout:輸出點對 GND 的電壓
5 V 經 10 kΩ(R1)和 4.7 kΩ(R2):
Vout = 5 × 4700 ÷ (10000 + 4700) = 5 × 0.32 = 1.6 V
串聯電流處處相同、並聯電壓處處相同(這不是公式,是規則)兩顆 LED 並聯接同一顆電池,兩顆 LED 的電壓一樣,但每顆各自拿自己的電流。

分壓器接法對照:

 Vin ──[ R1 ]──┬──[ R2 ]── GND
               │
              Vout

B.2 元件與電源相關公式

公式符號意義與單位算例
LED 限流電阻(Current-Limiting Resistor)
R = (Vs − Vf) ÷ I
Vs:電源電壓(V)
Vf:LED 順向電壓(V),見附錄 C
I:想要的電流(A),一般取 10–20 mA
算出來後往上挑最接近的電阻值
Arduino 5 V 接紅光 LED(Vf ≈ 2 V),想要 15 mA:
R = (5 − 2) ÷ 0.015 = 200 Ω → 挑 220 Ω

ESP32 3.3 V 接藍光 LED(Vf ≈ 3 V),想要 5 mA:
R = (3.3 − 3) ÷ 0.005 = 60 Ω → 挑 68 Ω 或 100 Ω
RC 時間常數(Time Constant)
τ = R × C
τ(讀作「tau」):秒(s)
R:Ω
C:法拉(F)
經過 1 個 τ 充到 63%,5 個 τ 當作充飽(或放完)
10 kΩ 配 100 µF:
τ = 10,000 × 0.0001 = 1 秒,5 秒充飽。

1 kΩ 配 100 nF:
τ = 1000 × 0.0000001 = 0.0001 s = 0.1 ms
電池續航估算
時間(小時)= 容量(mAh)÷ 電流(mA)
mAh:毫安培小時,電池上會寫
mA:電路平均吃的電流
這是理想值,實際大約打 7 折
9 V 鹼性電池約 500 mAh,點一顆 15 mA 的 LED:
500 ÷ 15 ≈ 33 小時,實際約 23 小時。

3 號鹼性電池約 2000 mAh,ESP32 連 Wi-Fi 平均吃 120 mA:
2000 ÷ 120 ≈ 16.7 小時
電晶體基極電阻(簡化版,第 9 章)
RB = (V控制 − 0.7) ÷ IB
IB = I負載 ÷ 10(保險起見用 β = 10)
V控制:Arduino 腳位電壓 5 V
0.7 V:基極–射極壓降
IB:基極電流(A)
I負載:要開關的電流(A)
要開關一顆 100 mA 的馬達:
IB = 0.1 ÷ 10 = 0.01 A
RB = (5 − 0.7) ÷ 0.01 = 430 Ω → 挑 330 Ω 或 470 Ω
電池串聯與並聯串聯:電壓相加、容量不變
並聯:電壓不變、容量相加
4 顆 1.5 V 3 號電池串聯 = 6 V,容量還是 2000 mAh。

B.3 訊號相關公式

公式符號意義與單位算例
頻率與週期(Frequency / Period)
f = 1 ÷ T  T = 1 ÷ f
f:頻率,赫茲(Hz)=每秒幾次
T:週期,秒(s)=一次要多久
示波器量到一個波的週期是 2 ms:
f = 1 ÷ 0.002 = 500 Hz

tone() 發 1 kHz:
T = 1 ÷ 1000 = 0.001 s = 1 ms
占空比(Duty Cycle)
D = t高 ÷ T × 100%
t高:一個週期裡 HIGH 的時間
T:整個週期
D:百分比
週期 2 ms,HIGH 占 0.5 ms:
D = 0.5 ÷ 2 × 100% = 25%
PWM 的平均電壓
V平均 = Vcc × D
Vcc:HIGH 時的電壓(UNO 5 V、ESP32 3.3 V)
D:占空比(用小數)
analogWrite(ledPin, 64):D = 64 ÷ 255 ≈ 0.25
V平均 = 5 × 0.25 ≈ 1.25 V(用 RC 低通濾波後可以用三用電表量到,第 10 章)
analogWrite 數值 ↔ 占空比(UNO 8 位元)
D = 數值 ÷ 255
數值:0–255數值 128 → 128 ÷ 255 ≈ 50%
數值 255 → 100%(等於 digitalWrite HIGH)
ADC 換算:Arduino UNO(10 位元)
V = 讀值 × 5 ÷ 1023
讀值:analogRead() 回傳 0–1023
5:參考電壓 5 V
讀值 512:
V = 512 × 5 ÷ 1023 ≈ 2.5 V
ADC 換算:ESP32(12 位元)
V = 讀值 × 3.3 ÷ 4095
讀值:analogRead() 回傳 0–4095
3.3:參考電壓 3.3 V
(ESP32 的 ADC 兩端不太線性,低於 0.1 V 和高於 3.1 V 會不準)
讀值 2048:
V = 2048 × 3.3 ÷ 4095 ≈ 1.65 V
ADC 每一格代表多少電壓(解析度)UNO:5 ÷ 1023 ≈ 4.9 mV/格
ESP32:3.3 ÷ 4095 ≈ 0.8 mV/格
光敏分壓讀值從 600 變成 620,差 20 格,約 20 × 4.9 mV ≈ 0.1 V
UART 一個位元多久
t位元 = 1 ÷ 鮑率
鮑率(baud):每秒幾個位元9600 baud:t = 1 ÷ 9600 ≈ 0.000104 s ≈ 104 µs
一個字元(1 起始 + 8 資料 + 1 停止 = 10 位元)≈ 1.04 ms

B.4 單位前綴與換算

前綴表

前綴符號意思等於常見例子
皮(pico)p一兆分之一0.000 000 000 001(÷1,000,000,000,000)22 pF 電容(本書不常用)
奈(nano)n十億分之一0.000 000 001(÷1,000,000,000)100 nF 電容
微(micro)µ百萬分之一0.000 001(÷1,000,000)100 µF 電容、100 µH 電感、104 µs
毫(milli)m千分之一0.001(÷1,000)20 mA、1 ms、2000 mAh
(無)115 V、220 Ω、1 s
千(kilo)k一千倍1,000(×1,000)10 kΩ、1 kHz
百萬(mega)M一百萬倍1,000,000(×1,000,000)1 MΩ、24 MHz(邏輯分析儀取樣率)

記法:每往上一格是 ×1000,往下一格是 ÷1000。

  p  ──×1000──►  n  ──×1000──►  µ  ──×1000──►  m  ──×1000──►  (無)  ──×1000──►  k  ──×1000──►  M
  ◄──÷1000──      ◄──÷1000──      ◄──÷1000──      ◄──÷1000──         ◄──÷1000──      ◄──÷1000──

換算例子

題目怎麼想答案
4.7 kΩ 是幾 Ω?k 是 ×10004.7 × 1000 = 4700 Ω
1 MΩ 是幾 kΩ?M 到 k 差一格,×10001000 kΩ
20 mA 是幾 A?m 是 ÷100020 ÷ 1000 = 0.02 A
0.0047 A 是幾 mA?×10004.7 mA
100 nF 是幾 µF?n 到 µ 差一格,÷1000100 ÷ 1000 = 0.1 µF
1000 µF 是幾 mF?是幾 F?÷1000 一次得 mF,再 ÷1000 得 F1 mF = 0.001 F
電容上寫「104」是多少?三碼制:前兩碼 10,後一碼 4 是「加 4 個 0」,單位 pF100,000 pF = 100 nF = 0.1 µF
電容上寫「223」是多少?22 加 3 個 0,pF22,000 pF = 22 nF
500 µs 是幾 ms?÷10000.5 ms
示波器 s/div 旋到 200 µs,一格是幾秒?µ 是 ÷1,000,000200 ÷ 1,000,000 = 0.0002 s
2 ms 週期的頻率?先換成秒:0.002 s,再 1 ÷ T1 ÷ 0.002 = 500 Hz
1 mH 是幾 µH?×10001000 µH

本書用到的單位總表

量單位符號用三用電表量得到嗎
電壓伏特(Volt)V可以(直流 V 檔)
電流安培(Ampere)A可以(mA 檔,要串聯進電路)
電阻歐姆(Ohm)Ω可以(Ω 檔,元件要先拔離電路)
功率瓦特(Watt)W不行,用 V × I 算
電容法拉(Farad)F部分電表有 F 檔
電感亨利(Henry)H一般電表沒有
頻率赫茲(Hertz)Hz部分電表有 Hz 檔;示波器可以
時間秒(second)s示波器可以
電池容量毫安培小時mAh不行,看電池標示

附錄 C 色碼表、元件規格與腳位

這一頁是「拿著元件、對著看」用的。讀色碼、查 LED 要用多少電流、確認電晶體哪一腳是哪一腳,都在這裡。腳位圖全部是 ASCII 畫的,看圖的時候請注意每一張圖旁邊寫的「從哪個方向看」,看反了腳位就會左右顛倒。


C.1 電阻色碼表(Resistor Color Code)

顏色對照

顏色英文數字倍數(第 3 環/五環的第 4 環)誤差(最後一環)
黑Black0×1—
棕Brown1×10±1%
紅Red2×100±2%
橙Orange3×1,000(×1 k)—
黃Yellow4×10,000(×10 k)—
綠Green5×100,000(×100 k)±0.5%
藍Blue6×1,000,000(×1 M)±0.25%
紫Violet7×10,000,000±0.1%
灰Gray8—±0.05%
白White9——
金Gold—×0.1±5%
銀Silver—×0.01±10%

口訣:黑棕紅橙黃、綠藍紫灰白,0 到 9 剛好一輪。金銀只會出現在倍數環或誤差環。

四環電阻(本書電阻包大多是這種,誤差 ±5%,最後一環金色)

      第1環 第2環 第3環   第4環
        │    │    │       │
   ─────█────█────█───────█─────
        ↑    ↑    ↑       ↑
       數字  數字  倍數    誤差(金色)

   讀法:把「金色(或銀色)那一環」放右邊,從左邊讀起。
色環讀法阻值
紅 紅 棕 金2 2 ×10220 Ω ±5%
橙 橙 棕 金3 3 ×10330 Ω ±5%
棕 黑 紅 金1 0 ×1001 kΩ ±5%
黃 紫 紅 金4 7 ×1004.7 kΩ ±5%
棕 黑 橙 金1 0 ×100010 kΩ ±5%
棕 黑 黃 金1 0 ×10,000100 kΩ ±5%
棕 黑 綠 金1 0 ×100,0001 MΩ ±5%
棕 黑 黑 金1 0 ×110 Ω ±5%

五環電阻(誤差 ±1%,常見棕色最後一環,身體多半是藍色)

      第1環 第2環 第3環 第4環   第5環
        │    │    │    │       │
   ─────█────█────█────█───────█─────
        ↑    ↑    ↑    ↑       ↑
       數字  數字  數字  倍數    誤差(棕色 = ±1%)

   讀法:前三環是三位數字,第四環是倍數。誤差環通常離其他環遠一點。
色環讀法阻值
紅 紅 黑 黑 棕2 2 0 ×1220 Ω ±1%
棕 黑 黑 棕 棕1 0 0 ×101 kΩ ±1%
黃 紫 黑 棕 棕4 7 0 ×104.7 kΩ ±1%
棕 黑 黑 紅 棕1 0 0 ×10010 kΩ ±1%

分不清楚哪邊是頭? 用三用電表 Ω 檔量一次最快。第 2 章教過。


C.2 E12 系列標準值

電阻不是什麼值都有賣。±5% 的電阻只做這 12 個「基本數字」,然後乘 10、乘 100……。這叫 E12 系列。

 1.0   1.2   1.5   1.8   2.2   2.7   3.3   3.9   4.7   5.6   6.8   8.2

所以你會看到 220、2.2 k、22 k,但不會看到 250 Ω 或 2.5 kΩ。算出來 200 Ω,就往上挑 220 Ω;算出來 430 Ω,就挑 470 Ω。

本書電阻包常見值(10 Ω–1 MΩ)

十位百位千位(k)萬位(k)十萬位(k)百萬位(M)
10 Ω100 Ω1 kΩ10 kΩ100 kΩ1 MΩ
12 Ω120 Ω1.2 kΩ12 kΩ120 kΩ
15 Ω150 Ω1.5 kΩ15 kΩ150 kΩ
18 Ω180 Ω1.8 kΩ18 kΩ180 kΩ
22 Ω220 Ω2.2 kΩ22 kΩ220 kΩ
27 Ω270 Ω2.7 kΩ27 kΩ270 kΩ
33 Ω330 Ω3.3 kΩ33 kΩ330 kΩ
39 Ω390 Ω3.9 kΩ39 kΩ390 kΩ
47 Ω470 Ω4.7 kΩ47 kΩ470 kΩ
56 Ω560 Ω5.6 kΩ56 kΩ560 kΩ
68 Ω680 Ω6.8 kΩ68 kΩ680 kΩ
82 Ω820 Ω8.2 kΩ82 kΩ820 kΩ

粗體是全書最常用的六個值:220 Ω、330 Ω、1 kΩ、4.7 kΩ、10 kΩ、100 kΩ。


C.3 LED 順向電壓與建議電流

顏色順向電壓 Vf(典型)建議電流最大電流(5 mm 一般 LED)5 V 用的限流電阻3.3 V 用的限流電阻
紅1.8–2.2 V10–15 mA20 mA220 Ω100 Ω
黃2.0–2.2 V10–15 mA20 mA220 Ω100 Ω
綠(一般黃綠色)2.0–2.4 V10–15 mA20 mA220 Ω100 Ω
綠(翠綠、高亮)3.0–3.4 V10–15 mA20 mA150–220 Ω33–68 Ω
藍3.0–3.4 V10–15 mA20 mA150–220 Ω33–68 Ω
白3.0–3.4 V10–15 mA20 mA150–220 Ω33–68 Ω
  • 為什麼表裡的電阻都比算出來的大? 因為 220 Ω 一顆就能搞定四種顏色,亮度差一點沒關係,但絕對不會燒。本書的接線一律用 220 Ω,想更亮才換 150 Ω。
  • 3.3 V 配藍/白 LED 要小心:3.3 − 3.2 只剩 0.1 V 可以分給電阻,LED 的 Vf 稍微高一點就不亮了。這不是壞掉,是電壓不夠(第 8 章)。
  • 腳位:長腳是正極(陽極 Anode,接電阻那邊),短腳是負極(陰極 Cathode,接 GND)。塑膠邊緣有一個小平面的那邊也是負極。
        長腳 (+)  短腳 (−)
           │        │
           │        │        ← 側邊有個小平面的是 (−)
         ┌─┴────────┴─┐
         │   LED      │
         └────────────┘

C.4 常用元件腳位圖

2N2222 NPN 電晶體(TO-92 包裝)

        ┌─────────┐
        │  2N2222 │      ← 平的那一面朝自己,腳朝下
        │         │
        └─┬──┬──┬─┘
          │  │  │
          E  B  C
        射極 基極 集極
     (Emitter)(Base)(Collector)
  • E 接 GND,B 經基極電阻接 Arduino 腳位,C 接負載(馬達、蜂鳴器)的負端。
  • 市面上 2N2222 有好幾種版本(P2N2222A、PN2222A),絕大多數 TO-92 包裝都是 E-B-C,但也有少數是 C-B-E。不確定就用三用電表二極體檔查:紅棒接 B、黑棒接 E 或 C 都會顯示約 0.6–0.7 V,那就是 B 腳沒錯。

IRLZ44N N 通道 MOSFET(TO-220 包裝)

          ┌─────────────┐
          │   ○  金屬片  │   ← 金屬散熱片在背面,有字的那一面朝自己
          │             │
          │  IRLZ44N    │
          └──┬────┬────┬┘
             │    │    │
             G    D    S
           閘極  汲極  源極
          (Gate)(Drain)(Source)
  • G 經 100 Ω–220 Ω 接 Arduino 腳位,另外加一顆 10 kΩ 從 G 接到 GND(不開機時保持關閉);D 接負載負端;S 接 GND。
  • 背面的金屬片和 D 腳是連在一起的,不要讓金屬片碰到其他東西。
  • IRLZ44N 的「L」代表邏輯準位(Logic Level),5 V 就能推到全開,3.3 V 也可以開大半。IRFZ44N 不行。

1N4007 整流二極體 / 1N4148 小訊號二極體

   陽極 (Anode, +)                 陰極 (Cathode, −)
        ──────┤████████████▓▓│──────
                            ↑
                        色環這一端是陰極
   電流只能從左流到右(從 + 流到色環那邊)。

   電路符號:   ──►|──    箭頭指的方向就是色環那一端
  • 1N4007:黑色身體、銀灰色環,可以承受 1 A,當飛輪二極體和整流用。
  • 1N4148:橘紅色小玻璃管、黑色環,只能承受 0.2 A,但反應快,當訊號用。
  • 飛輪二極體接法:和馬達/繼電器線圈並聯,色環(陰極)接電源正極那一側,陽極接電晶體集極那一側。接反會直接短路電源。
   +V ──┬──────────┬──
        │          │
       ┌┴┐        ─┴─  色環朝上(接 +V)
       │馬│        ▲
       │達│       ─┬─
       └┬┘        │
        └──────────┴── 到 2N2222 的 C

SG90 伺服馬達

     ┌──────────────┐
     │     SG90     │
     │   ┌──────┐   │
     │   │ 搖臂 │   │
     └───┴──────┴───┘
            ║║║  三條線:
            ║║╚── 橘(或黃):訊號 → Arduino D9
            ║╚─── 紅:5 V(電源)
            ╚──── 棕(或黑):GND
  • 訊號線接 PWM 腳,但 Servo 函式庫其實不用 PWM 腳也行。
  • 一顆 SG90 轉動時可能瞬間吃到 500 mA 以上,電源建議用 4 顆 3 號電池盒(6 V)或 USB 5 V 另外供電,GND 要和 Arduino 共接。只接 Arduino 的 5 V 腳常常會讓 Arduino 重開機。

DHT11 溫濕度感測器

4 腳裸件(藍色格子殼):

        ┌─────────────┐
        │ ▦▦▦▦▦▦▦▦▦▦▦ │   ← 有格子的那一面朝自己
        │ ▦▦▦▦▦▦▦▦▦▦▦ │
        │ ▦▦▦▦▦▦▦▦▦▦▦ │
        └─┬───┬───┬───┬┘
          │   │   │   │
         VCC DATA NC GND
         (+) 訊號 不接 (−)

   DATA 和 VCC 之間要接一顆 4.7 kΩ–10 kΩ 上拉電阻。

3 腳模組版(焊在小 PCB 上,已內建上拉電阻):

        ┌─────────┐
        │  DHT11  │
        └──┬──┬──┬┘
           │  │  │
           +  out −       ← 順序各家不同!一定要看板子上的印字
          VCC DATA GND
  • VCC 接 3.3 V 或 5 V 都可以(ESP32 用 3.3 V)。
  • DATA 接任何數位腳(本書用 D2 或 ESP32 GPIO 4)。
  • 上電後要等 1–2 秒才能讀第一筆,讀太頻繁會回傳 nan(附錄 E)。

SSD1306 0.96 吋 OLED(I2C,4 腳)

        ┌───────────────────┐
        │ ● ● ● ●           │
        │GND VCC SCL SDA    │   ← 大部分模組是這個順序
        │                   │
        │  ┌─────────────┐  │
        │  │             │  │
        │  │   128×64    │  │
        │  │             │  │
        │  └─────────────┘  │
        └───────────────────┘
OLED 腳位Arduino UNOESP32 DevKit V1
GNDGNDGND
VCC5 V(或 3.3 V)3V3
SCLA5GPIO 22
SDAA4GPIO 21
  • 有些模組的前兩腳是 VCC、GND 顛倒,接之前先看印字,接反會燒掉。
  • I2C 位址幾乎都是 0x3C,少數是 0x3D。程式裡位址寫錯畫面會全黑(附錄 E)。

C.5 Arduino UNO 腳位總覽

                  ┌──────────────────────────────────────────────────────────┐
                  │ 數位腳位(上排,從右到左編號)                               │
                  │ ● ● ● ● ● ● ● ● ● ● ● ● │ ● ● ● ● ● ● ● ●              │
   USB-B ┌──┐     │SCL SDA AREF GND 13 12 ~11 ~10 ~9 8 │ 7 ~6 ~5 4 ~3 2 TX1 RX0   │
   (方頭) │  │     │                                                          │
         └──┘     │                        ARDUINO UNO R3                   │
                  │                                                          │
  電源孔 ┌──┐     │               [RESET]              L(板上LED=D13)         │
  7–12V  │  │     │                                                          │
         └──┘     │ ● ● ● ● ● ● ● ●           ● ● ● ● ● ●                   │
                  │ × IOREF RST 3V3 5V GND GND VIN      A0 A1 A2 A3 A4 A5    │
                  │   電源區                             類比輸入 (SDA)(SCL)  │
                  └──────────────────────────────────────────────────────────┘
分區腳位說明
數位 I/OD0–D13都可以 digitalWrite / digitalRead。HIGH = 5 V,LOW = 0 V。每腳最多 20 mA 安全(絕對上限 40 mA)。
PWM(有 ~ 符號)3、5、6、9、10、11analogWrite() 只有這六腳有效。D5、D6 約 980 Hz,其他約 490 Hz。
序列埠D0(RX)、D1(TX)和 USB 共用。上傳和 Serial 用的時候不要接東西在 D0/D1。
外部中斷D2、D3按鈕要用中斷時接這兩腳。
類比輸入A0–A5analogRead() 回傳 0–1023。也可以當數位腳用(寫成 A0 即可)。
I2CA4 = SDA、A5 = SCL板子上方另外兩個 SDA/SCL 腳是同一條線拉出來的。OLED 接這裡。
板上 LEDD13板上標 L 的 LED,Blink 範例用。
電源區5V板子穩壓後的 5 V 輸出,USB 供電時總共約 400–500 mA 可用。
電源區3.3V最多 50 mA,只夠給感測器,不要拿來推馬達。
電源區VIN從這裡輸入 7–12 V 也能供電(和電源孔同一條線)。
電源區GND(×3)三個 GND 都是連在一起的。
電源區RESET接 GND 一下 = 按重置鈕。
電源區IOREF告訴擴充板工作電壓是 5 V,本書用不到。

C.6 ESP32 DevKit V1 腳位總覽(30 腳版)

                          ┌─────────────────┐
                          │   ┌─────────┐   │
                          │   │  天線區  │   │   ← 天線這一端朝上
                          │   └─────────┘   │
          EN(重置)  ●───┤EN            D23├───●  GPIO23
  只能輸入 GPIO36    ●───┤VP            D22├───●  GPIO22 = SCL
  只能輸入 GPIO39    ●───┤VN            TX0├───●  GPIO1 = USB 序列埠 TX(不要用)
  只能輸入 GPIO34    ●───┤D34           RX0├───●  GPIO3 = USB 序列埠 RX(不要用)
  只能輸入 GPIO35    ●───┤D35           D21├───●  GPIO21 = SDA
           GPIO32    ●───┤D32           D19├───●  GPIO19
           GPIO33    ●───┤D33           D18├───●  GPIO18(本書 LED 備用腳)
           GPIO25    ●───┤D25            D5├───●  GPIO5
           GPIO26    ●───┤D26           TX2├───●  GPIO17
           GPIO27    ●───┤D27           RX2├───●  GPIO16
           GPIO14    ●───┤D14            D4├───●  GPIO4(本書 DHT11 用)
           GPIO12    ●───┤D12            D2├───●  GPIO2 = 板上藍色 LED
           GPIO13    ●───┤D13           D15├───●  GPIO15
              GND    ●───┤GND           GND├───●  GND
              VIN    ●───┤VIN           3V3├───●  3.3 V 輸出
                          └───┬───────┬───┘
                           [EN]  USB  [BOOT]
                                Micro-USB
分區腳位說明
工作電壓全部3.3 V! HIGH = 3.3 V。任何腳位輸入不可以超過 3.3 V,接 5 V 感測器輸出要先分壓。
板上 LEDGPIO 2藍色小燈,Blink 用。
本書常用輸出GPIO 18、GPIO 2LED、蜂鳴器、電晶體。
類比輸入(Wi-Fi 開著也能用)GPIO 32、33、34、35、36(VP)、37、38、39(VN)這組叫 ADC1。本書類比輸入用 GPIO 34。
只能輸入GPIO 34、35、36、39沒有輸出功能、沒有內建上拉電阻。接按鈕要自己加外部上拉。
類比輸入(Wi-Fi 開著不能用)GPIO 0、2、4、12–15、25–27這組叫 ADC2,Wi-Fi 一開 analogRead 就會回傳 0。第 16 章要注意。
I2CGPIO 21 = SDA、GPIO 22 = SCLOLED 接這裡。
序列埠TX0 = GPIO 1、RX0 = GPIO 3和 USB 共用,上傳程式和 Serial Monitor 都走這裡。不要接東西。
第二序列埠TX2 = GPIO 17、RX2 = GPIO 16想接別的 UART 裝置用這組(Serial2)。
開機時要小心的腳GPIO 0(BOOT 按鈕)、GPIO 2、GPIO 12、GPIO 15開機瞬間這幾腳的電壓會決定 ESP32 要進燒錄模式還是正常開機。GPIO 12 開機時不要被拉 HIGH,否則開不了機。
PWM幾乎所有輸出腳用 ledcAttach / ledcWrite(第 14 章),不是 analogWrite。
電源VINUSB 供電時這裡會有 5 V 可以拿出來(例如給伺服馬達)。也可以從這裡輸入 5–12 V 供電。
電源3V3板上穩壓器輸出,最多約 500 mA(連 Wi-Fi 時 ESP32 自己就吃掉一半)。
按鈕EN重置(重新開機)。
按鈕BOOT上傳卡在 Connecting… 時,按住它再放開(附錄 E)。

ESP32 和 UNO 腳位對照速查:

功能Arduino UNOESP32 DevKit V1
LEDD9GPIO 2(板上)或 GPIO 18
按鈕D2GPIO 4 或 GPIO 15(內建上拉可用)
類比輸入A0GPIO 34
SDA / SCLA4 / A5GPIO 21 / GPIO 22
HIGH 電壓5 V3.3 V
ADC 範圍0–10230–4095
PWM 函式analogWrite()ledcWrite()

附錄 D 示波器與邏輯分析儀操作速查

這一頁是站在儀器前面、手放在旋鈕上的時候看的。示波器的部分用「步驟清單」寫,照著做就能把波形叫出來;D.2 那張表直接告訴你全書每一種訊號要轉到哪一格。邏輯分析儀的部分照 PulseView 的畫面順序寫。最後 D.4 回答一個很多人會問的問題:兩台都在,該用哪一台?

不同牌子的示波器按鈕位置和名字會差一點,但功能都一樣。下面用「最常見的名字」寫,括號裡是另一種常見叫法。

安全提醒(每次都要):探棒的黑色鱷魚夾一定接電路的 GND。本書電路最高只有 12 V,探棒和示波器都很安全,但鱷魚夾夾錯地方會把電路短路,元件可能燒掉。


D.1 示波器操作步驟清單

步驟 1:開機與探棒補償(第一次用這台示波器、或換了探棒時做)

  1. 按電源鍵,等開機畫面消失(約 10–30 秒)。
  2. 探棒的 BNC 接頭插到 CH1,順時針轉半圈卡住。
  3. 探棒上的小開關撥到 10×。本書從頭到尾都用 10×,因為它比較不會干擾電路。
  4. 在示波器面板上找到 CH1 按鈕,按下去,在畫面選單裡把 探棒(Probe)設成 10×。這一步沒做,讀值會差 10 倍(附錄 E)。
  5. 找到面板上標著「Probe Comp」或「~ 5V 1kHz」的兩個小金屬片。探棒勾子勾在上面那片(方波訊號),鱷魚夾夾下面那片(GND)。
  6. 按 Auto Set(Autoscale),畫面會出現方波。
  7. 看方波的角:
    • 四個角方方正正 → 補償正確,不用動。
    • 角上翹(過衝)或角被削圓 → 用探棒附的小螺絲起子,轉探棒 BNC 端的小螺絲,一邊轉一邊看,直到角變成直角。
   補償正確        補償不足(圓角)      補償過度(尖角)
   ┌────┐          ╭────╮              ┐┌───┐
   │    │          │    │              ││   │
 ──┘    └──      ──╯    ╰──          ──┘└   └──
  1. 拔下探棒,去量真正的電路。

步驟 2:接上電路

  1. 鱷魚夾夾電路的 GND(麵包板藍色負軌、Arduino 的 GND 腳)。
  2. 探棒的勾子勾你要看的那一點(例如 Arduino D9、電阻的某一腳)。勾不到的時候先插一條杜邦線到麵包板,再勾杜邦線。
  3. 接第二個通道時,兩支探棒的鱷魚夾都接 GND,而且是同一個 GND。

步驟 3:Auto Set(先讓它自己試)

  1. 按 Auto Set(Autoscale / Autoset)。
  2. 等 1–2 秒,大部分穩定的重複訊號(方波、PWM、tone)會直接出現。
  3. Auto Set 失敗的情況:訊號是直流(會出現一條線但格子可能很怪)、訊號只出現一次(按鈕彈跳、尖波)、訊號太慢(1 Hz Blink)。這些要用步驟 4 手動調。

步驟 4:手動調整(順序很重要:先垂直、再水平、最後觸發)

4a. 先調 V/div(垂直刻度,Vertical Scale 旋鈕)

  1. 想一下訊號最高是幾 V。Arduino 是 5 V、ESP32 是 3.3 V、電池 9 V。
  2. 畫面垂直通常有 8 格。挑一個 V/div 讓訊號占 3–6 格:5 V 訊號用 1 V/div(占 5 格)或 2 V/div(占 2.5 格)。
  3. 轉 Vertical Position 旋鈕把 0 V 的線(畫面左邊有個小箭頭標著通道號)移到畫面下方第 1 或第 2 格,這樣往上才有空間。
  4. 在 CH1 選單裡把耦合(Coupling)設成 DC。本書幾乎都用 DC。AC 耦合會把直流部分去掉,看電池會看到 0 V。

4b. 再調 s/div(水平刻度,Horizontal Scale 旋鈕)

  1. 想一下訊號一個週期多久(不知道就查 D.2 的表)。
  2. 畫面水平通常有 10 格(有些 12 或 14 格)。挑一個 s/div 讓畫面裡出現 2–5 個週期。例如 490 Hz PWM 週期約 2 ms,用 500 µs/div 一格半一個週期,畫面會有 5 個左右。
  3. 要看細節(例如方波的上升邊),再把 s/div 轉小。

4c. 最後調觸發(Trigger)

  1. 找到 Trigger 區的旋鈕(Level)和 Menu 按鈕。
  2. 來源(Source)選 CH1(或你要當基準的那個通道)。
  3. 類型選 Edge(邊緣),斜率(Slope)選 上升(Rising ↑)。
  4. 轉 Level 旋鈕把觸發準位放在訊號的中間:5 V 訊號放 2.5 V、3.3 V 訊號放 1.6 V。畫面右邊會有個小箭頭標示準位在哪。
  5. 模式(Mode):
    • Auto:沒觸發到也會一直畫,看直流或亂找訊號時用。
    • Normal:沒觸發到就停住等。波形穩定後改成 Normal,畫面才不會閃。
    • Single:觸發一次就停,看一次性的事件用(見步驟 6)。
  6. 波形還在左右跑 → 觸發準位可能在訊號範圍外(例如放到 6 V 了),轉回訊號中間。還是跑 → 換一個通道當來源,或把 Holdoff 稍微加大。

步驟 5:讀數字(Measure 與 Cursor)

自動量測(Measure):

  1. 按 Measure 鈕。
  2. 選來源通道,加入你要的項目。本書常用:
    • Vpp(峰對峰電壓)
    • Vmax / Vmin(最高、最低)
    • Vavg / Mean(平均電壓,看 PWM 濾波後很有用)
    • Freq(頻率)、Period(週期)
    • +Duty(正占空比)
    • +Width(HIGH 的時間,量伺服脈波用)
  3. 數字會出現在畫面下方或旁邊。畫面裡要有至少 1 個完整週期,頻率才算得出來。

游標(Cursor):

  1. 按 Cursor 鈕。
  2. 選 Time(時間,垂直兩條線) 或 Voltage(電壓,水平兩條線)。
  3. 用旋鈕把兩條線分別移到你要量的兩個位置,畫面會顯示 ΔT(時間差) 或 ΔV(電壓差),以及 1/ΔT(換算的頻率)。
  4. 量按鈕彈跳的持續時間、量 RC 充電到 63% 花多久,都用游標。

步驟 6:抓一次性事件(Single)

  1. 先照步驟 4 把 V/div、s/div 設好(這時候畫面可能還是空的,沒關係)。
  2. 觸發模式設成 Normal,來源、斜率、準位設好。尖波通常是上升緣、準位設得比正常電壓高一點(例如 8 V);按鈕彈跳是下降緣、準位 2.5 V。
  3. 按面板上的 Single 鈕,它會亮起來,示波器進入「等待」狀態。
  4. 去做那件事(按下按鈕、關掉馬達)。
  5. 示波器抓到就會自動停住,畫面定格。
  6. 用 Horizontal Position 旋鈕左右捲動,用游標量。
  7. 要再抓一次,再按一次 Single。按 Run/Stop 回到連續模式。

步驟 7:存圖

  1. 插 USB 隨身碟到示波器前面板的 USB 孔(有些機型要先格式化成 FAT32)。
  2. 按 Save/Recall(或 Storage、Print)。
  3. 類型選 Image(BMP / PNG)。
  4. 按 Save 或 Press to Save。有些機型面板上有專用的「相機」或「列印」鍵,按一下就直接存。
  5. 存的檔案拿去貼在實驗紀錄裡。沒有隨身碟的話,用手機對著畫面拍也可以,拍之前先按 Run/Stop 讓畫面停住。

D.2 要看什麼訊號 → 設定對照表

這張表假設探棒設 10×、耦合 DC、垂直 8 格、水平 10 格。數字是「起始值」,看到波形後再微調。

要看的訊號章節V/divs/div觸發設定畫面應該長這樣
電池直流(9 V 或 6 V)62 V1 ms(隨便)Auto 模式一條平的直線,在 0 V 線上方 4.5 格(9 V)或 3 格(6 V)。
Arduino 1 Hz Blink(D9 或 D13)122 V200 msAuto,上升緣,2.5 V很慢的方波,畫面一格一格從左畫到右,0.5 s 高、0.5 s 低。用 Normal 會等很久。
490 Hz PWM(analogWrite D9)142 V500 µsNormal,上升緣,2.5 V方波,週期約 2 ms(4 格),HIGH 的寬度隨 analogWrite 數值變。
980 Hz PWM(D5、D6)142 V200 µsNormal,上升緣,2.5 V方波,週期約 1 ms(5 格)。
1 kHz tone()(蜂鳴器腳)102 V200 µsNormal,上升緣,2.5 V50% 方波,週期 1 ms。Measure Freq 應顯示約 1.000 kHz。
RC 充放電(10 kΩ × 100 nF,τ = 1 ms,用 100 Hz 方波推)51 V1 msNormal,上升緣,來源接方波的 CH1CH1 方波;CH2 是圓滑的充電曲線往上爬、再往下掉,像鯊魚鰭。5 ms 大約充飽。
RC 充放電(10 kΩ × 100 µF,τ = 1 s,用按鈕手動充放)51 V1 sAuto 模式,捲動(Roll)模式更好畫面慢慢從右往左捲,電壓慢慢爬上去再慢慢掉下來。
SG90 伺服 50 Hz 脈波142 V5 msNormal,上升緣,2.5 V很瘦的脈波,每 20 ms(4 格)一個。轉 s/div 到 500 µs 可看清楚脈波寬 1–2 ms。
反電動勢尖波(關掉電感/馬達瞬間)75 V100 µsSingle,上升緣,準位 8 V一個很高很瘦的尖刺,可能衝到 20–40 V 以上,然後迅速掉回來。加了飛輪二極體後尖刺消失。
按鈕彈跳(D2 接上拉電阻)112 V1 msSingle,下降緣,2.5 V按下去的瞬間不是一刀切下來,而是在 5 V 和 0 V 之間亂跳好幾次,持續 0.1–5 ms。
UART 9600(Arduino TX 腳 D1)152 V200 µsSingle,下降緣,2.5 V每個位元約 104 µs 寬(半格),一個字元 10 個位元約 1 ms。平常是 HIGH,開始傳才往下掉。
I2C 100 kHz(CH1 = SCL、CH2 = SDA)152 V20 µsSingle,來源 CH2(SDA),下降緣,1.6 VCH1 一串整齊的時脈,每格 2 個;CH2 在時脈之間變化。SDA 在 SCL 是 HIGH 時往下掉就是「開始」。
PWM 經 RC 低通濾波後101 V500 µsNormal,來源接濾波前的 CH1CH1 方波;CH2 幾乎是直線,只剩一點點鋸齒。改 analogWrite 數值,CH2 的直線會上下移。
電晶體集極電壓反相92 V500 µsNormal,來源 CH1(基極方波)CH1 HIGH 的時候 CH2 LOW,CH1 LOW 的時候 CH2 HIGH,剛好相反。
半波整流(自製線圈的交流經 1N4007)8500 mV10 msAuto 模式整流前(CH1)上下都有;整流後(CH2)只剩上半,下半被削平成 0。

D.3 邏輯分析儀與 PulseView 速查

安裝 PulseView

  1. 到 sigrok 官網(sigrok.org)的 Downloads 頁面下載 PulseView。Windows 下載 .exe 安裝檔,macOS 下載 .dmg,Linux 下載 AppImage。
  2. 安裝時勾選 包含驅動程式(fx2lafw firmware) 的選項(預設有勾)。
  3. Windows 要多做一步:便宜的 USB 邏輯分析儀插上去之後,Windows 會裝錯驅動。
    • 下載 Zadig(zadig.akeo.ie)。
    • 插上邏輯分析儀,打開 Zadig,選單 Options → List All Devices。
    • 下拉選到邏輯分析儀(名字可能是「USB Logic Analyzer」、「Unknown Device #1」或「fx2lafw」)。
    • 右邊的驅動選 WinUSB,按 Install Driver(或 Replace Driver)。
    • 完成後重新插拔一次。
  4. macOS 和 Linux 不用裝驅動,但 Linux 可能要用 sudo 執行或設定 udev 規則(PulseView 的說明頁有寫)。

裝置選擇

  1. 打開 PulseView。
  2. 工具列左上角按 「<No Device>」 那個下拉,選 Connect to Device。
  3. 驅動(Driver)選 fx2lafw (generic driver for FX2 based LAs)。
  4. 介面(Interface)選 USB,按 Scan for devices using driver above。
  5. 下面出現「Saleae Logic」或「fx2lafw」就點它,按 OK。
  6. 工具列會變成裝置名稱,旁邊有 取樣數 和 取樣率 兩個下拉。

取樣率(Sample Rate)與取樣數(Samples)

規則:取樣率至少是訊號頻率的 4 倍,保險用 10 倍。取樣數決定能錄多久:錄的時間 = 取樣數 ÷ 取樣率。

要看的訊號建議取樣率建議取樣數能錄多久
1 Hz Blink1 kHz10 k10 秒
按鈕彈跳1 MHz1 M1 秒
490 Hz PWM100 kHz100 k1 秒
UART 96001 MHz1 M1 秒
UART 1152004 MHz4 M1 秒
I2C 100 kHz2 MHz2 M1 秒
I2C 400 kHz8 MHz8 M1 秒
SPI 1 MHz16–24 MHz10 M約 0.5 秒
  • 8 個通道全開的時候,便宜的邏輯分析儀最高只能到 24 MHz;只開 3 個通道可以更高,但本書用不到。
  • 取樣數太多會等很久、電腦會卡;先用 1 M 試。

接線(GND 必接)

   邏輯分析儀                 Arduino / ESP32 / 麵包板
   ┌─────────┐
   │ CH0 ●───┼─────────────── 要看的訊號 1(例如 TX、SDA)
   │ CH1 ●───┼─────────────── 要看的訊號 2(例如 SCL)
   │ CH2 ●   │
   │  ...    │
   │ GND ●───┼─────────────── GND  ← 沒接這條什麼都看不到
   └─────────┘
        │
       USB → 電腦
  1. 先接 GND,再接訊號線。
  2. 訊號線用母對母或公對母杜邦線接到要看的腳位(用「並聯」的方式掛上去,不要拆掉原本的線)。
  3. 通道電壓只能是 0–5 V 的數位訊號。不要接 9 V 電池、不要接反電動勢尖波、不要接交流。
  4. 在 PulseView 左邊的通道名稱上點兩下可以改名,把 D0 改成 TX、D1 改成 SDA,之後看比較不會搞混。

擷取

  1. 按工具列的 Run(綠色三角)。
  2. 擷取進行中去觸發訊號(例如按 Arduino 的 RESET 讓它重新印 Serial,或讓 OLED 更新畫面)。
  3. 擷取完會自動停。用滑鼠滾輪放大縮小,按住拖曳左右移動。
  4. 什麼都沒看到(全部一條線)→ 查附錄 E「邏輯分析儀全高/全低」。

加解碼器(Protocol Decoder)

UART(第 15 章 Serial.println):

  1. 工具列按 Add protocol decoder(黃綠色的圖示)。
  2. 搜尋 UART,點兩下加入。
  3. 畫面下方出現一條 UART 軌,點它的名稱開設定:
    • RX:選接到 Arduino TX 的那個通道(我們是「聽」Arduino 講話,所以接在解碼器的 RX)。
    • TX:可以不選。
    • Baud rate:9600(要和程式裡 Serial.begin() 的數字一樣)。
    • Data bits:8
    • Parity:none
    • Stop bits:1
    • 這組就是常說的 9600 8N1。
  4. 放大波形,UART 軌上會出現一個個字元(例如 H、e、l、l、o)。看不懂的話把 Data format 改成 ASCII。

I2C(第 15 章 OLED):

  1. 加入 I²C 解碼器。
  2. 設定:SCL 選接 SCL 的通道、SDA 選接 SDA 的通道。
  3. 放大到看得到時脈,I2C 軌會顯示 Start → Address write: 3C → ACK → Data: … → Stop。
  4. 看到 3C 就對了,那是 OLED 的位址。

其他常用: SPI、PWM(會直接算占空比和頻率)、Timing(量兩個邊緣之間的時間)。

常見問題

問題原因與做法
Scan 找不到裝置Windows 沒裝 WinUSB 驅動(用 Zadig);USB 線只能充電不能傳資料;換一個 USB 孔。
全部通道都是一條直線GND 沒接;通道接錯腳;取樣率太低看不到變化;Arduino 根本沒在送(先用示波器或板上 LED 確認)。
UART 解出亂碼或「Frame error」鮑率設錯;取樣率不到鮑率的 4 倍;RX/TX 選反。
I2C 只解出一堆錯誤取樣率不夠(I2C 100 kHz 至少 1 MHz,建議 2 MHz);SDA/SCL 選反。
擷取到一半電腦很卡取樣數太大,降到 1 M 以下。
擷取完畫面空白擷取時間太短,訊號還沒發生就結束了。把取樣數加大,或先按 Run 再讓訊號發生。

D.4 示波器 vs 邏輯分析儀,什麼時候用哪個

一句話:示波器看「電壓長什麼樣」,邏輯分析儀看「0 和 1 排成什麼順序」。

示波器邏輯分析儀
看到的東西連續的電壓曲線,任何高度只有 HIGH 和 LOW 兩種
通道數28
能看直流嗎能(電池、分壓點)不能(只會顯示一條線)
能看圓滑的曲線嗎能(RC 充放電、濾波後的 PWM、正弦波)不能
能看尖波、雜訊、彈跳嗎能,而且看得到有多高彈跳看得到,但不知道有多高
能解 UART / I2C 的內容嗎高階機型可以,入門機型不行可以,而且是強項
能錄很長一段時間嗎幾個畫面可以錄好幾秒、幾百萬個點
價錢一萬到幾萬幾百塊
接線探棒 + 鱷魚夾杜邦線

用示波器的時候:

  • 第 5 章看電容充放電曲線。
  • 第 6 章學儀器本身。
  • 第 7 章看反電動勢尖波(邏輯分析儀看不到高度,而且尖波超過 5 V 會傷到它)。
  • 第 8 章看整流前後的波形。
  • 第 9 章看電晶體集極電壓。
  • 第 10 章看濾波前後、看蜂鳴器頻率。
  • 第 14 章量伺服脈波寬度、PWM 占空比。
  • 任何「這個腳到底有沒有電壓、是幾 V」的問題。

用邏輯分析儀的時候:

  • 第 11 章看按鈕彈跳(也可以用示波器,但邏輯分析儀能錄比較長)。
  • 第 15 章解 UART 看到字元、解 I2C 看到 0x3C。
  • 第 16 章同時看好幾個腳位誰先誰後。
  • 任何「這兩條線的時間順序是什麼」「晶片到底傳了什麼內容」的問題。

兩台一起用的時候:

  • 先用示波器確認訊號電壓正常(HIGH 真的有 5 V 或 3.3 V、沒有超過 5 V),再接邏輯分析儀解碼內容。
  • 兩台的 GND 都接電路 GND,可以同時掛在同一條線上。

附錄 E 故障排除總表

電路不動、程式不跑,是這門課最正常的事。先別急著拆掉重接,照這張表從上往下找你的症狀。每一列都是「先查最簡單的,再查難的」。

開始找問題前,先做這三件事(八成的問題在這裡就解決了):

  1. 拔掉電源,用眼睛看一遍。 杜邦線有沒有插在麵包板同一排(五個孔一組)?LED 長短腳對嗎?電解電容正負對嗎?
  2. 用三用電表量 GND 到電源的電壓。 沒電壓就不用往下查電路了,先查電池、USB 線。
  3. 把程式裡最簡單的 Blink 燒一次。 板上 LED 會閃就代表板子和上傳都沒問題,問題在你的程式或接線。

E.1 電源、LED、被動元件

症狀可能原因怎麼檢查/解決相關章節
LED 完全不亮LED 接反(長腳要接電阻/正極那邊)把 LED 拔起來轉 180° 再插。1、8
LED 完全不亮迴路沒有閉合:杜邦線沒插到同一排、電阻腳沒插進去、GND 沒接回去用三用電表通斷檔(蜂鳴)從電源正極一路量到負極,哪一段不響就是哪一段斷了。1
LED 完全不亮電阻太大(例如拿到 100 kΩ 當 220 Ω)讀色碼或用 Ω 檔量。紅紅棕才是 220 Ω。2
LED 完全不亮(ESP32、藍/白 LED)3.3 V 減掉 LED 的 3.2 V 順向電壓後幾乎沒剩,推不亮換紅色或綠色 LED,或限流電阻改 68–100 Ω。8、16
LED 完全不亮(Arduino)程式腳位寫錯,或 pinMode 沒設成 OUTPUT檢查程式裡的 ledPin 數字和實際插的腳一不一樣;setup() 裡要有 pinMode(ledPin, OUTPUT)。12
LED 一閃就暗掉、或變很暗、聞到焦味沒接限流電阻,或電阻太小,LED 燒掉了LED 燒了就換一顆(它不會自己好)。接之前確認有 220 Ω 串聯。2、8
LED 很暗電阻太大、電池快沒電、並聯了太多 LED 分電流量 LED 兩端電壓:低於 1.8 V 就是電流不夠。換小一點的電阻(最小 150 Ω)或換電池。2、3、4
電阻發燙、變色、冒煙功率超過 1/4 W:電阻太小或電壓太高(例如 9 V 直接接 100 Ω 以下)立刻拔電源。用 P = V² ÷ R 算一次,超過 0.25 W 就要換大一點的電阻。附錄 B 有算例。4
電解電容鼓起來、噴液、爆開接反極性,或電壓超過耐壓拔電源,丟掉這顆(戴手套、不要碰到液體)。長腳是正極、有白色條紋那一側是負極。耐壓要大於電路電壓。5
電池一下子就沒電、摸起來燙短路:正負極直接相碰,或麵包板電源軌被一條線接通了拔掉電池。用通斷檔量電池扣的兩條線,會響就是短路。9 V 電池扣的兩個金屬頭很容易互碰。1、4
電池沒電用太久,或存放太久用三用電表直流 V 檔量:9 V 電池低於 7 V、3 號電池低於 1.2 V 就該換。量的時候最好接著負載。4
三用電表量不到電流電表要「串聯」進電路,不是「並聯」;或電表的保險絲燒了把迴路拆開一個缺口,電表的兩支棒接在缺口兩端。紅棒要插在 mA 孔不是 V 孔。1、2
三用電表量電阻讀值亂跳電阻還接在電路上,或你的手指同時摸到兩支棒把電阻拔起來單獨量,手不要碰金屬腳。2
麵包板接觸不良(時好時壞、碰一下就變)麵包板孔鬆了、杜邦線針頭彎了、元件腳太細換一排孔插;把杜邦線針頭弄直;電阻腳可以稍微折一下再插。老舊麵包板直接換。全書

E.2 電晶體、馬達、感測器、顯示器

症狀可能原因怎麼檢查/解決相關章節
馬達不轉電流不夠:直接接 Arduino 腳位(最多 20 mA)當然推不動馬達一定要經電晶體或 MOSFET,電源用電池盒或 5V 腳。9、14
馬達不轉電晶體腳位接錯(E-B-C 弄反)對照附錄 C 的腳位圖。用三用電表二極體檔找 B 腳。9
馬達不轉基極沒有電阻,或電阻太大B 腳要經 330 Ω–1 kΩ 接 Arduino。10 kΩ 以上電流不夠讓電晶體飽和。9
馬達不轉(MOSFET)用了 IRFZ44N 而不是 IRLZ44N;或 G 腳沒接 10 kΩ 下拉看元件上的印字。ESP32 的 3.3 V 只推得動 IRLZ 系列。9
馬達一轉 Arduino 就重開機、序列埠斷線馬達啟動電流把 5 V 拉垮;或沒接飛輪二極體,反電動勢打到板子馬達用獨立電池盒,只有 GND 和 Arduino 共接。馬達兩端並聯 1N4007(色環接正極)。7、9
伺服馬達抖動、嗡嗡叫、轉不到位電流不足:SG90 瞬間可以吃 500 mA 以上,Arduino 的 5V 腳撐不住伺服的紅線接 4 顆電池盒(6 V)或獨立 USB 5 V,棕線 GND 和 Arduino GND 接在一起,橘線接 D9。14
伺服馬達亂轉或不動訊號線接錯腳;程式沒有 myServo.attach(9)訊號線(橘/黃)接程式裡 attach 的那一腳。用示波器看 D9 有沒有 50 Hz 脈波(附錄 D)。14
繼電器一直喀喀響線圈電流讓電源電壓抖動,Arduino 跟著不穩繼電器模組的 VCC 接獨立 5 V,GND 共接。7、9
DHT11 讀到 nan 或 -999接線錯(VCC/DATA/GND 順序每家模組不同);讀太快;沒上拉電阻看模組上的印字再接。兩次讀取間隔至少 2 秒。裸件要加 4.7 kΩ–10 kΩ 上拉(DATA 到 VCC)。13、16
DHT11 讀到的數值不變、或明顯錯函式庫選錯型號(DHT22 vs DHT11)程式裡 #define DHTTYPE DHT11。13
光敏電阻讀值一直是 0 或 1023分壓器沒接對,變成直接接電源或直接接 GND光敏電阻和 10 kΩ 串聯在 5 V 和 GND 之間,A0 接「中間那一點」。13
OLED 沒畫面(全黑)I2C 位址錯:程式寫 0x3D 但模組是 0x3C(或相反)先跑 I2C 掃描程式(第 15 章)看到位址幾號,再改程式。15、16
OLED 沒畫面(全黑)SDA、SCL 接反UNO:SDA = A4、SCL = A5。ESP32:SDA = 21、SCL = 22。對調一下。15、16
OLED 沒畫面,摸起來燙VCC 和 GND 接反(有些模組前兩腳順序相反)立刻拔掉。看模組印字重接。燒掉的 OLED 通常救不回來。15
OLED 有畫面但只亮一半、或字疊在一起程式裡的解析度設錯(128×32 vs 128×64)本書的模組是 128×64,display 初始化的參數要對。16
蜂鳴器只有「嗒」一聲,不會發出音調買到有源蜂鳴器(Active),它不吃頻率要用無源(Passive)蜂鳴器。有源的通電就只會叫固定一個音。10
蜂鳴器完全沒聲音tone() 用在 ESP32 上(ESP32 沒有 tone())ESP32 用 ledcWriteTone(),第 14 章有範例。10、14、16

E.3 Arduino 與 ESP32

症狀可能原因怎麼檢查/解決相關章節
Arduino IDE 的連接埠選單是灰的、找不到 COM 埠USB 線只有充電功能;相容板的 CH340 驅動沒裝;USB 孔沒電換一條確定能傳資料的線。Windows 到裝置管理員看有沒有「未知裝置」,去 CH340 驅動網站下載安裝。macOS 新版通常免裝。12
上傳失敗:avrdude: stk500_recv(): programmer is not responding選錯連接埠或選錯板子;D0/D1 腳上有接東西工具 → 板子選 Arduino UNO,連接埠選有 Arduino 字樣的那個。把 D0、D1 上的線拔掉再上傳。12
上傳失敗:Access is denied / 連接埠被占用序列埠監控視窗、PulseView 或另一個 IDE 視窗還開著關掉其他正在用這個埠的程式,再上傳。12
程式編譯錯誤:‘xxx’ was not declared in this scope打錯字、大小寫錯、沒有 #include 函式庫、變數在用之前沒宣告看錯誤訊息的行號,去那一行。Arduino 分大小寫:digitalwrite 不等於 digitalWrite。12
序列埠監控視窗出現亂碼(方塊、問號、奇怪符號)監控視窗右下角的鮑率和程式 Serial.begin() 的數字不一樣兩邊都設 9600(或都設 115200)。ESP32 開機時會先用 115200 印一段開機訊息,那段是正常的亂碼。12、15
序列埠監控視窗什麼都沒印程式沒有 Serial.begin();選錯連接埠;板子一直在重開加 Serial.begin(9600)。看板上的 TX LED 有沒有閃,有閃就是有在送。12
ESP32 上傳卡在 Connecting…….._____…..板子沒進入燒錄模式看到 Connecting 時按住 BOOT 鍵不放,等開始上傳(出現 Writing at…)再放開。還是不行就按住 BOOT、按一下 EN、再放開 BOOT。16
ESP32 上傳失敗:A fatal error occurred: Failed to connect同上;或 USB 線不良;或 CP2102/CH340 驅動沒裝先換線,再裝驅動,再試 BOOT 鍵。16
ESP32 一直重開機,序列埠印 Brownout detector was triggered電壓不夠:USB 線太細、USB 孔供電弱、Wi-Fi 開啟瞬間電流拉太高換短一點粗一點的 USB 線;插電腦後面的 USB 孔;3V3 和 GND 之間並一顆 470 µF–1000 µF 電解電容;馬達、伺服改用獨立電源。16
ESP32 一直重開機,印 Guru Meditation Error程式當掉:通常是陣列越界、用到空指標、或 Wi-Fi 還沒連上就去用看錯誤訊息下面的 Backtrace;用 Serial.println 一步一步找是哪一行。16
ESP32 開機後完全沒反應、不印任何東西GPIO 12 開機時被拉 HIGH,或 GPIO 0 被拉 LOW把 GPIO 0、2、12、15 上的線拔掉再開機。16
ESP32 analogRead 一直回傳 0用到 ADC2 的腳位(0、2、4、12–15、25–27),Wi-Fi 開啟後它們不能用類比輸入改接 GPIO 32–39(本書用 34)。13、16
ESP32 腳位燒壞、讀值怪怪的給它輸入了 5 VESP32 腳位只能 3.3 V。5 V 感測器輸出要先用 10 kΩ + 20 kΩ 分壓再接。16
Wi-Fi 連不上(WiFi.status() 一直不是 WL_CONNECTED)SSID 或密碼打錯(大小寫、空格);Wi-Fi 是 5 GHz(ESP32 只支援 2.4 GHz);訊號太弱用手機熱點測試(記得開 2.4 GHz 相容模式)。SSID 和密碼用複製貼上。靠近路由器。16
Wi-Fi 連上了,但手機打不開網頁手機和 ESP32 不在同一個 Wi-Fi;IP 位址打錯;學校網路把裝置互相隔離序列埠印出的 IP 要和手機的網段一樣(例如都是 192.168.1.x)。用手機熱點最保險。16
按鈕按一下,Arduino 卻數成好幾次按鈕彈跳加 50 ms 延遲去抖動,或在按鈕兩端並 100 nF 電容。用示波器看彈跳(第 11 章)。11
按鈕沒按也亂觸發腳位浮接,沒有上拉或下拉電阻用 pinMode(buttonPin, INPUT_PULLUP),按鈕另一端接 GND。ESP32 的 34–39 沒有內建上拉,要外接 10 kΩ。11

E.4 示波器與邏輯分析儀

症狀可能原因怎麼檢查/解決相關章節
示波器畫面沒有波形、一條直線在 0 V通道沒打開;探棒沒接好;鱷魚夾沒夾 GND;電路本來就沒訊號按 CH1 鈕讓它亮;把探棒勾到 Probe Comp 看有沒有方波(有就是電路問題,沒有就是示波器或探棒問題)。6
示波器波形超出畫面、或壓成一條線V/div 太小或太大轉 Vertical Scale 讓波形占 3–6 格。按 Auto Set 重來。6
示波器波形左右亂跑、重疊、閃爍觸發準位在訊號範圍外;觸發來源選錯通道;模式在 Auto 卻沒抓到轉 Trigger Level 到訊號中間(5 V 訊號設 2.5 V);來源改成有訊號的那個通道;穩了之後改 Normal。6
示波器讀值剛好差 10 倍(5 V 顯示 0.5 V 或 50 V)探棒撥在 10× 但示波器通道設 1×,或相反探棒上的開關和 CH 選單裡的 Probe 設定要一致。本書統一用 10×。6
示波器量電池看到 0 V耦合設成 AC,直流被濾掉了CH 選單裡 Coupling 改 DC。6
示波器量 1 Hz Blink 看不到東西s/div 太小,一格才幾 ms,畫面裡只有一小段 HIGH 或 LOWs/div 轉到 200–500 ms;模式用 Auto。12
示波器抓不到尖波、彈跳這類一次性事件用 Auto 或 Normal 模式,畫面一直被後面的訊號蓋掉用 Single:設好準位和斜率,按 Single,再去觸發事件。7、11
示波器波形有一層毛毛的雜訊鱷魚夾接的 GND 離訊號太遠;探棒線繞到馬達旁邊;電路沒有去耦電容GND 夾離訊號點越近越好;電源腳旁邊並 100 nF 電容。6、10
示波器一接上去,電路就壞了或不動鱷魚夾夾到不是 GND 的地方,把那一點短路到地了鱷魚夾只能夾 GND。先接 GND 再勾訊號。6
邏輯分析儀每個通道都是全高或全低GND 沒接(最常見);通道接錯腳;取樣率太低先接 GND 再接訊號;取樣率至少是訊號的 4 倍。15
PulseView 找不到裝置Windows 驅動沒換成 WinUSB;USB 線只能充電用 Zadig 裝 WinUSB(附錄 D)。換線。15
UART 解碼出亂碼或一堆 Frame error鮑率設錯;取樣率不到鮑率的 4 倍;通道選到 RX 而不是 TX解碼器鮑率設和程式一樣(9600);取樣率 1 MHz;Arduino 的 TX 腳接到解碼器的 RX 欄位。15
I2C 解不到,或只有 Start 沒有位址取樣率不夠(100 kHz 的 I2C 要 1–2 MHz);SDA/SCL 選反取樣率改 2 MHz;解碼器設定裡 SCL/SDA 對調。15
邏輯分析儀擷取時間太短,看不到想看的事件取樣數太少取樣數加大到 1 M 以上,或取樣率降低(錄得比較久)。15
邏輯分析儀接上去之後電路變怪通道接到超過 5 V 的點,或接到反電動勢尖波邏輯分析儀只能接 0–5 V 的數位訊號。看尖波請用示波器。7、15

E.5 都查過了還是不行?

  1. 整個拆掉,從最簡單的開始重建。 先只接電源 + 電阻 + LED,亮了再加下一個元件。每加一個就測一次。
  2. 換一個元件試。 杜邦線、LED、電晶體都可能壞。用三用電表通斷檔量杜邦線兩頭。
  3. 換一塊麵包板、換一塊板子。 排除掉硬體本身的問題。
  4. 把接線畫成 ASCII 圖,程式印出來,拿給同學或老師看。 很多錯自己看十遍看不到,別人一眼就看到。
  5. 寫下來。 「我做了什麼 → 看到什麼 → 預期是什麼」。這就是除錯,也是專題報告裡最有價值的一段(第 17 章)。

附錄 F 中英名詞對照表

全書出現過的名詞都在這裡,依主題分成六組。每一條有中文、英文和一句話說明。說明是「幫你想起來」用的,不是完整定義;完整的解釋請回對應章節看。

查的方法:先想這個詞是「講電的基本性質」「某個零件」「訊號或儀器」「數位或 Arduino」「通訊或 Wi-Fi」還是「程式裡的東西」,再到那一組找。


F.1 電學基礎

中文英文簡短說明
電荷Charge電的「最小單位」,正負兩種,同性相斥、異性相吸。
電流Current (I)電荷流動的量,單位安培(A)。像水管裡每秒流過多少水。
電壓Voltage (V)推動電流的「壓力」,單位伏特(V)。像水塔的高度。
電阻Resistance (R)阻擋電流的程度,單位歐姆(Ω)。像水管變細。
安培Ampere (A)電流的單位。本書常用毫安培(mA)。
伏特Volt (V)電壓的單位。
歐姆Ohm (Ω)電阻的單位。
瓦特Watt (W)功率的單位。1/4 W 電阻最多只能散 0.25 W 的熱。
歐姆定律Ohm’s LawV = I × R。電壓、電流、電阻三者的關係。
功率Power (P)每秒消耗的能量,P = V × I。
導體Conductor電流容易通過的材料:銅、鋁、鐵。
絕緣體Insulator電流幾乎不通過的材料:塑膠、橡膠、空氣。
閉合迴路Closed Circuit電流從電源正極出發、繞一圈回到負極的完整路徑。斷一處就不通。
開路Open Circuit迴路斷掉,沒有電流。
短路Short Circuit電源正負極被幾乎沒電阻的東西直接接通,電流超大、會發熱甚至起火。
接地/地Ground (GND)電路裡約定的「0 V 基準點」。所有電壓都是相對它量的。
直流Direct Current (DC)電流方向固定不變。電池、USB 都是直流。
交流Alternating Current (AC)電流方向來回交替。家用插座是交流,本書不碰。
串聯Series元件一個接一個排成一條線,電流處處相同。
並聯Parallel元件並排接在同兩點之間,電壓處處相同。
分壓器Voltage Divider兩顆串聯電阻,從中間取出比較低的電壓。
分流Current Division並聯時電流依電阻大小分配,電阻小的分到多。
克希荷夫電流定律Kirchhoff’s Current Law (KCL)流進一個接點的電流 = 流出的電流。
克希荷夫電壓定律Kirchhoff’s Voltage Law (KVL)繞迴路一圈,所有電壓升和電壓降加起來是 0。
內阻Internal Resistance電池內部自己的電阻,電流越大、輸出電壓掉越多。
空載電壓Open-Circuit Voltage電池沒接負載時量到的電壓。
負載Load吃電的東西:LED、馬達、Arduino。
電池容量Battery Capacity (mAh)毫安培小時。1000 mAh 可以供 100 mA 十小時(理想值)。
穩壓器Voltage Regulator把輸入電壓變成固定輸出電壓的晶片,Arduino 板上就有一顆 5 V 的。
磁場Magnetic Field磁鐵或通電導線周圍的「力的範圍」。
電磁感應Electromagnetic Induction磁場變化讓線圈產生電壓。發電機的原理。
反電動勢Back EMF線圈的電流突然被切斷時,它自己產生的反向高電壓尖波。
時間常數Time Constant (τ)RC 電路充放電的「快慢指標」,τ = R × C,5τ 當作充飽。

F.2 元件

中文英文簡短說明
電阻(元件)Resistor固定阻值的零件,用色環標示阻值。
色碼Color Code電阻身上的色環,用顏色表示數字。
可變電阻/電位器Potentiometer轉旋鈕可以改阻值的三腳元件,常當分壓器用。
光敏電阻Light-Dependent Resistor (LDR)越亮阻值越低的電阻,做夜燈用。
電容(元件)Capacitor儲存電荷的零件,像小水桶,單位法拉(F)。
法拉Farad (F)電容的單位。本書用微法(µF)和奈法(nF)。
電解電容Electrolytic Capacitor容量大的圓柱形電容,有極性,接反會爆。
陶瓷電容Ceramic Capacitor小容量、沒極性的扁平電容,常用 100 nF(104)。
極性Polarity元件有分正負腳。LED、電解電容、二極體都有。
去耦電容Decoupling Capacitor並在晶片電源腳旁邊的電容,吸收電壓的小抖動。
電感(元件)Inductor線圈,抗拒電流變化,單位亨利(H)。
亨利Henry (H)電感的單位。本書用微亨(µH)和毫亨(mH)。
線圈Coil把導線繞成圈,通電生磁、磁變生電。
電磁鐵Electromagnet線圈裡放鐵釘,通電就變磁鐵。
二極體Diode只讓電流往一個方向走的零件。
陽極Anode二極體/LED 的正極腳,電流從這裡進。
陰極Cathode二極體/LED 的負極腳,電流從這裡出。色環那一端。
順向偏壓Forward Bias二極體接「對」方向,會導通。
逆向偏壓Reverse Bias二極體接「反」方向,不導通。
順向電壓Forward Voltage (Vf)二極體導通時固定吃掉的電壓,1N4007 約 0.7 V、LED 1.8–3.4 V。
整流Rectification用二極體把交流變成只有一個方向的直流。
飛輪二極體Flyback Diode並在線圈兩端、吸收反電動勢尖波的二極體。
發光二極體Light-Emitting Diode (LED)會發光的二極體,一定要串限流電阻。
限流電阻Current-Limiting Resistor串在 LED 前面、防止電流過大的電阻。
七段顯示器Seven-Segment Display七個 LED 排成「8」字,顯示數字。
電晶體Transistor用小電流控制大電流的三腳元件,當開關用。
NPN 電晶體NPN Transistor本書用的 2N2222,基極給正電流就導通。
基極Base (B)電晶體的控制腳。
集極Collector (C)電晶體接負載的腳。
射極Emitter (E)電晶體接 GND 的腳。
放大倍數Current Gain (β / hFE)集極電流可以是基極電流的幾倍,2N2222 約 100。
飽和Saturation電晶體完全導通的狀態,像水閥全開。
截止Cut-off電晶體完全不導通的狀態,像水閥全關。
金氧半場效電晶體MOSFET用電壓控制的開關,本書用 IRLZ44N,幾乎不吃控制電流。
閘極Gate (G)MOSFET 的控制腳。
汲極Drain (D)MOSFET 接負載的腳。
源極Source (S)MOSFET 接 GND 的腳。
邏輯準位 MOSFETLogic-Level MOSFET5 V 或 3.3 V 就能推到全開的 MOSFET,型號裡有 L。
達靈頓Darlington兩顆電晶體串起來,放大倍數相乘。
繼電器Relay用線圈吸動金屬片的機械開關,可以用小電壓切換另一個電路。
直流馬達DC Motor通電就轉的馬達,調電壓或 PWM 調速。
伺服馬達Servo Motor可以指定角度的馬達,靠 1–2 ms 的脈波控制。
蜂鳴器Buzzer發聲元件。無源(Passive)要給頻率才會響,有源(Active)通電就響。
按鈕開關Push Button / Tactile Switch按下才導通的開關。
溫濕度感測器Temperature & Humidity Sensor (DHT11)一條線回傳溫度與濕度的感測器。
感測器Sensor把光、溫度、聲音等變成電壓或數位訊號的元件。
麵包板Breadboard不用焊接就能插元件的板子,每五孔一排相通。
杜邦線Jumper Wire (Dupont Wire)兩端有針(公)或孔(母)的連接線。
電池扣Battery Snap接 9 V 電池用的卡扣,附兩條線。
有機發光二極體顯示器OLED Display自己會發光的小螢幕,本書用 0.96 吋 SSD1306。

F.3 訊號與儀器

中文英文簡短說明
訊號Signal隨時間變化、帶有資訊的電壓。
波形Waveform訊號畫在「電壓 vs 時間」圖上的形狀。
正弦波Sine Wave最平滑的波,像海浪。
方波Square Wave只有高低兩種電壓、方方正正的波。
脈波Pulse短暫跳高又回來的一個訊號。
頻率Frequency (f)每秒幾個週期,單位赫茲(Hz)。f = 1 ÷ T。
週期Period (T)一個完整的波要多久,單位秒。
赫茲Hertz (Hz)頻率的單位,每秒一次。
振幅Amplitude波從中心到最高點的高度。
峰對峰電壓Peak-to-Peak Voltage (Vpp)波最高點到最低點的差。
平均電壓Average Voltage一段時間內電壓的平均值,PWM 濾波後就是這個。
占空比Duty Cycle一個週期內 HIGH 占的百分比。
脈寬調變Pulse-Width Modulation (PWM)用改變占空比的方波來「假裝」不同電壓。
上升緣Rising Edge訊號從低變高的瞬間。
下降緣Falling Edge訊號從高變低的瞬間。
濾波Filtering把訊號裡不要的頻率去掉。
低通濾波器Low-Pass Filter讓慢的變化通過、擋掉快的變化。RC 一顆電阻一顆電容就能做。
雜訊Noise訊號上不想要的亂七八糟小抖動。
尖波Spike很短、很高的一個突波,例如反電動勢。
彈跳Bounce按鈕按下時金屬片反覆跳動,造成好幾次高低變化。
去抖動Debounce用延遲、電容或程式把彈跳濾掉。
示波器Oscilloscope把電壓隨時間的變化畫出來的儀器。
探棒Probe示波器的測試線,有勾子和鱷魚夾。
衰減比Attenuation (1×/10×)探棒把訊號縮小的倍數,10× 比較不干擾電路。
探棒補償Probe Compensation調探棒上的小螺絲,讓方波的角變直角。
接地夾Ground Clip探棒上的黑色鱷魚夾,一定接電路 GND。
通道Channel (CH)示波器或邏輯分析儀的一個輸入。
每格電壓Volts per Division (V/div)示波器畫面垂直一格代表幾 V。
每格時間Seconds per Division (s/div)示波器畫面水平一格代表多少時間。
耦合Coupling (DC/AC)DC 看完整電壓;AC 把直流去掉只看變化。
觸發Trigger告訴示波器「從訊號的哪一點開始畫」,波形才會停住。
觸發準位Trigger Level觸發用的電壓門檻。
自動模式Auto Mode沒觸發到也一直畫。
一般模式Normal Mode沒觸發到就等。
單次觸發Single觸發一次就停住畫面,看一次性事件。
自動設定Auto Set / Autoscale示波器自己猜一組設定。
游標Cursor畫面上可以移動的量測線,量時間差或電壓差。
自動量測Measure示波器自動算 Vpp、頻率、占空比等數值。
捲動模式Roll Mode畫面像紙帶一樣慢慢捲,看很慢的訊號。
三用電表Multimeter量電壓、電流、電阻的手持儀器。
通斷檔Continuity三用電表的蜂鳴功能,兩點相通會叫。
邏輯分析儀Logic Analyzer同時記錄多條線 0/1 變化的儀器,可以解碼通訊。
取樣率Sample Rate每秒記錄幾次,至少要是訊號頻率的 4 倍。
取樣數Sample Count總共記錄幾個點,決定錄多久。
協定解碼器Protocol DecoderPulseView 裡把 0/1 翻譯成字元或位址的功能。
序列繪圖器Serial PlotterArduino IDE 裡把序列埠的數字畫成曲線的工具。

F.4 數位與微控制器

中文英文簡短說明
數位Digital只有 0 和 1 兩種狀態。
類比Analog連續變化的量,任何電壓都可以。
高電位/低電位HIGH / LOW數位的 1 和 0。UNO 是 5 V/0 V,ESP32 是 3.3 V/0 V。
電壓門檻Threshold高於多少算 1、低於多少算 0 的分界線。
位元Bit一個 0 或 1。
位元組Byte8 個位元,可以表示 0–255。
二進位Binary只用 0 和 1 的計數方式。
十六進位Hexadecimal用 0–9 和 A–F 計數,0x3C 這種寫法。
邏輯閘Logic Gate做 AND、OR、NOT 等判斷的基本電路。
真值表Truth Table把所有輸入組合和對應輸出列成的表。
及閘AND Gate全部輸入都是 1 才輸出 1。
或閘OR Gate任何一個輸入是 1 就輸出 1。
反閘NOT Gate把 1 變 0、0 變 1。
互斥或閘XOR Gate兩個輸入不一樣才輸出 1。
上拉電阻Pull-up Resistor把腳位平常拉到 HIGH 的電阻,按鈕按下才變 LOW。
下拉電阻Pull-down Resistor把腳位平常拉到 LOW 的電阻。
浮接Floating腳位沒接任何東西,讀值會亂跳。
微控制器Microcontroller (MCU)一顆有 CPU、記憶體、腳位的小電腦晶片。
Arduino UNOArduino UNO本書用的 5 V 開發板,晶片是 ATmega328P。
ESP32ESP32本書用的 3.3 V 開發板,內建 Wi-Fi 和藍牙。
開發板Development Board把微控制器、USB、穩壓器做在一起方便使用的板子。
腳位Pin微控制器伸出來可以接線的接點。
通用輸入輸出GPIO可以設定成輸入或輸出的腳位。
數位輸出Digital Output腳位輸出 HIGH 或 LOW。
數位輸入Digital Input腳位讀取 HIGH 或 LOW。
類比輸入Analog Input腳位讀取電壓並換成數字。
類比數位轉換器Analog-to-Digital Converter (ADC)把電壓變成數字的電路,UNO 10 位元、ESP32 12 位元。
解析度ResolutionADC 能分成幾格:10 位元 = 1024 格。
參考電壓Reference VoltageADC 把哪個電壓當成最大值:UNO 5 V、ESP32 3.3 V。
中斷Interrupt腳位一變化就立刻跳去執行某段程式。
重置Reset讓微控制器重新開機。
燒錄/上傳Upload / Flash把程式寫進微控制器。
燒錄模式Bootloader ModeESP32 等待接收程式的狀態,按 BOOT 鍵進入。
開機按鈕BOOT ButtonESP32 上進燒錄模式用的按鈕(接 GPIO 0)。
啟用腳EN (Enable)ESP32 的重置腳,按下就重開。
欠壓偵測Brownout DetectorESP32 偵測到電壓不夠就自動重開機的保護機制。
深度睡眠Deep SleepESP32 幾乎全部關掉省電,時間到再醒來。
板上 LEDOnboard LED焊在開發板上的 LED:UNO 是 D13,ESP32 是 GPIO 2。
驅動程式Driver讓電腦認得 USB 裝置的軟體,CH340、CP2102 常要另外裝。
函式庫Library別人寫好的程式包,例如 Servo、DHT、Adafruit_SSD1306。
整合開發環境IDE寫程式、編譯、上傳一站搞定的軟體,Arduino IDE。

F.5 通訊與無線

中文英文簡短說明
通訊協定Communication Protocol兩顆晶片講話的「規則」,誰先講、多快講、怎麼算一個字。
序列通訊Serial Communication一次送一個位元,排隊送。
並列通訊Parallel Communication多條線同時送很多位元。
通用非同步收發器UART兩條線(TX、RX)的序列通訊,Serial.println 用的就是它。
傳送/接收TX / RX送出資料的腳/接收資料的腳。A 的 TX 接 B 的 RX。
鮑率Baud Rate每秒幾個位元,兩邊要一樣,本書用 9600 或 115200。
起始位元Start BitUART 每個字元前面的一個 LOW,告訴對方「要開始了」。
停止位元Stop BitUART 每個字元後面的一個 HIGH,告訴對方「講完了」。
8N18N18 個資料位元、無同位元、1 個停止位元,UART 最常見設定。
序列埠Serial Port (COM Port)電腦和 Arduino 講話的那條通道。
序列埠監控視窗Serial MonitorArduino IDE 裡顯示 Serial.println 內容的視窗。
積體電路匯流排I2C (Inter-Integrated Circuit)兩條線(SDA、SCL)可以接很多裝置的通訊,靠位址認人。
資料線SDA (Serial Data)I2C 的資料線。UNO 是 A4,ESP32 是 GPIO 21。
時脈線SCL (Serial Clock)I2C 的時脈線。UNO 是 A5,ESP32 是 GPIO 22。
位址AddressI2C 裝置的「門牌號碼」,OLED 是 0x3C。
主機/從機Master / Slave (Controller / Peripheral)I2C 裡發號施令的那顆/聽命的那顆。
應答ACK (Acknowledge)I2C 從機收到資料後回的一個「收到」位元。
序列周邊介面SPI四條線的高速通訊,本書只簡介。
時脈Clock用來同步「現在讀第幾個位元」的規律方波。
無線網路Wi-FiESP32 內建的無線網路,只支援 2.4 GHz。
網路名稱SSIDWi-Fi 的名字。
網際網路協定位址IP Address裝置在網路上的號碼,例如 192.168.1.50。
網頁伺服器Web Server等別人用瀏覽器來敲門、然後回傳網頁的程式。
超文字傳輸協定HTTP瀏覽器和伺服器講話的規則。
超文字標記語言HTML寫網頁內容的語言。
用戶端Client主動發出請求的一方,例如手機瀏覽器。
存取點Access Point (AP)讓別人連上的 Wi-Fi 熱點,ESP32 自己也能當。
訊息佇列遙測傳輸MQTT物聯網常用的「發布/訂閱」通訊方式,本書只簡介。
藍牙BluetoothESP32 內建的短距離無線通訊,本書只提到。
物聯網Internet of Things (IoT)讓感測器、燈、風扇都連上網路的概念。

F.6 程式

中文英文簡短說明
程式碼Code / SketchArduino 把一個程式叫做 sketch。
初始設定setup()開機只執行一次的區塊。
主迴圈loop()setup() 結束後一直重複執行的區塊。
函式Function一段取了名字、可以重複呼叫的程式。
變數Variable存數值的「盒子」,要先宣告型別。
常數Constant (const)宣告後不能改的變數,腳位編號常用。
整數int整數型別,UNO 上範圍 −32768 到 32767。
浮點數float有小數的數字,例如 3.14。
布林bool只有 true/false 兩種值。
字串String一串文字。
註解Comment用 // 或 /* */ 寫給人看的說明,程式不執行。
條件判斷if / else「如果……就……否則……」。
迴圈for / while重複執行某段程式。
比較運算子Comparison Operator==、!=、<、>、<=、>=。注意 == 和 = 不一樣。
邏輯運算子Logical Operator&&(且)、||(或)、!(非)。
設定腳位模式pinMode()把腳位設成 INPUT、OUTPUT 或 INPUT_PULLUP。
數位寫入digitalWrite()讓腳位輸出 HIGH 或 LOW。
數位讀取digitalRead()讀腳位是 HIGH 還是 LOW。
類比讀取analogRead()讀 ADC 數值,UNO 0–1023、ESP32 0–4095。
類比寫入analogWrite()UNO 輸出 PWM,0–255。
延遲delay()暫停幾毫秒。
毫秒計時millis()回傳開機到現在過了幾毫秒,不卡住程式的計時方法。
對應map()把一個範圍的數字換算成另一個範圍。
音調tone()UNO 讓腳位輸出指定頻率的方波。
LED 控制ledcWrite() / ledcAttach()ESP32 輸出 PWM 的函式。
序列埠初始化Serial.begin()設定鮑率、打開序列埠。
序列埠輸出Serial.println()把文字或數字送到電腦。
引入#include把函式庫加進程式。
定義#define幫一個數字或文字取名字。
伺服函式庫Servo.h控制伺服馬達的函式庫,attach()、write()。
編譯Compile把人看的程式翻譯成晶片看的機器碼。
編譯錯誤Compile Error程式語法有問題,IDE 會指出哪一行。
無效數值nan (Not a Number)浮點數「算不出來」的標記,DHT11 讀失敗會回傳它。
除錯Debug找出並修正程式或電路的錯誤。

附錄 G 電路符號對照表

本書的電路圖有兩種畫法:

  1. 文字示意圖(ASCII 圖):用鍵盤打得出來的符號畫,例如 ──[ 220Ω ]──►|── GND。好處是和接線說明放在一起,一眼看出誰接誰。
  2. 麵包板接線圖:彩色的實物圖,照著插就對了。

但是你以後查資料、看零件說明書、看別人的電路,會遇到標準電路符號。下面這張圖把三者對照起來:每格左上是零件名稱,右上是本書 ASCII 圖的寫法,中間是標準符號。

怎麼讀本書的 ASCII 圖

本書寫法意思標準符號怎麼畫備註
──、│、┬、┴、┼導線與分叉直線;有圓點的交叉才是相接本書 ASCII 圖的 ┼ 一律代表相接
[ 220Ω ]、[ R1 ]電阻鋸齒(美式)或長方形(國際式)方括號裡是阻值或代號,沒有方向性
[ 10kΩ 可變電阻 ]、「中間腳」可變電阻電阻加一個箭頭指向中間三隻腳:兩端是固定電阻,中間腳是滑動端
[ LDR ]光敏電阻電阻外加圓圈,兩個箭頭射進來光越亮,電阻越小
══╧══、══╤══電容兩條平行直線陶瓷電容沒有極性
│+ │− 標在 ══╧══ 旁電解電容一直線一弧線,直線是正極有極性,接反會爆
「線圈」、[ 1mH ]電感一串半圓本書多用文字標示
`──►──`二極體三角形加一條直線
`──►──` 旁邊寫 LED發光二極體二極體加兩個往外的箭頭
B ──┤ 配 C、ENPN 電晶體圓圈裡一條粗線,E 腳有箭頭朝外2N2222:平面朝自己,左到右 E、B、C
G ──┤ 配 D、SN 通道 MOSFET閘極和通道之間有一條縫(絕緣)IRLZ44N:左到右 G、D、S
9V +、9V −、Arduino 5V電池或直流電源長短線成對;長線是正極本書也用 USB 5V、3.3V 表示電源
GND接地三條越來越短的橫線電路的 0V 基準;圖上所有 GND 都是同一個點
[ 按鈕 ]、「開關」開關一條可以翹起來的線本書的按鈕是「按下才接通」
┌ 馬達 ┐ 或「馬達」直流馬達圓圈裡寫 M接電感的規則都適用(要加飛輪二極體)
「蜂鳴器」蜂鳴器半圓加兩條線無源蜂鳴器要給它頻率才會響
Arduino D9 ──板子的腳位方塊代表板子,拉一條線出來腳位名稱照板子上印的字
CH1 探棒接這裡 ───►量測點一個點,旁邊寫 CH1 或 V示波器的接地夾一律接 GND

三個看圖的習慣

  1. 先找電源和 GND。 電流從電源正極出發,繞一圈回到 GND。找不到回路,電路就不會動。
  2. 再找有方向性的零件。 二極體、LED、電解電容、電晶體接反了不是不動就是燒掉。看到 ►|、+、−、E/B/C 就停下來確認方向。
  3. 把圖和麵包板對起來。 圖上一條線代表「這些點是同一個電位」,在麵包板上就是同一列的五個孔,或是用一條杜邦線接起來。