akira.keiのアイコン画像
akira.kei 2026年06月20日作成 (2026年06月21日更新) © MIT
セットアップや使用方法 セットアップや使用方法 閲覧数 32
akira.kei 2026年06月20日作成 (2026年06月21日更新) © MIT セットアップや使用方法 セットアップや使用方法 閲覧数 32

Arduino IDEでI2C接続温湿度センサーを使う(その1):AHT21B

<前の記事 : 次の記事>

I2C接続温度センサー

秋月電子通商には様々なI2C接続の温湿度センサーが売られている。環境温度を測定するのに必要かも(いや必要ではない)と考え、チマチマと買い揃えたのは以下のセンサーだ。

  1. AHT21B:440円
  2. SHT40i:650円
  3. SHT31:950円
  4. BME280:1380円
  5. BMP280

最後のはアリエクで安さに驚いてBME280だと思い込んで買ったBMP280なのであった。どれも温度は測れるのだが、どうも表示される温度がマチマチなようなので使い勝手を含めて比較してみた。
I2Cバス

I2C

まずはAHT21Bから

AHT21Bのデータシートの7.4項を参照すると使い方は(まあまあ)シンプルだ。

  1. 起動後100ms待って0x71を送り、戻ったステータスの第3ビットが立っていれば初期化終了(なんかゴニョゴニョ別のことが書いてあるけどw)
  2. 10ms待ってから0xAC-0x33-0x00を送る
  3. 測定に80ms待ってステータスバイトを受け取り、MSBが0なら測定が終わっている。
  4. 更に6バイト受け取ってCRCを計算して比較(これは無視しよう)
  5. 湿度と温度に換算する。

なんか連続計測とかフィルター設定とかモード変更とか面倒くさい分岐がないのでライブラリ化も簡単だった。これを使うとスケッチは以下のようになる。

#include "Wire.h" #include "AHT21B.h" AHT21B meas=AHT21B(0x38); void setup(void) { Serial.begin(115200); Wire.begin(); meas.begin(); } byte cnt=0; void loop(void) { meas.measure(); Serial.print(cnt++); Serial.print(", AHT21B, MEAS-T-H, "); Serial.print(meas.temperature()); Serial.print(", "); Serial.println(meas.humidity()); delay(1000); }

ヘッダファイル「AHT21B.h」

オリジナルライブラリのヘッダファイルAHT21B.hを以下に示す。要はbeginで初期化し、measureで測って、temperaturehumidityで測定結果を得る、というシンプルな構成なので、ヘッダも短い。

AHT21B.h

#ifndef AHT21B_h #define AHT21B_h #include <inttypes.h> #include "Arduino.h" class AHT21B { public: AHT21B(uint8_t); void begin(void); void measure(void); float temperature(); float humidity(); private: uint8_t _adrs; uint8_t data[7]; }; #endif

ライブラリ本体「AHT21B.cpp」

ライブラリの中身もシンプルだ。コンストラクタはI2Cアドレスを保管しておくだけ。初期化のbeginは0x71を送ってステータスをチェックするが、シリアルに表示は良くないな。measureで0xAC-0x33-0x00を送信して7バイト受信、temperaturehumidityもデータシート通りのfloat計算だ。
実際には100倍した固定小数点化して割り算をシフト演算にして整数部と小数点部に分けて表示する、みたいな方法が良さそうだけど、今はシンプルにこうで良い。8ビットのArduino UNOだと負荷が大きくても、RP2040なら問題にならないだろうし。

AHT21B.cpp

#include "AHT21B.h" #include "Wire.h" #include <inttypes.h> #include "Arduino.h" AHT21B::AHT21B(uint8_t adrs) { _adrs=adrs; } void AHT21B::begin(void) { delay(100); Wire.beginTransmission(_adrs); Wire.write(0x71); Wire.endTransmission(); delay(10); byte stat=0; Wire.requestFrom((int)_adrs,(int)1); if(Wire.available()) stat=Wire.read(); if(stat & 0x08) Serial.println("AHT21B ready..."); } void AHT21B::measure(void) { Wire.beginTransmission(_adrs); Wire.write(0xAC); Wire.write(0x33); Wire.write(0x00); Wire.endTransmission(); delay(80); byte i=0; Wire.requestFrom((int)_adrs,(int)7); while(Wire.available()) data[i++]=Wire.read(); if(!(data[0] & 0x08)) for(byte i=0;i<7;i++) data[i]=0xff; } float AHT21B::temperature(void) { uint32_t raw = ((uint32_t)(data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | data[5]; return ((float)raw / 1048576.0) * 200.0 - 50.0; } float AHT21B::humidity(void) { uint32_t raw = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | ((data[3] & 0xF0) >> 4); return ((float)raw / 1048576.0) * 100.0; }

実行してみると、シリアルモニタには以下のように表示される。隣に置いた安物の温湿度計表示は「29.1℃、64%」なのでなかなか良いのでは。できたw
シリアルモニタ


<前の記事 : 次の記事>

akira.keiのアイコン画像
機械系エンジニアだが電子工作を趣味としている。週末はひとりバーベキュー。
ログインしてコメントを投稿する