Arduinoで複数センサーを同時に使う方法|値の取得・配列・タイミング制御
センサー1つなら簡単に動かせても、2つ、3つと増えていくと、とたんにコードがぐちゃぐちゃになったり、動きがおかしくなったりしませんか?本記事では、複数のセンサーを無理なく同時に扱うための「値の取得方法」「配列での管理」「delay()を使わないタイミング制御」のコツを、子供でもわかるように、ひとつずつ丁寧に解説していきます。
🔧 この記事でわかること
気になる項目から読んでも大丈夫です。
- Arduinoの「同時」の本当の仕組み → 1章へ
- 配列を使ったセンサー値の一元管理 → 2章へ
- 複数のアナログセンサーを読む実践コード → 3章へ
- 複数のデジタルセンサーを読む実践コード → 4章へ
- delay()を使わないタイミング制御 → 5章へ
- 配線・電源の注意点 → 6章へ
- 同じI2Cセンサーを複数つなぐ方法 → 7章へ
01大前提:Arduinoの「同時」は超高速の「順番」
複数センサーを扱う前に、まず知っておきたい、Arduinoの内部の仕組みです。

Arduino UNOは、アナログの値を読み取る「物差し」を、実は1本しか持っていません(これをADC=アナログ・デジタル変換器と呼びます)。A0、A1、A2…という複数のアナログピンがあっても、裏側ではこの1本の物差しを、ものすごい速さで順番に使い回しているのです。1回測るのにかかる時間は、わずか約100マイクロ秒(1万分の1秒)。人間の目には同時に見えますが、実際には「超高速の順番待ち」が起きています。
| 読み取り方法 | 1回あたりの時間 | 特徴 |
|---|---|---|
analogRead() |
約100マイクロ秒 | 内部のADC1つを複数ピンで共有しているため、この時間が必ずかかる |
digitalRead() |
1マイクロ秒未満 | ON/OFFの判定だけなので、ADCを使わず非常に高速 |
センサーが3つ、4つと増えても、1つあたり約100マイクロ秒程度なので、合計しても1ミリ秒に満たないことがほとんどです。つまり、「複数のアナログセンサーを順番に読む」こと自体は、速度の面ではほとんど問題になりません。本当に気をつけるべきなのは、この後に説明する「delay()を使った待ち時間」や「配線・電源」の方です。
ただし例外もあります。超音波距離センサー(HC-SR04など)で使うpulseIn()という関数は、電気信号が戻ってくるまで数十〜数万マイクロ秒、プログラムの実行を止めて待ち続けます。こうした「待たされる」命令が混ざっている場合は、後述する5章のタイミング制御がとても重要になります。
02配列(array)でセンサー値を一元管理する
センサーが増えるほど、変数をバラバラに管理すると大変になります。そこで役立つのが「配列」です。

配列(array)は、同じ種類の箱を、番号付きでまとめて並べた「ロッカー」のようなものです。
int sensorValues[3];と書くと、「0番・1番・2番」という3つの箱(ロッカー)がまとめて用意されます。センサーが1個増えるたびに新しい変数名(sensor1, sensor2, sensor3…)を考える必要がなくなり、「for文」を使って全部の箱に一気にアクセスできるようになります。
変数を個別に書く場合(センサーが増えると大変)
// センサーが3つあると、変数も3つ必要
int sensorValueA0 = analogRead(A0);
int sensorValueA1 = analogRead(A1);
int sensorValueA2 = analogRead(A2);
Serial.print(sensorValueA0);
Serial.print(",");
Serial.print(sensorValueA1);
Serial.print(",");
Serial.println(sensorValueA2);
配列を使う場合(センサーが増えても書き方は変わらない)
// 使うピンの一覧を配列にまとめる
const int sensorPins[] = {A0, A1, A2};
const int NUM_SENSORS = 3; // センサーの数
int sensorValues[NUM_SENSORS]; // 読み取った値を入れる箱(ロッカー)
void setup() {
Serial.begin(9600);
}
void loop() {
// for文で全センサーを順番に読み取る
for (int i = 0; i < NUM_SENSORS; i++) {
sensorValues[i] = analogRead(sensorPins[i]);
}
// まとめて表示する
for (int i = 0; i < NUM_SENSORS; i++) {
Serial.print(sensorValues[i]);
if (i < NUM_SENSORS - 1) Serial.print(",");
}
Serial.println();
delay(200);
}
このコードの良いところは、センサーを4つ、5つに増やしたいときも、sensorPins[]の中身とNUM_SENSORSの数字を変えるだけで済む点です。for文の中身を書き直す必要はありません。センサーの種類が増えても、管理すべき場所が1箇所に集約されるため、バグも減らせます。
03複数のアナログセンサーを同時に読む
実際によく使われる、複数のアナログセンサーの組み合わせで試してみましょう。

