今から始める電子工作 ⑭ I2Cバス その1-1 温湿度センサSHT45 + OLEDグラフィック・ボード
いろいろなバスの中で、一番手軽に利用できるI2Cバスの利用を始めました。
今から始める電子工作 ⑫ データを表示する その2 OLEDディスプレイ
バスは、複数のデバイスをつないで利用できます。今回、温湿度センサのSHT45を利用します。
●環境
- Arduino IDE;2.3.4
- Windows11;23H2
- Arduino UNO R4 WiFi
●SHT45のおもなスペック
- 湿度 ±1% typ(25~75%)
- 温度 ±0.1 °C typ(0~75 °C)
- 供給電圧 1.08~3.6V
- インターフェース I2C(0~400kHz)
- スレーブ・アドレス 0x44(固定)
(typはtypicalの省略形で、代表的は値を示している)
●接続
温湿度センサSHT45は、AdafruitのStemma QT/Qwiicボードを利用します。
Adafruit Sensirion SHT45 Precision Temperature & Humidity Sensor - STEMMA QT / Qwiic
このボードは、3.3/5Vの両方の電源電圧に対応しており、信号もレベル・シフト回路が入っているので、3.3/5Vのどちらのロジック電圧でも利用できます。
Stemma QT/Qwiic(JST SH 4ピン)コネクタは2か所に装着されていて、どちらにつないでもかまいません。このコネクタを使ってI2Cで制御する場合、特に、ジャンパ線をつなぐなどは不要です。
コネクタは、表と裏のどちらも差し込めそうですが、ピンが内部の上部に並んでいるので、差し込める方向は一意です。ロック機構はないですが、すぐに抜けるということはありません。
OLEDグラフィック・ボード(裏面)にもコネクタが2か所ついています。
4線のケーブルでつなぎます。プルアップ抵抗は、どちらのボードも切り離していません。
●I2Cデバイスはスレーブ・アドレスで区別される
バスにつながれたデバイスは、バスを監視しています。自分のスレーブ・アドレスがバスに現れると、やり取りを始めます。なので、スレーブ・アドレスがどのデバイスも異なっていなければなりません。
つながっているデバイスのスレーブ・アドレスが、デバイスのスペックに書かれています。また、i2cScannerと呼ばれるスケッチを利用して表示できますが、多くがWire1に対応していません。古くから、Arduino DUEというマイコン・ボードには二つのI2Cバスがあったので、このボードに対応したスケッチを探します。
How to Scan and Detect I2C Addresses
このサイトにある I2C scanner sketch をArduino IDEにコピペし、説明にあるように、
#define WIRE Wire1
の1行を修正し保存します。i2cScannerという名前にして保存しました。
実行します。
二つのスレーブ・アドレスを見つけてきました。0x3DがOLEDグラフィック・ディスプレイ、0x44が温湿度センサSHT45です。
●専用のライブラリを利用
温湿度センサSHT45は、専用のライブラリを利用します。SHT4xという表現が出てきますが、これは、SensirionのSHT40/41/45が同じようにI2Cバスでアクセスできるために、つけられた名称です。
ライブラリの検索欄に「SHT4x」と入れると、複数のライブラリが検出します。画面下のほうにSensirionの純正ライブラリが見えていますが、ここは、Adafruit SHT4x Libraryをインストールします。
インストールの途中、必要な追加のライブラリのパネルが出るので、全てをインストールします。
サンプル例をインストールします。
スケッチ例->Adafruit SHT4x Library -> SHT4test
このままだと、QWIICでないほうのI2Cバスになってしまうので、22行目の、sht4.begin()を修正します。
if (! sht4.begin(&Wire1)) {
実行します。
●測定値をOLEグラフィック・ディスプレイに表示
上記のスケッチを、温湿度を読む部分を関数にしました。
#include "Adafruit_SHT4x.h" Adafruit_SHT4x sht4 = Adafruit_SHT4x(); sensors_event_t humidity, temp; void setup() { Serial.begin(115200); delay(1000); Serial.println("Adafruit SHT4x read"); if (! sht4.begin(&Wire1)) { Serial.println("Couldn't find SHT4x"); while (1) delay(1); } Serial.println("Found SHT4x sensor"); Serial.print("Serial number 0x"); Serial.println(sht4.readSerial(), HEX); sht4.setPrecision(SHT4X_HIGH_PRECISION); sht4.setHeater(SHT4X_NO_HEATER); } void readData(){ sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data } void loop() { readData(); Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C"); Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH"); Serial.println(""); delay(1000); }
前回の最後のOLEグラフィック・ディスプレイに電圧を表示するところを、温湿度に変更しました。
#include "Adafruit_SHT4x.h" #include <SparkFun_Qwiic_OLED.h> Adafruit_SHT4x sht4 = Adafruit_SHT4x(); sensors_event_t humidity, temp; Qwiic1in3OLED myOLED; void setup() { Serial.begin(115200); delay(1000); Serial.println("Adafruit SHT4x read OLED Display"); if (! sht4.begin(&Wire1)) { Serial.println("Couldn't find SHT4x"); while (1) delay(1); } Serial.println("Found SHT4x sensor"); Serial.print("Serial number 0x"); Serial.println(sht4.readSerial(), HEX); sht4.setPrecision(SHT4X_HIGH_PRECISION); sht4.setHeater(SHT4X_NO_HEATER); Wire1.begin(); if (myOLED.begin(Wire1) == false){ Serial.println("Device begin failed. Freezing..."); while (true) ; } Serial.println("OLED Begin success"); myOLED.rectangleFill(4, 4, myOLED.getWidth() - 8, myOLED.getHeight() - 8); String hello = "SHT45 Temperature & "; // top line message String hello1 = "Humidity"; // Draw the text - color of black (0) myOLED.text(5, 5, hello, 0); myOLED.text(42, 15, hello1, 0); myOLED.display(); } void readData(){ sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data } void loop() { readData(); Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C"); Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH"); Serial.println(""); String temp0 = (String)(temp.temperature); String humi0 = (String)(humidity.relative_humidity); myOLED.rectangleFill(4, 24, 50, 20, 1); myOLED.text(5, 25, temp0, 0); myOLED.text(5, 35, humi0, 0); myOLED.display(); delay(1000); }
実行します。