I2C接続温度センサー
秋月電子通商には様々なI2C接続の温湿度センサーが売られている。環境温度を測定するのに必要かも(いや必要ではない)と考え、チマチマと買い揃えたのは以下のセンサーだ。
最後のはアリエクで安さに驚いてBME280だと思い込んで買ったBMP280なのであった。どれも温度は測れるのだが、どうも表示される温度がマチマチなようなので使い勝手を含めて比較してみた。
まずはAHT21Bから
AHT21Bのデータシートの7.4項を参照すると使い方は(まあまあ)シンプルだ。
- 起動後100ms待って0x71を送り、戻ったステータスの第3ビットが立っていれば初期化終了(なんかゴニョゴニョ別のことが書いてあるけどw)
- 10ms待ってから0xAC-0x33-0x00を送る
- 測定に80ms待ってステータスバイトを受け取り、MSBが0なら測定が終わっている。
- 更に6バイト受け取ってCRCを計算して比較(これは無視しよう)
- 湿度と温度に換算する。
なんか連続計測とかフィルター設定とかモード変更とか面倒くさい分岐がないのでライブラリ化も簡単だった。これを使うとスケッチは以下のようになる。
#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で測定結果を得る、というシンプルな構成なので、ヘッダも短い。
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なら問題にならないだろうし。
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
さんが
前の土曜日の16:00
に
編集
をしました。
(メッセージ: 初版)
-
akira.kei
さんが
前の土曜日の20:07
に
編集
をしました。
-
akira.kei
さんが
前の土曜日の20:11
に
編集
をしました。
-
akira.kei
さんが
前の土曜日の20:13
に
編集
をしました。
-
akira.kei
さんが
前の土曜日の20:18
に
編集
をしました。
-
akira.kei
さんが
前の日曜日の2:13
に
編集
をしました。
ログインしてコメントを投稿する