1センサーを選ぶ・配線する
例として、CdS光センサー(明るさ)、可変抵抗(ボリューム)、土壌湿度センサーの3つを、それぞれA0・A1・A2につなぐ構成を考えます。アナログセンサーの多くは「信号線をアナログピンへ、+を5Vへ、-をGNDへ」という共通の配線パターンです。
2配列で一括読み取り
2章で紹介した配列の書き方をそのまま使い、3つのセンサーをまとめて読み取ります。
const int sensorPins[] = {A0, A1, A2};
const char* sensorNames[] = {"明るさ", "ボリューム", "土壌湿度"};
const int NUM_SENSORS = 3;
int sensorValues[NUM_SENSORS];
void setup() {
Serial.begin(9600);
}
void loop() {
for (int i = 0; i < NUM_SENSORS; i++) {
sensorValues[i] = analogRead(sensorPins[i]);
}
for (int i = 0; i < NUM_SENSORS; i++) {
Serial.print(sensorNames[i]);
Serial.print(": ");
Serial.print(sensorValues[i]);
Serial.print(" ");
}
Serial.println();
delay(300);
}
名前の配列(
sensorNames[])も一緒に用意しておくと、シリアルモニタに「明るさ: 512」のように、何の値かひと目でわかる形で表示できます。センサーが増えても、どの数字がどのセンサーのものか迷わなくなる、小さな工夫です。
04複数のデジタルセンサーを同時に読む
タクトスイッチや人感センサーなど、ON/OFFのデジタルセンサーを複数扱う場合も、考え方は同じです。

const int switchPins[] = {2, 3, 4}; // タクトスイッチ3個
const int NUM_SWITCHES = 3;
int switchStates[NUM_SWITCHES];
void setup() {
Serial.begin(9600);
for (int i = 0; i < NUM_SWITCHES; i++) {
pinMode(switchPins[i], INPUT_PULLUP); // 内部プルアップ抵抗を使う
}
}
void loop() {
for (int i = 0; i < NUM_SWITCHES; i++) {
switchStates[i] = digitalRead(switchPins[i]);
}
for (int i = 0; i < NUM_SWITCHES; i++) {
// INPUT_PULLUPは「押すとLOW」になる点に注意
Serial.print(switchStates[i] == LOW ? "押されている" : "離されている");
Serial.print(" ");
}
Serial.println();
delay(50);
}
INPUT_PULLUPを使うと、スイッチにつなぐ配線を1本減らせる(抵抗を別途用意しなくて済む)便利な設定です。ただし、ボタンを「押したとき」に電気の値がLOW(0)になるという、直感とは逆の動きをする点に注意してください。慣れないうちは混乱しやすいポイントです。
digitalRead()はADCを使わないため、1章で説明した「順番待ち」のロスがほとんどありません。タクトスイッチやPIR人感センサー(HC-SR501)のようなON/OFFセンサーなら、何個増やしても速度面の心配はほぼ不要です。
05delay()を使わないタイミング制御
複数センサーを扱うときに、もっともつまずきやすいのが「タイミング制御」です。ここが本記事の核心です。

