本記事では Raspberry Pi Zero W と マルチプレクサ(TCA9548A) で 湿度・温度計(SHT31)を複数利用する方法 を紹介します。
また、i2cdetect / i2cset / i2cget 等のi2c-toolsでの方法で確認しながら、Pythonで交互に値を取得する方法 まで分かりやすくまとめて説明します。
まず初めに、構成は以下の通りです。
✅ TCA9548A の基本
TCA9548A は I2C マルチプレクサで、
Raspberry Pi の I2C バス(SDA/SCL)を最大 8 本のサブバス(SC0/SD0〜SC7/SD7)に切り替えるための IC です。
切り替えは以下の制御バイトを TCA9548A のアドレス(通常 0x70)へ書き込むだけです:
| チャネル番号 | ビット | 書き込み値(hex) |
|---|---|---|
| 0 (SC0/SD0) | bit0 | 0x01 |
| 1 (SC1/SD1) | bit1 | 0x02 |
| 2 (SC2/SD2) | bit2 | 0x04 |
| … | … | … |
✅ 配線状況
- TCA9548AのSC0/SD0(回路図の 4-SCL/4-SDA) に SHT31 を 1個接続
- TCA9548AのSC2/SD2(回路図の 1-SCL/1-SDA) に SHT31 を 2個接続
- Pi Zero WH の I2C (PIN3:SDA, PIN5:SCL)(/dev/i2c-1)→ TCA9548A の SDA/SCL
✅ 回路図

