{{ 'fb_in_app_browser_popup.desc' | translate }} {{ 'fb_in_app_browser_popup.copy_link' | translate }}
{{ 'in_app_browser_popup.desc' | translate }}
歡迎光臨瑪可希維,本站商品皆為台灣現貨、含稅可打統編
在前兩篇中,你已經學會讓 Arduino 成功連線、上傳程式,並控制板載 LED 閃爍。這一篇要更進一步,讓 Arduino 不只是「發出訊號」,而能「讀懂環境變化」。
我們會使用 LM393 光敏模組 這個常見的入門感測器,學習如何讓 Arduino 讀取明暗變化(數位輸入),並控制 LED 反應(數位輸出)。這個過程會用到兩個非常重要的函式:digitalRead() 與 digitalWrite()。
完成本篇後,你將能:
Arduino 程式範例:LM393光敏模組讀取光線並控制LED
在 Arduino 的世界裡,所有「互動」都從這兩件事開始:
輸入(Input)代表「接收訊號」,例如按鈕被按下、光線變亮。
輸出(Output)代表「發送訊號」。例如讓燈亮、蜂鳴器響、馬達轉。
這是感測器與控制元件之間的語言,幾乎每個專案都會用到。
可以想成 Arduino 是一個「判斷盒」,外界把訊號丟進來(輸入)→ Arduino 判斷 → 再把指令送出去(輸出)。而這就是每個感測器專案的基本流程。
Arduino 的板子上有一排「Digital」字樣的接腳,這些就是數位腳位(Digital Pins)。就像一排「可以自己開關的插座」。
每個腳位都能做兩件事:
而數位腳位只認得兩種狀態:
| 狀態 | 電位 | 意思 | 舉例 |
|---|---|---|---|
| HIGH | 有電(約 5V 或 3.3V) | 表示「打開」「偵測到」 | LED 亮、按鈕被按下 |
| LOW | 沒電(0V) | 表示「關閉」「未偵測到」 | LED 滅、按鈕放開 |
數位腳位是 Arduino 跟外界溝通的「開關孔」,可以選擇「自己發電」(輸出)或「去感應」(輸入)。
小提醒:數位腳位只有兩種狀態:「0=沒電」「1=有電」。跟它不同,類比腳位可以量到「中間程度」的強弱,會用數字表示(0~1023)。你看到的 512 就是「大約一半強度」,768 則是「比一半再強一些」。本篇主要介紹數位開/關;類比「強弱多少」的細節,我們會在後續章節再完整補充。
digitalRead() 與 digitalWrite() 是什麼?當你要讓 Arduino 操作這些腳位時,就會用到兩個最基本的指令:
digitalRead() 與 digitalWrite()
簡單的來說可以這樣記
digitalRead() 是「耳朵」,用來聽訊號 = 我接收訊號(感受世界)
digitalWrite() 是「手」,用來執行動作 = 我發出訊號(控制別人)
| 指令 | 用途 | 白話解釋 | 範例 |
digitalWrite(pin, HIGH/LOW) | 輸出訊號 | 「我讓這個腳位有電或沒電」 | 讓 LED 亮或滅 |
digitalRead(pin) | 讀取訊號 | 「我去看這個腳位現在有沒有電」 | 判斷按鈕有沒有被按下 |
而這兩個指令要搭配 pinMode() 使用。先用 pinMode(pin, OUTPUT) 或 pinMode(pin, INPUT) 指定腳位方向,
再依用途選擇讀或寫。告訴 Arduino 這個腳位是要「讀」還是「寫」:
| pinMode(2, INPUT); // 宣告第 2 腳是輸入(感測器) pinMode(13, OUTPUT); // 宣告第 13 腳是輸出(LED) |
| int sensor = digitalRead(2); // 讀取感測器訊號 if (sensor == HIGH) { digitalWrite(13, HIGH); // 亮燈 } else { digitalWrite(13, LOW); // 滅燈 } |
Arduino 先「聽」外界(read),再「想」要不要動作(if 判斷),最後「做」出反應(write)。
整個過程是一個訊號進出循環(Input → Process → Output)。
可以從以下步驟想像訊號流動的方向:
舉三個常見的例子:
LED 控制(數位輸出)
digitalWrite(13, HIGH); → LED 亮
digitalWrite(13, LOW); → LED 滅
按鍵偵測(數位輸入)
if (digitalRead(2) == HIGH) → 代表按鍵被按下
if (digitalRead(3) == LOW) → 偵測到光線變亮
把 Arduino 當成一個「判斷盒」的概念後,就可以執行:
輸入訊號(光、聲、溫度) → 經過程式判斷 → 執行對應輸出(亮燈、發聲、轉動)。
理解了數位腳位的概念後,接下來我們就用 LM393 光敏模組 來實際操作一次, Arduino 如何透過「數位輸入」讀取光線變化,並用「數位輸出」控制 LED 反應,讓抽象的「輸入與輸出」變成可以親眼看到的互動結果。
LM393 光敏模組是一個常見的光線感測器模組,能根據環境明暗變化,輸出「有電(HIGH)」或「沒電(LOW)」的訊號給 Arduino。
它的特點是已內建比較器電路,不需要自己處理複雜的電壓判斷,非常適合初學者。
延伸閱讀:比較器(Comparator)是一種用來比較兩個電壓高低的電路。當感測端的電壓高於設定的參考電壓時,輸出 HIGH;反之則輸出 LOW。LM393 模組就是利用這個原理,將光敏電阻感測到的亮度變化轉換成「亮」或「暗」兩種數位訊號給 Arduino。
這個模組主要由三個部分組成:
| 組成部分 | 功能說明 |
|---|---|
| 光敏電阻(LDR) | 會隨光線強度改變阻值。光越亮,阻值越小;光越暗,阻值越大。 |
| LM393 比較器晶片 | 負責比較光敏電阻與可調電位器之間的電壓差,輸出 HIGH 或 LOW。 |
| 可調電位器(旋鈕) | 用來設定光線判斷的臨界值,決定在多亮的情況下輸出改變。 |
讀取感測器 DO 腳的電壓(HIGH/LOW)。
若是 HIGH(亮)→ 輸出 HIGH 給 LED。
若是 LOW(暗)→ LED 熄滅。
將模組放在明亮處 LED 會亮,遮住光敏電阻 LED 會滅。(部分廠牌邏輯可能反向,即明亮處LED熄滅)
若不靈敏或不觸發可透過旋轉電位器微調感測閾值。
為了清楚看到感測器輸出的狀態,可以透過 序列監控視窗(Serial Monitor) 顯示當前讀值。
const int sensorPin = 2; const int ledPin = 13; void setup() { pinMode(sensorPin, INPUT); pinMode(ledPin, OUTPUT); Serial.begin(9600); // 開啟序列埠監控, 鮑率設定為 9600 } void loop() { int sensorValue = digitalRead(sensorPin); Serial.print("感測器狀態 : "); Serial.println(sensorValue); // 顯示 0 (LOW) 或 1 (HIGH) if (sensorValue == HIGH) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } delay(200); // 每 0.2 秒更新一次 }
在 工具 → 序列監控視窗 開啟後,會看到輸出 0 或 1。
1 代表模組輸出 HIGH(亮),0 代表輸出 LOW(暗)。這樣可以更容易判斷模組反應是否正確。
不同品牌的 LM393 模組在亮/暗判斷上可能反向,若你想在「訊號為LOW時亮燈」而不是「訊號為HIGH時亮燈」,只要在判斷式裡反轉條件即可:
if (sensorValue == LOW) { digitalWrite(ledPin, HIGH); // 光線暗 → LED 亮 } else { digitalWrite(ledPin, LOW); // 光線亮 → LED 滅 }
若反應不靈敏或觸發太頻繁,轉動模組上的藍色電位器可改變亮度判斷臨界值。
順時針轉 → 提高靈敏度;逆時針轉 → 降低靈敏度(依模組設計略有差異)。
這三個階段的練習中,你會循序理解整個 Arduino 的輸入與輸出流程。
學習重點回顧:
第 1 階段學會「讓它動起來」;
第 2 階段看懂「它在讀什麼」;
第 3 階段則能「控制它怎麼反應」。
完整流程:光線變化 → LM393 DO 輸出 HIGH/LOW → Arduino 讀取 → 判斷 → LED 亮或滅。
在實際操作 LM393 光敏模組時,若 LED 沒反應或讀值異常,通常不是模組壞掉,而是幾個常見的接線或設定問題。
以下整理出最容易踩到的三類狀況與對應檢查方向。
| 問題現象 | 可能原因 | 檢查與解決方式 |
|---|---|---|
| LED 不亮或一直亮 | 腳位接錯或沒有共地 | 確認 DO 腳接的是數位腳(如 D2),且模組與 Arduino 的 GND 一定要相連。 |
| 讀值亂跳、不穩定 | 沒共地或環境光干擾 | 檢查共地是否確實接好,並嘗試在模組 VCC 與 GND 間加上電容(100nF~10µF),或調整電位器靈敏度。 |
| 序列監控顯示數值固定不變 | 感測器方向錯/旋鈕設定錯 | 確認光敏電阻朝向光源,嘗試轉動藍色旋鈕調整臨界值,直到輸出在亮/暗之間能切換。 |
| 上傳成功但沒有反應 | 腳位未設定正確 | 檢查程式中的 sensorPin 和實際接線腳位是否一致(常見錯接成 A0 或 D0)。 |
當你遇到Arduino 專案有問題時,我們會建議先從「電」與「線」開始排查。
所以如果不確定問題來自程式還是接線,可以先上傳 Blink 範例測試板子,再用 Serial Monitor 檢查感測值是否有變化。
把「讀 → 判斷 → 寫」用在更多元件上,就能做出更多小專案。下面列三個延伸方向,範例可以沿用本篇接線(DO→D2、LED→D13),只需要多接 1–2 個元件即可上手。
// LM393 : D0→D2 ; Buzzer(主動)→D8 const int sensorPin = 2; const int buzzerPin = 8; void setup() { pinMode(sensorPin, INPUT); pinMode(buzzerPin, OUTPUT); } void loop() { bool isDark = (digitalRead(sensorPin) == LOW); // 若你的模組相反,改成 == HIGH digitalWrite(buzzerPin, isDark ? HIGH : LOW); }
這段程式碼加入了一個新的硬體元件:蜂鳴器 (Buzzer)。
並且把蜂鳴器連接到 buzzerPin (設定為 D8),控制的對象從 ledPin 改成了 buzzerPin:當光線暗 (LOW) 時,蜂鳴器會響起 (HIGH)。
小提醒:主動蜂鳴器可直接 HIGH/LOW 控制;被動蜂鳴器可改用
tone(buzzerPin, 2000); noTone(buzzerPin);。
digitalWrite() 不再只是只能做單純的開關動作,也可以是閃爍的效果。
// LM393 : D0 → D2 (輸入) // LED : → D9 const int sensorPin = 2; const int ledPin = 9; const int ledFreq = 10; // 閃爍頻率(毫秒) void setup() { pinMode(sensorPin, INPUT); // 感測器輸入 pinMode(ledPin, OUTPUT); // LED PWM 輸出 } void loop() { // LOW=暗、HIGH=亮 (若相反, 改判斷式或調電位器) if (digitalRead(sensorPin) == LOW) { // 暗 → 閃爍,可以透過更改閃爍頻率參數變更閃爍的頻率 digitalWrite(ledPin, HIGH); delay(ledFreq); digitalWrite(ledPin, LOW); delay(ledFreq); } else { // 亮 → 停止 digitalWrite(ledPin, LOW); } }
// 雙模件:LM393(光) + HC-SR04 (距離) const int sensorPin = 2; // LM393 D0 → D2 const int trigPin = 9; // HC-SR04 Trig → D9 const int echoPin = 10; // HC-SR04 Echo → D10 const int ledPin = 13; // 警示輸出 (可改蜂鳴器腳) long readDistanceCm() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); unsigned long dur = pulseIn(echoPin, HIGH, 30000UL); // 最長等 30ms = 5m if (dur == 0) return 9999; // 無回波視為很遠 return (dur * 0.0343) / 2; // 時間→距離 (公分) } void setup() { pinMode(sensorPin, INPUT); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(ledPin, OUTPUT); } void loop() { bool isDark = (digitalRead(sensorPin) == LOW); // 依你的模組, LOW=暗 long dist = readDistanceCm(); digitalWrite(ledPin, (isDark && dist < 20) ? HIGH : LOW); // 暗且近→啟動警示 delay(50); // 簡單節流, 避免過於頻繁觸發 }
到這裡,你已經已完成
接線(VCC/GND/DO)→ 設定腳位(pinMode)→ 讀取輸入(digitalRead)→ 判斷(if)→ 輸出控制(digitalWrite)→ LED 亮/滅。LM393 的 DO 為數位輸出,只回傳 HIGH/LOW;行為可在程式中反轉,靈敏度透過電位器調整。
若遇到異常,先檢查「共地是否確實相連」、「DO 是否接到數位腳」與「在 Serial Monitor 中,讀值是否會隨明暗變化」。
analogWrite() 做簡單的漸亮/漸暗,體驗「類比輸出(模擬)」帶來的效果差異。delay() 改成 millis() 的非阻塞寫法,避免卡住迴圈(之後要加蜂鳴器或顯示器時會更穩)。資訊可視化: 加上 I2C LCD(或序列監控)顯示「Bright/Dark」、「最後變化秒數」,練習字串與變數輸出。
| 【撰文編修/瑪可希維編輯部】 Lisette 、Jhin 【監修/瑪可希維站長】 瑪可 |