光感應
讀一個「有很多種可能」的值。 · ⏱ 約 30 分鐘
你會學到三件事
analogRead 讀到的不是兩種值,是 0 到 1023
map 把一個範圍換算成另一個範圍
- 感測器讀到的數字沒有單位——單位是你給的
開始之前
上一課的按鈕只有兩種答案。而光線是連續的——它可以是任何亮度。
接線:光敏電阻一腳接 A0、一腳接 5V,A0 再用一顆 10kΩ 電阻接 GND。
(這叫分壓電路——它把「電阻變化」變成「電壓變化」,因為板子只讀得懂電壓。)
一、0 到 1023
int raw = analogRead(A0);
|
範圍 |
digitalRead |
兩種:HIGH / LOW |
analogRead |
1024 種:0 到 1023 |
為什麼是 1023?和上一課同一個理由——10 個位元,2¹⁰ = 1024 種值。
⚠️ 只有 A0 到 A5 這幾支腳可以。 一般數位腳沒有這個能力。
⚠️ analogRead 的腳不用 pinMode。
二、那個數字是什麼意思?
它什麼意思都沒有。
analogRead 回報的是「這支腳上的電壓,佔滿格的幾分之幾」。
它不是「幾勒克斯」、不是「幾度」——它只是一個比例。
感測器給你的是原始讀數,意義是你賦予的。
要變成「亮度」或「溫度」,你得自己換算——而換算要靠實測。
所以第一步永遠是:印出來看看。
Serial.println(raw);
用手遮住感測器、拿燈照它,看那個數字怎麼變。先觀察,再寫邏輯。
三、map:把範圍換掉
讀到的是 0~1023,而 analogWrite 要的是 0~255。差 4 倍。
int level = map(raw, 0, 1023, 0, 255);
讀法:「把 raw 從 0~1023 這個範圍,換算到 0~255」。
raw 0 ────────────────── 1023
level 0 ────────────────── 255
⚠️ map 用的是整數除法(C++ 入門第 5 課那件事),所以會有一點誤差。
map(500, 0, 1023, 0, 255) 得到 124 而不是 124.6。
⚠️ 而 map 不會幫你把值夾在範圍內。輸入超出去的話輸出也會超出去,
要夾住得用 constrain。
四、接起來
int raw = analogRead(A0);
int level = map(raw, 0, 1023, 0, 255);
Serial.println(level);
analogWrite(9, level);
越暗,燈越亮——一個會自己調整的夜燈。
⚠️ 而方向對不對取決於你怎麼接線。反了的話,把 map 的後兩個數字對調:
map(raw, 0, 1023, 255, 0)。
完成的樣子
void setup() {
Serial.begin(9600);
pinMode(9, OUTPUT);
}
void loop() {
int raw = analogRead(A0);
int level = map(raw, 0, 1023, 0, 255);
Serial.println(level);
analogWrite(9, level);
delay(200);
}
換你了
先只印 raw,用手遮住感測器,記下最暗和最亮的實際數字
(多半不是 0 和 1023,可能是 200 和 800)。
然後把 map 的前兩個數字換成你量到的——畫面會靈敏很多。
這就是「校正」。規格書寫的範圍,和你桌上這一顆的範圍,不一樣。
這一課你做了什麼
- 你用
analogRead 讀到了 0~1023 的連續值
- 你用
map 把它換算到另一個範圍
- 你知道感測器的讀數沒有單位,而校正要靠實測
如果卡住了
| 你看到 |
多半是因為 |
| 一直是 0 或一直是 1023 |
接線問題——分壓電阻沒接,或接到 5V/GND 短路了 |
| 數字跳來跳去 |
正常。類比讀數本來就會抖,可以多讀幾次取平均 |
analogRead(9) 得到 0 |
9 號腳不是類比輸入。要用 A0~A5 |
| 越亮燈越亮(想要相反) |
把 map 的後兩個數字對調 |
在編輯器打開這一課 →