SHTですがFritzingの素子ではADRが無かったので図示できていませんが同じバスに2つ繋ぐ場合はADRをHiにした0x45と、Lo(解放 or GND)にした0x44とでアドレスをかぶらないようにしないといけないのでご注意下さい
✅ コマンド一覧
| やりたいこと | コマンド |
|---|---|
| SC0/SD0 を選択 | i2cset -y 1 0x70 0x01 |
| SC2/SD2 を選択 | i2cset -y 1 0x70 0x04 |
| センサー検出 | i2cdetect -y 1 |
| 測定開始 | i2cset -y 1 0x44 0x24 0x00 |
| 測定値取得 | i2cget -y 1 0x44 0x00 w |
✅ マルチプレクサの切り替えについて
SC0/SD0を選択させる際にはマルチプレクサのADRである0x70に0x01をセットします。SC2/SD2を選択させるには0x70に0x04をセットします。
これは、マルチプレクサの端子をSC7/SD7~SC0/SD0の8ビットに見立てて、以下の2進数を16進数で表現したものです。
| Sx7 | Sx6 | Sx5 | Sx4 | Sx3 | Sx2 | Sx1 | Sx0 | 16進数 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0x01 |
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0x02 |
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0x04 |
| 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0x08 |
| 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0x10 |
| 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0x20 |
| 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0x40 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0x80 |
① SC0/SD0 のデバイスを検出する方法(i2cdetect)
1. i2cdetectでTCA9548A の アドレスを確認する
user@raspberrypi:~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --1. TCA9548A の 0 番チャネルを有効にする
user@raspberrypi:~ $ i2cset -y 1 0x70 0x012. SC0/SD0 のバスをスキャン
user@raspberrypi:~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --結果: SHT31 が 0x44 のアドレスで1つ見えている
② SC2/SD2 のデバイスを検出する方法
1. TCA9548A の 2 番チャネルを有効にする
user@raspberrypi:~ $ i2cset -y 1 0x70 0x042. スキャン
user@raspberrypi:~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- 44 45 -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --結果:SHT31が 0x44 と 0x45 のアドレス2つで見えている
③ 測定値を取得する方法(i2cset / i2cget)
SHT31 の測定コマンドは:
- 単発測定(High Repeatability)
コマンド:0x24 0x00
例:SC0/SD0 → 0x44 のセンサーから読み取る
# チャネル0を有効化
i2cset -y 1 0x70 0x01
# 測定開始
i2cset -y 1 0x44 0x24 0x00
# 15ms程度待つ
sleep 0.05
# 6バイト読み取る
i2cget -y 1 0x44 0x00 w
④ チャネルを交互に切り替えながら読み取る方法(コマンドのみ)
# --- SC0/SD0 ---
i2cset -y 1 0x70 0x01 # channel 0
i2cset -y 1 0x44 0x24 0x00 # SHT31 measure
sleep 0.05
i2cget -y 1 0x44 0x00 w
# --- SC2/SD2 ---
i2cset -y 1 0x70 0x04 # channel 2
i2cset -y 1 0x44 0x24 0x00
sleep 0.05
i2cget -y 1 0x44 0x00 w
⑤ Pythonで複数チャネルを順番に読み取るサンプル
サンプルコード
BUS = 1
TCA_ADDR = 0x70
# すべてのSHT31センサーの定義: (チャネル番号, I2Cアドレス, センサー名)
SENSORS = [
(0, 0x44, "SHT31-Ch0"), # チャネル 0 の SHT31 (アドレス 0x44)
(2, 0x44, "SHT31-Ch2-A"), # チャネル 2 の SHT31 (アドレス 0x44)
(2, 0x45, "SHT31-Ch2-B"), # チャネル 2 の SHT31 (アドレス 0x45)
]
def select_channel(bus, ch):
"""TCA9548AでI2Cチャネルを選択する"""
# TCA9548Aのアドレスに、選択したいチャネルビット (1 << ch) を書き込む
bus.write_byte(TCA_ADDR, 1 << ch)
def crc8(data):
"""SHT31のCRC8チェックサムを計算する"""
# SHT CRC8 (polynomial 0x31)
crc = 0xFF
for b in data:
crc ^= b
for _ in range(8):
if crc & 0x80:
crc = ((crc << 1) & 0xFF) ^ 0x31
else:
crc = (crc << 1) & 0xFF
return crc
def read_sht31(bus, sht_addr, sensor_name):
"""指定されたアドレスのSHT31からデータを読み取り、CRCチェックと変換を行う"""
print(f"\n--- センサー: {sensor_name} (Addr: 0x{sht_addr:02X}) ---")
try:
# 1. 測定コマンド送信: High Repeatability, Single Shot (0x2400)
# i2c_msg.writeの最初の引数には、ターゲットとするSHT31の単一アドレスを指定
write = i2c_msg.write(sht_addr, [0x24, 0x00])
bus.i2c_rdwr(write)
time.sleep(0.05) # 測定完了を待つ (High Repeatabilityで約15ms必要)
# 2. 6バイト読み取り (Temp[2], CRC[1], Hum[2], CRC[1])
read = i2c_msg.read(sht_addr, 6)
bus.i2c_rdwr(read)
data = list(read)
# 3. データ抽出
temp_raw = (data[0] << 8) | data[1]
t_crc_rx = data[2]
hum_raw = (data[3] << 8) | data[4]
h_crc_rx = data[5]
# 4. CRC チェック
t_crc_calc = crc8(data[0:2])
h_crc_calc = crc8(data[3:5])
t_crc_ok = (t_crc_calc == t_crc_rx)
h_crc_ok = (h_crc_calc == h_crc_rx)
# 5. 結果出力(デバッグ情報)
print(f" Temp CRC: Calc=0x{t_crc_calc:02X}, Rx=0x{t_crc_rx:02X}, OK={t_crc_ok}")
print(f" Hum CRC: Calc=0x{h_crc_calc:02X}, Rx=0x{h_crc_rx:02X}, OK={h_crc_ok}")
if not (t_crc_ok and h_crc_ok):
print(" !!! 警告: CRCチェックに失敗しました。データが信頼できない可能性があります。 !!!")
# 6. 測定値変換
temperature = -45 + (175.0 * temp_raw / 65535.0)
humidity = 100.0 * hum_raw / 65535.0
print(" Temperature: {:.2f} °C Humidity: {:.2f} %".format(temperature, humidity))
except Exception as e:
print(f" !!! エラー: SHT31 (0x{sht_addr:02X}) の読み取り中に問題が発生しました: {e} !!!")
# --- メイン処理 ---
with SMBus(BUS) as bus:
current_channel = -1
for channel, address, name in SENSORS:
# TCA9548Aチャネル切り替えが必要な場合のみ実行
if channel != current_channel:
print(f"\n--- TCA9548A チャネル {channel} に切り替え中 (0x{1 << channel:02X}) ---")
select_channel(bus, channel)
current_channel = channel
time.sleep(0.01) # チャネル切り替え後の安定化を待つ (オプション)
# SHT31の読み取りを実行
read_sht31(bus, address, name)
# 終了時にマルチプレクサをリセット(全チャネルオフ)
bus.write_byte(TCA_ADDR, 0x00)
print("\n--- TCA9548A: 全チャネルをオフに設定して終了 ---")
print("\nプログラムを終了します。")出力結果
--- TCA9548A チャネル 0 に切り替え中 (0x01) ---
--- センサー: SHT31-Ch0 (Addr: 0x44) ---
Temp CRC: Calc=0xCD, Rx=0xCD, OK=True
Hum CRC: Calc=0xA9, Rx=0xA9, OK=True
Temperature: 26.13 °C Humidity: 51.05 %
--- TCA9548A チャネル 2 に切り替え中 (0x04) ---
--- センサー: SHT31-Ch2-A (Addr: 0x44) ---
Temp CRC: Calc=0xD8, Rx=0xD8, OK=True
Hum CRC: Calc=0x26, Rx=0x26, OK=True
Temperature: 27.32 °C Humidity: 48.72 %
--- センサー: SHT31-Ch2-B (Addr: 0x45) ---
Temp CRC: Calc=0x40, Rx=0x40, OK=True
Hum CRC: Calc=0x5F, Rx=0x5F, OK=True
Temperature: 25.96 °C Humidity: 51.69 %
--- TCA9548A: 全チャネルをオフに設定して終了 ---
