本文へ移動
「読む」の0〜1023、
「書く」の0〜255。数字が違う理由。
analogRead()で読み取った値をそのままanalogWrite()に渡すと、なぜか動きがおかしい——これはArduinoを触り始めた人がほぼ必ず一度は通る疑問です。実はanalogReadとanalogWriteは、名前は似ていても扱っている数字の範囲がまったく違います。この記事では、センサー値が0〜1023で返ってくる仕組みから、電圧への換算、PWMという仕組みで0〜255の値を送り出すanalogWrite、そして2つの範囲をつなぐmap()関数まで、豊富な具体例を使って専門用語ゼロから徹底的に解説します。
analogReadとanalogWriteは正反対の役割
名前がよく似ているanalogRead()とanalogWrite()ですが、この2つは矢印の向きがまったく逆の命令です。
analogRead() = 読み取る
- センサーから「値をもらう」
- 矢印の向き:センサー → Arduino
- 返ってくる数字:0〜1023
- 使えるピン:A0〜A5などアナログ入力ピン
analogWrite() = 送り出す
- LEDやモーターに「値を渡す」
- 矢印の向き:Arduino → LED・モーター
- 渡す数字:0〜255
- 使えるピン:~マーク付きのPWM対応ピン
可変抵抗(つまみを回すと値が変わる部品)の回転量をanalogRead()で読み取り、その値をそのままanalogWrite()でLEDに渡す——という組み合わせは定番ですが、そのまま渡すと数字の範囲が合わずうまく動きません。この「範囲の違い」こそが、この記事全体を通じての最大のテーマです。
digitalReadやdigitalWrite、pinModeといった基本のI/O命令をすでに理解している方向けの内容です。基礎から確認したい場合はArduinoのコードの書き方(コピペ可20選)もあわせてご覧ください。
analogRead()の基本|0〜1023という数字の正体
analogRead(ピン番号)は、A0〜A5のようなアナログ入力ピンにかかっている電圧を測定し、その結果を0〜1023の整数で返してくれる命令です。なぜ0〜1023というキリの悪い数字なのか、順を追って見てみましょう。
例1:可変抵抗の値を読み取ってみる
const int POT_PIN = A0; // 可変抵抗の信号線をA0に接続
void setup() {
Serial.begin(9600);
}
void loop() {
int value = analogRead(POT_PIN);
Serial.println(value); // つまみを回すと、0〜1023の間で数字が変わる
delay(100);
}
つまみを左いっぱいに回すと0付近、右いっぱいに回すと1023付近の数字がシリアルモニタに表示されます。真ん中あたりでは、だいたい500前後の数字になります。
例2:センサーの種類が違っても、返ってくる数字の形は同じ
int lightValue = analogRead(A0); // 光センサー:明るいほど数字が変わる
int pressureValue = analogRead(A1); // 圧センサー:押す強さで数字が変わる
int muscleValue = analogRead(A2); // 筋電センサー:筋肉の活動量で数字が変わる
// センサーの種類が違っても、analogRead()が返す形(0〜1023)は共通
光センサーでも圧センサーでも筋電センサーでも、analogRead()が返してくる数字の「形」はいつも0〜1023です。センサーごとに「暗い時は数字が小さい」「強く押すと数字が大きい」といった意味づけが変わるだけで、命令の使い方自体は共通しています。センサーの種類ごとの特徴はArduino用センサー完全ガイド16選で詳しく比較しています。
正式な仕様は、Arduino公式のanalogRead()言語リファレンス ↗で確認できます。
0〜1023を実際の電圧(ボルト)に変換する
analogRead()が返す0〜1023という数字は、それ自体では「電圧」ではありません。あくまで「0〜1023段階のうちの何番目か」という順位のようなものです。これを実際の電圧(ボルト)に直すには、簡単な計算が必要です。
Arduino Uno / Nanoの基準電圧は標準で5Vです。0〜1023の1024段階で0〜5Vを表しているので、「今の値 ÷ 1023 × 5」という計算で、実際の電圧に変換できます。
例3:センサー値を電圧(ボルト)に変換して表示する
const int SENSOR_PIN = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int rawValue = analogRead(SENSOR_PIN); // 0〜1023の生の値
float voltage = rawValue * (5.0 / 1023.0); // 電圧(ボルト)に変換
Serial.print("生の値: ");
Serial.print(rawValue);
Serial.print(" / 電圧: ");
Serial.print(voltage);
Serial.println(" V");
delay(200);
}
| analogRead()の値 | 計算式 | 電圧(約) |
|---|---|---|
| 0 | 0 ÷ 1023 × 5 | 0.00 V |
| 512 | 512 ÷ 1023 × 5 | 2.50 V |
| 1023 | 1023 ÷ 1023 × 5 | 5.00 V |
5.0や1023.0のように小数点を付けているのがポイントです。もし5 / 1023のように整数だけで計算すると、割り算の結果が0になってしまい(int型の割り算は小数点以下を切り捨てるため)、正しい電圧が求まりません。小数を扱いたい計算では、必ずどこかに小数点を含めておきましょう。0〜1023という数字のままでも動作の判定(しきい値判定など)には十分使えますが、電圧という「誰が見ても意味の分かる単位」に変換しておくと、センサーのデータシート(仕様書)に書かれた数値と見比べたり、他の人にデータを説明したりする時に扱いやすくなります。
analogWrite()の基本|PWMと0〜255の意味
analogWrite(ピン番号, 値)は、LEDの明るさやモーターの速さを、0(完全にオフ)から255(完全にオン)までの256段階で指定できる命令です。ここで大きな疑問が出てきます。「Arduinoの出力はHIGH(5V)かLOW(0V)の2択のはずなのに、なぜ中間の明るさを出せるのか?」——その答えがPWMです。
例4:PWMのイメージを図で見る
下の図は、同じ長さの時間の中で「オン(点灯)」の割合をどれだけ増やすかを表したイメージです。オンの時間が長いほど、LEDは明るく(あるいはモーターは速く)感じられます。
オレンジ色の部分が「オン」、グレーの部分が「オフ」の時間です。analogWrite(127)はほぼ半分がオンなので、見た目には「約半分の明るさ」に感じられます。この考え方は、Arduino公式の「Basics of PWM」↗でも図解付きで説明されています。
例5:LEDの明るさを0〜255で指定する
const int LED_PIN = 9; // ~マークの付いたPWM対応ピンを使う
void setup() {
// analogWrite()を使う時はpinMode()を省略してもOK
}
void loop() {
analogWrite(LED_PIN, 64); // 弱め(約25%の明るさ)
delay(1000);
analogWrite(LED_PIN, 191); // 強め(約75%の明るさ)
delay(1000);
}
analogWrite()はどのピンでも使えるわけではありません。Arduino Unoの場合、ボード上に~(チルダ)マークが付いている3・5・6・9・10・11番ピンだけがPWMに対応しています。マークのないピンにanalogWrite()を使っても、意図した中間の明るさは出せません。
正式な仕様は、Arduino公式のanalogWrite()言語リファレンス ↗で確認できます。
比較表:analogReadとanalogWriteの違いまとめ
ここまでの内容を、一覧表に整理しておきましょう。迷ったらこの表に戻ってくると、頭の中が整理しやすくなります。
| 項目 | analogRead() | analogWrite() |
|---|---|---|
| 役割 | 値を「読み取る」 | 値を「送り出す」 |
| 数字の範囲 | 0〜1023(1024段階) | 0〜255(256段階) |
| 使えるピン | A0〜A5などアナログ入力ピン | ~マーク付きのPWM対応ピン |
| 仕組み | 電圧をADC(アナログ-デジタル変換回路)で測定 | PWM(高速なオン・オフの繰り返し) |
| pinModeの要否 | 基本的に不要(入力扱いされる) | 省略しても動作するが、明示してもよい |
| 典型的な用途 | 可変抵抗、光センサー、圧センサー、筋電センサーなど | LEDの明るさ調整、モーターの速度調整 |
「analog」という名前が付いていても、内部で扱っている実体はどちらも0か1(デジタル)の組み合わせです。analogReadは電圧を細かい段階のデジタル数値に変換して読み取り、analogWriteは高速なオン・オフの組み合わせ(PWM)でアナログらしい効果を作り出しています。どちらも「デジタルの仕組みで、アナログの世界を扱う工夫」という点では共通しています。
map()関数で範囲を変換する
ここまでで、analogReadは0〜1023、analogWriteは0〜255という、異なる範囲の数字を扱うことが分かりました。では、センサーで読み取った0〜1023の値を、そのままLEDの明るさ(0〜255)として使いたい時はどうすればいいでしょうか。ここで登場するのがmap()関数です。
map()の書き方
map(変換したい値, 変換前の最小, 変換前の最大, 変換後の最小, 変換後の最大)
「変換前の範囲でこの値だったら、変換後の範囲では何番目に相当するか」を自動で計算してくれる命令です。
例6:0〜1023を0〜255に変換する
const int SENSOR_PIN = A0;
const int LED_PIN = 9;
void loop() {
int sensorValue = analogRead(SENSOR_PIN); // 0〜1023
int ledValue = map(sensorValue, 0, 1023, 0, 255); // 0〜255に変換
analogWrite(LED_PIN, ledValue);
}
| sensorValue(0〜1023) | map()後のledValue(0〜255) |
|---|---|
| 0 | 0 |
| 512 | 約128 |
| 1023 | 255 |
例7:範囲を反転させる(値を逆にする)
// 変換後の範囲を逆順に書くと、値の大小関係も反転する
int ledValue = map(sensorValue, 0, 1023, 255, 0);
// sensorValueが大きいほど、ledValueは小さくなる(値の大小関係を逆にしたい場合に使う)
例えば「センサー値が大きいほどLEDを暗くしたい」「つまみを右に回すほどモーターを遅くしたい」といった、直感とは逆向きの反応をさせたい場合にこの書き方が役立ちます。
map()は小数を扱わず、整数だけで計算します。そのため、割り切れない計算では小数点以下が切り捨てられます。0〜1023を0〜255に変換するような大まかな用途では問題になりませんが、より正確な計算が必要な場面では注意してください。詳しい仕様はArduino公式のmap()言語リファレンス ↗にまとまっています。
実践コード:センサー値でLEDの明るさを連続的に変える
最後に、ここまで学んだ内容をすべて組み合わせた実践的なコードを見てみましょう。センサーの値を読み取り、電圧としてシリアルモニタに表示しつつ、同じ値をmap()で変換してLEDの明るさとして反映させます。
const int SENSOR_PIN = A0; // 可変抵抗や光センサーなど
const int LED_PIN = 9; // ~マーク付きのPWM対応ピン
void setup() {
Serial.begin(9600);
}
void loop() {
// 1. センサー値を読み取る(0〜1023)
int sensorValue = analogRead(SENSOR_PIN);
// 2. 参考用に電圧へ変換して表示する
float voltage = sensorValue * (5.0 / 1023.0);
// 3. LEDの明るさ用に0〜255へ変換する
int brightness = map(sensorValue, 0, 1023, 0, 255);
// 4. LEDの明るさに反映する(PWM出力)
analogWrite(LED_PIN, brightness);
// 5. 状態をシリアルモニタで確認する
Serial.print("センサー値: ");
Serial.print(sensorValue);
Serial.print(" / 電圧: ");
Serial.print(voltage);
Serial.print("V / LED明るさ: ");
Serial.println(brightness);
delay(100);
}
握力や圧力をセンサーで読み取ってゲーム化する応用例はリアルタイム握力計測ゲームのコード解説 ↗、センサー値の変化に応じてLEDの色を変える作例はセンサーで色が変わる電子工作 ↗で詳しく紹介しています。配線に不安がある場合はブレッドボード完全攻略ガイドもあわせてご確認ください。
よくある間違い・注意点
analogReadの値をそのままanalogWriteに渡してしまう。0〜1023の値を0〜255の命令にそのまま渡すと、255を超えた分は無視されたり、意図しない明るさになったりします。必ずmap()などで範囲を合わせましょう。
analogWriteをPWM非対応のピンに使ってしまう。~マークのないピンでは、中間の明るさが正しく出ません。ボードのピン配置図で対応ピンを確認してください。
電圧計算で整数同士の割り算をしてしまう。5 / 1023のように整数だけで書くと結果が0になります。5.0 / 1023.0のように小数点を含めましょう。
analogReadをデジタルピンに使ってしまう。A0〜A5のようなアナログ入力ピン以外では使用できません。
map()の変換前・変換後の範囲を書き間違える。特に3番目と4番目(変換前の最小・最大)、5番目と6番目(変換後の最小・最大)を混同しないよう、コメントを付けておくと安心です。
FAQ・まとめ
analogRead()とanalogWrite()は何が違うのですか?
analogRead()はセンサーなどから「値を読み取る」命令で、0〜1023の1024段階で返ってきます。analogWrite()はLEDやモーターへ「値を送り出す」命令で、0〜255の256段階でPWMという方式の信号を出力します。読み取りと書き込みで、扱う数字の範囲も向きも逆になる点が最大の違いです。
analogRead()の値はどのピンでも使えますか?
いいえ。analogRead()はA0〜A5のようなアナログ入力ピンでのみ使えます。デジタルピン(0〜13など)では使用できません。一方analogWrite()は、ボード上で~マークが付いたPWM対応のデジタルピンでのみ使用でき、Arduino Unoでは3・5・6・9・10・11番ピンが該当します。
PWMは本当にアナログ電圧を出しているのですか?
厳密には違います。PWMはHIGHとLOWを非常に高速に切り替えているだけで、実際に中間の電圧が出ているわけではありません。しかし人の目やモーター、LEDにとっては、その高速な点滅の「オンの時間の割合」が、あたかも中間の電圧であるかのように感じられます。これが擬似的なアナログ出力と呼ばれる理由です。
map関数を使えば必ず正確な値になりますか?
map()は整数(int)だけで計算するため、小数点以下は切り捨てられます。0〜1023を0〜255に変換するような大まかな範囲変換では問題になりませんが、正確な小数の計算が必要な場面では誤差が出ることがあるため、必要に応じてfloat型での計算に置き換えることも検討してください。
analogRead()とanalogWrite()は、名前は似ていても「読む」と「書く」という正反対の役割を持ち、扱う数字の範囲も0〜1023と0〜255でまったく違います。この違いさえ体に染みつけば、センサーの値をLEDやモーターに反映させる工作は驚くほどスムーズになります。まずは7章の実践コードを実際に書き換えて、センサー値・電圧・LEDの明るさが連動して変化する様子を、その目で確かめてみてください。
コメント