編集履歴一覧に戻る
akira.keiのアイコン画像

akira.kei が 2026年06月20日20時07分41秒 に編集

コメント無し

タイトルの変更

-

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

+

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

本文の変更

[<前の記事]() : 次の記事> ## I2C接続温度センサー 秋月電子通商には[様々なI2C接続の温湿度センサー](https://akizukidenshi.com/catalog/c/ctmphumse/)が売られている。環境温度を測定するのに必要かも(いや必要ではない)と考え、チマチマと買い揃えたのは以下のセンサーだ。

-

1. [AHT21B](https://akizukidenshi.com/catalog/g/g130222/):時価 1. [SHT40i](https://akizukidenshi.com/catalog/g/g130207/) 1. [SHT30](https://akizukidenshi.com/catalog/g/g112125/) 1. [BME280](https://akizukidenshi.com/catalog/g/g109421/)

+

1. [AHT21B](https://akizukidenshi.com/catalog/g/g130222/):440円 1. [SHT40i](https://akizukidenshi.com/catalog/g/g130207/):650円 1. [SHT31](https://akizukidenshi.com/catalog/g/g112125/):950円 1. [BME280](https://akizukidenshi.com/catalog/g/g109421/):1380円

1. BMP280

-

![AE-BMP280](https://akizukidenshi.com/img/goods/L/109421.jpg)

+

最後のはアリエクで安さに驚いてBME280だと思い込んで買ったBMP280なのであった。どれも温度は測れるのだが、どうも表示される温度がマチマチなようなので使い勝手を含めて比較してみた。 ![I2Cバス](https://camo.elchika.com/33f356ee15f1c4c24258e55488cf15d3dbddb12b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f32323337633162632d623730362d343038312d383064382d343036366136393134333765/)

-

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

+

![I2C](https://camo.elchika.com/8929bbdd5878c689fe5c88e117477fc234c95f2f/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f65306638323262652d616139642d343466372d623538312d373664303464666532303363/) ## まずはAHT21Bから [AHT21Bのデータシート](https://akizukidenshi.com/goodsaffix/AHT21B.pdf)の7.4項を参照すると使い方は(まあまあ)シンプルだ。 1. 起動後100ms待って0x71を送り、戻ったステータスの第3ビットが立っていれば初期化終了(なんかゴニョゴニョ別のことが書いてあるけどw) 1. 10ms待ってから0xAC-0x33-0x00を送る 1. 測定に80ms待ってステータスバイトを受け取り、MSBが0なら測定が終わっている。 1. 更に6バイト受け取ってCRCを計算して比較(これは無視しよう) 1. 湿度と温度に換算する。 なんか連続計測とかフィルター設定とかモード変更とか面倒くさい分岐がないのでライブラリ化も簡単だった。これを使うとスケッチは以下のようになる。 ```Arduino: #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```で測って、```temperature```と```humidity```で測定結果を得る、というシンプルな構成なので、ヘッダも短い。 ```Arduino: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バイト受信、```temperature```も```humidity```もデータシート通りのfloat計算だ。 実際には100倍した固定小数点化して割り算をシフト演算にして整数部と小数点部に分けて表示する、みたいな方法が良さそうだけど、今はシンプルにこうで良い。8ビットのArduino UNOだと負荷が大きくても、RP2040なら問題にならないだろうし。 ```Arduino: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; } ``` 実行してみると、シリアルモニタには以下のように表示される。できたw ![シリアルモニタ](https://camo.elchika.com/178174ac8327848ae7d6725cc0481abd18a7c390/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f39643431613064302d666664352d346431322d613165662d383238366663303138383261/)