今から始める電子工作 ⑭ 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);
}
実行します。