delay(1000)と書くと、Arduinoはその1000ミリ秒(1秒)の間、他のことを一切できなくなります。たとえ話で言うと、「1人の店員さんが、1人のお客さんの対応に1分間、完全に付きっきりになる」ようなイメージです。その間、他のお客さん(他のセンサー)は、ずっと無視されたままになってしまいます。
温度センサーは2秒に1回、光センサーは0.5秒に1回、距離センサーは0.1秒に1回……のように、センサーごとに「ちょうどいい確認頻度」が違うことはよくあります。それぞれにdelay()を使うと、合計の待ち時間が足し算されてしまい、全体の反応がどんどん遅くなります。この問題を解決するのが、millis()という「経過時間を測る関数」を使った書き方です。
millis()を使った非ブロッキング(止まらない)タイミング制御
unsigned long lastTempRead = 0;
unsigned long lastLightRead = 0;
unsigned long lastDistanceRead = 0;
const unsigned long TEMP_INTERVAL = 2000; // 2秒ごと
const unsigned long LIGHT_INTERVAL = 500; // 0.5秒ごと
const unsigned long DISTANCE_INTERVAL = 100; // 0.1秒ごと
void loop() {
unsigned long now = millis(); // 現在の経過時間を取得
// 温度センサー(2秒ごと)
if (now - lastTempRead >= TEMP_INTERVAL) {
lastTempRead = now;
int tempValue = analogRead(A0);
Serial.print("温度: ");
Serial.println(tempValue);
}
// 光センサー(0.5秒ごと)
if (now - lastLightRead >= LIGHT_INTERVAL) {
lastLightRead = now;
int lightValue = analogRead(A1);
Serial.print("明るさ: ");
Serial.println(lightValue);
}
// 距離センサー(0.1秒ごと)
if (now - lastDistanceRead >= DISTANCE_INTERVAL) {
lastDistanceRead = now;
int distanceValue = analogRead(A2);
Serial.print("距離: ");
Serial.println(distanceValue);
}
// delay()を使わないので、loop()は常にぐるぐる回り続ける
}
1仕組みのポイント
それぞれのセンサーに「最後に読み取った時刻(lastXxxRead)」を覚えさせておき、「現在時刻 − 最後に読み取った時刻 ≧ 決めた間隔」になったときだけ処理を実行します。これにより、loop()自体は止まらずに回り続けながら、センサーごとに異なるペースで処理を行えます。
pulseIn()を使う超音波センサーは要注意
HC-SR04などの超音波距離センサーで使うpulseIn()は、1章で触れた通り、戻ってくるまでプログラムを止めて待つ命令です。他の処理をmillis()で非ブロッキング化していても、pulseIn()自体は短時間ブロックすることを理解しておく必要があります。タイムアウト値(例:pulseIn(echoPin, HIGH, 30000)のように第3引数で上限を指定)を設定し、待ち時間に上限をつけておくと安心です。
06配線・電源面の注意点
センサーが増えると、ソフトだけでなく「配線」と「電源」にも気を配る必要が出てきます。

1供給できる電流には上限がある
Arduino UNOをパソコンのUSBポートから電源供給している場合、全体で使える電流には上限があります。センサー1つなら気にならなくても、サーボモーターやモーターなど電気を多く使う部品を複数つなぐと、供給が追いつかず、動作が不安定になったり、Arduino自体が再起動してしまうことがあります。
2電源を分ける・外部電源を使う
モーターやサーボなど電流を多く使う部品は、Arduinoの5V端子から直接取るのではなく、別の電源(外部電源)を用意し、GND(マイナス)だけは必ずArduinoと共通にする、という配線が基本です。
3配線とブレッドボードの整理
センサーが3つ、4つになると、配線もそれだけ増えます。ブレッドボードの電源レール(赤・青のライン)を使って、5VとGNDをまとめてから、各センサーに枝分かれさせるように配線すると、見通しがよくなり、ミスも減らせます。
電源は、水道のパイプに似ています。1つの蛇口(USBポート)から、たくさんのシャワーヘッド(センサーやモーター)に同時に水(電気)を送ろうとすると、1つあたりの水圧(電流)が弱くなってしまいます。電気をたくさん使う部品には、別の水道(外部電源)を用意してあげるのが安全です。
07応用:同じI2Cセンサーを複数つなぐには
OLEDディスプレイやジャイロセンサーなどで使われるI2C通信は、複数台つなぐ際に特有の注意点があります。
I2C通信は、1本の線に複数の機器をつなぎ、それぞれの機器に割り振られた「名前(アドレス)」を呼びかけて会話する仕組みです。ところが、同じ種類のセンサーを2個買うと、工場出荷時のアドレスがまったく同じであることが多く、2個同時につなぐと「同じ名前の人が2人いて、呼びかけてもどちらが返事をしたかわからない」状態になってしまいます。
解決策①:アドレスを変更できるセンサーを使う
センサーによっては、基板上のジャンパー(はんだブリッジ)やピンの接続を変えることで、I2Cアドレスを切り替えられる機種があります。この場合は、配線の変更だけで複数台を見分けられるようになります。
解決策②:I2Cマルチプレクサ(TCA9548Aなど)を使う
アドレスを変更できないセンサーの場合は、「TCA9548A」のようなI2Cマルチプレクサ(複数の回線を切り替える部品)を使います。Arduinoから見ると、マルチプレクサの8つの「チャンネル」それぞれに、同じアドレスのセンサーを1個ずつつないでおき、プログラム側で「今はチャンネル0と話す」「次はチャンネル1と話す」と切り替えながら通信します。
#include <Wire.h>
#define TCA9548A_ADDR 0x70 // マルチプレクサ自体のアドレス(代表的な例)
void selectChannel(uint8_t channel) {
Wire.beginTransmission(TCA9548A_ADDR);
Wire.write(1 << channel); // 指定したチャンネルだけを有効にする
Wire.endTransmission();
}
void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
for (uint8_t ch = 0; ch < 2; ch++) { // チャンネル0と1に同じセンサーがある例
selectChannel(ch);
// ここで、通常どおりそのセンサー用のライブラリ関数を呼び出す
// 例:float temp = sensor.readTemperature();
delay(10);
}
}
なお、TCA9548Aのアドレス(0x70など)は製品や配線(A0〜A2ピンの接続)によって変わることがあるため、お使いの機種のデータシートで必ず確認してください。
08よくあるトラブルQ&A
複数センサーを扱うときに、よく起きるトラブルをまとめました。
delay()が複数箇所にないか確認する。② あれば、5章で紹介した
millis()を使った書き方に置き換える。③
pulseIn()を使う超音波センサーがある場合、タイムアウト値を短く設定し、待ち時間の上限を減らす。② 6章の内容を確認し、電源(電流)が足りているか見直す。
③ 特にモーターやサーボと同時に使っている場合、ノイズの影響でアナログ値が揺れることがあります。モーターの電源ラインを分離すると改善することがあります。
sensorPins[]とsensorNames[]など、複数の配列を使っている場合、並び順が一致しているか確認する。② センサーを1つ追加・削除したときに、関連するすべての配列を同時に修正したか確認する。
③ 可能であれば、ピン番号・名前・値をまとめた構造体(struct)を使うと、ズレを防ぎやすくなります。
09まとめ:複数センサー設計の基本方針
複数センサーを扱うときの5つのコツ
- Arduinoの「同時」は、内部的には超高速な「順番処理」。analogReadは約100マイクロ秒、digitalReadはさらに高速
- センサーが増えたら、個別の変数ではなく配列(array)でまとめて管理する
delay()は他の処理を止めてしまうため、複数センサーではmillis()による非ブロッキング制御が基本pulseIn()など「待つ」命令を使うセンサーは、タイムアウト値を設定して影響を最小限にする- 電源は「センサーが増えるほど消費電流も増える」ことを意識し、必要なら外部電源を用意する
複数センサーをうまく扱えるようになると、Arduinoでできることの幅は一気に広がります。まずは2〜3個の簡単なセンサーから、配列とmillis()の組み合わせを練習してみてください。
関連記事・参考資料
基礎を学べる記事
応用・関連記事
参考資料(外部・一次情報)
- Gammon Software Solutions「ADC conversion on the Arduino (analogRead)」, https://www.gammon.com.au/adc
- Arduino公式リファレンス「analogRead()」, https://docs.arduino.cc/language-reference/en/functions/analog-io/analogRead/
- Arduino公式リファレンス「millis()」, https://docs.arduino.cc/language-reference/en/functions/time/millis/
- Random Nerd Tutorials「TCA9548A I2C Multiplexer: ESP32, ESP8266, Arduino」, https://randomnerdtutorials.com/tca9548a-i2c-multiplexer-esp32-esp8266-arduino/
※ 本記事のコード・数値は2026年10月時点の情報をもとに作成しています。センサーの型番や配線は製品により異なるため、実際の制作時は各センサーのデータシート・取扱説明書も併せてご確認ください。
コメント