「M5StickC Plus2」でI2C通信を使用した、温湿度気圧センサユニット「ENV IV(M5Stack社製)」の使い方を詳しく紹介します。
各データはライブラリを使用することで、I2C通信で簡単に取得でき、「M5StickC Plus2」の液晶画面にデータを表示させることができます。
「M5StickC Plus2」については以下のリンクで詳しく紹介しています。
前モデルの「ENV III」を使用したI2C通信の使い方については以下のリンクで詳しく紹介しています。
1.使用するセンサ(ENV IV)について
2.I2C通信とは
3.温湿度センサ SHT40の通信仕様確認
4.サンプルプログラム(ライブラリ未使用)
5.I2C通信を行うArduinoコマンドについて
・初期設定
・データの受信(読み取り)方法
・データの送信(書き込み)方法
6.サンプルプログラム(ライブラリ使用)
7.まとめ
1.使用するセンサ(ENV IV)について
「ENV IV」は「I2C通信」を使用して温度、湿度、気圧のデータを測定することができる「M5Stack社」製の温湿度気圧センサユニットです。(下写真)
「Groveコネクタ」付きで「M5StickC Plus2」とは付属のケーブルで接続するだけで、I2C通信でデータを取得できます。
2.I2C通信とは
I2C通信とは「アイスクエアドシー」と読み、通称「アイ・ツー・シー」と呼ばれます。
フィリップス社によって開発されたシリアル通信方法で、同じ基板内などの近距離デバイス同士の通信を目的に開発されたものです。
通信速度はスタンダードモードで最大100kbps、ファストモードで最大400kbps、さらに高速な通信モードもありますがArduinoコマンドを使用する場合は標準でスタンダードモードとなります。
通信はマスターとスレーブ間で行われ、スレーブとしてデバイスアドレスが違うものであれば1つのマスターからの指示で複数のスレーブデバイスを制御することができます。
3.温湿度センサ SHT40の通信仕様確認
「ENV IV」に内蔵されている、温度と湿度を測定するセンサー「SHT40」は通信手順がシンプルなため「I2C通信」の動作確認をするのに最適です。
ここでも、まずはライブラリを使用せずに「Arduino」の「I2C通信」コマンドを使用して、温湿度データを取得するサンプルプログラムから紹介しているので「SHT40」の通信仕様について確認しておきましょう。
「I2C通信」を行うためには、通信相手デバイスのアドレスを確認する必要があります。
このアドレスは各デバイスのデータシートで確認することができます。
「I2C通信」手順はデータシートにブロック図で記載されているため、以下に抜粋します。
通信手順は以下になります。
①デバイスアドレスを指定して、データ(要求コマンド)送信
②データ受信待ち
③受信データ数分データ受信
データシートにはデータ送受信のプログラム例も記載があるので以下に抜粋して紹介します。
上画像右側が「I2C通信」のプログラム例です。「Arduino」のコマンドとは異なりますが、1行目でデバイスアドレス「0x44」を指定してデータ(要求コマンド)「0xFD」を送信しています。
送信完了後、2行目でデータ受信するまで「0.01秒」待機して、3行目からデータの受信を行なっています。
以降は受信したデータを温度、湿度データに換算する方法が書かれています。
送信データ(要求コマンド)は「0xFD」の他にもいくつかあります。
実用的には「0xFD」だけで十分と思いますが、他のコマンドもデータシートから抜粋して以下表にまとめました。
要求コマンド | 受信データ数 | 受信データ説明 [2 * 8ビット温度データ+8ビットCRC/ 2 * 8ビットRHデータ+8ビットCRC] |
---|---|---|
0xFD | 6 | 高精度(高い再現性)で温湿度を測定。 |
0xF6 | 6 | 中精度(中程度の再現性)で温湿度を測定。 |
0xE0 | 6 | 最も低い精度(低再現性)で温湿度を測定。 |
0x89 | 6 | シリアル番号を読み取る。 |
0x94 | 6 | ソフトリセット[ACK](受信データ無し) |
0x39 | 6 | 200mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
0x32 | 6 | 200mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
0x2F | 6 | 110mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
0x24 | 6 | 110mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
0x1E | 6 | 20mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
0x15 | 6 | 20mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。 |
要求コマンド送信後は6byte(8bit × 6)のデータがデバイスから送信されてきます。
温度と湿度でそれぞれ「測定データ:8bit ×2 と CRC:8bit で、合計6byte」のデータになります。
4.サンプルプログラム(ライブラリ未使用)
最初のサンプルプログラムではライブラリは使用せずに温度と湿度だけを「I2C通信」で取得します。
プログラムを書き込んで実行すると、以下のような表示が確認できます。
サンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#include <M5StickCPlus2.h>
#include <Wire.h>
#define SHT3X_ADDR 0x44 // SHT3X(温度、湿度センサ)I2C通信アドレス
M5Canvas canvas(&M5.Lcd); // 液晶表示用、メモリ描画領域表示(スプライト)のインスタンスを作成
// 変数宣言
float data[6]; // 温度、湿度受信データ格納用
float t_ticks; // 温度計算用
float rh_ticks; // 湿度計算用
unsigned int checksum_t; // 温度受信データチェックサム(CRC)
unsigned int checksum_rh;// 湿度受信データチェックサム(CRC)
float t_degC = 0.0; // 温度換算データ格納用
float rh_pRH = 0.0; // 湿度換算データ格納用
// 初期設定 -----------------------------------------
void setup() {
auto cfg = M5.config(); // 本体初期設定
StickCP2.begin(cfg);
Wire.begin(32, 33); // I2C通信初期化 SDA=32, SCL=33
Serial.begin(9600); // シリアル通信初期化
while (!Serial) {
delay(100);
}
// ベース画面の初期設定
M5.Lcd.fillScreen(BLACK); // 背景色
M5.Lcd.setRotation(1); // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)
M5.Lcd.setTextSize(1); // 文字サイズ(整数倍率)
canvas.setTextWrap(false); // 改行をしない(画面をはみ出す時自動改行する場合はtrue。書かないとtrue)
canvas.createSprite(M5.Lcd.width(), M5.Lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
}
// メイン -----------------------------------------
void loop() {
// I2Cデータ送信
Wire.beginTransmission(SHT3X_ADDR); // デバイスアドレスを指定して I2C通信開始
Wire.write(0xFD); // 要求コマンド送信(高精度測定を指定)
Wire.endTransmission(true); // 書き込み完了
delay(10); // データ受信待ち(時間はデータシートによる:0.01s)
// I2Cデータ受信(温度、湿度それぞれ 測定データ:8bit ×2 + CRC:8bit で合計6byte)
Wire.requestFrom(SHT3X_ADDR, 6); // 受信データリクエスト(6byte)
for (int i = 0; i < 6; i++) { // 6byte分繰り返し
data[i] = Wire.read(); // 受信データ格納
}
// 受信データを温度、湿度に換算(データシートより抜粋)
t_ticks = data[0] * 256 + data[1];
checksum_t = data[2];
rh_ticks = data[3] * 256 + data[4];
checksum_rh = data[5];
t_degC = -45 + 175 * t_ticks/65535;
rh_pRH = -6 + 125 * rh_ticks/65535;
if (rh_pRH > 100) {
rh_pRH = 100;
}
if (rh_pRH < 0) {
rh_pRH = 0;
}
// 各データシリアル出力
Serial.printf("%.0f, %.0f, %.1f, %.1f, 0x%02X, 0x%02X\n", t_ticks, rh_ticks, t_degC, rh_pRH, checksum_t, checksum_rh);
// LCD表示
canvas.fillScreen(BLACK); // 画面初期化
canvas.setCursor(0, 0); // メモリ描画領域の表示座標指定
canvas.setFont(&fonts::Font4); // フォント
canvas.printf("I2C ENV.IV ( SHT40 )\n"); // タイトル表示
canvas.drawFastHLine(0, 30, 230, WHITE); // 水平線(x, y, 長さ)
canvas.setCursor(0, 35); // メモリ描画領域の表示座標指定
canvas.setFont(&fonts::lgfxJapanGothicP_36); // フォント(日本語:ゴシック体)
canvas.printf("温度:%.1f℃\n", t_degC); // 温度表示
canvas.printf("湿度:%.1f%\n", rh_pRH); // 湿度表示
canvas.pushSprite(&M5.Lcd, 8, 8); // モリ描画領域を指定座標に一括表示実行
delay(1000); // 遅延時間
}
「I2C通信」は「2行目」で「Wire.h」をインクルードし、初期設定の「21行目」で「Wire.begin(32, 33)」のように通信に使用する端子を指定します。
「37〜47行目」で「I2C通信」を使用してデータを取得し「49〜61行目」でデータを温湿度データに換算しています。
5.I2C通信を行うArduinoコマンドについて
サンプルプログラムでは初期設定や液晶表示のプログラムが半分ほどありますが、I2C通信を行うための初期設定とデータの送受信方法は以下の数行だけです。
・初期設定
まずは以下のように「I2C通信」を使用するためのヘッダファイルをインクルードします。
#include <Wire.h>
次に初期設定として通信に使用する端子番号を以下のように指定します。
// 初期設定
void setup() {
Wire.begin(32, 33); // I2C通信端子指定(SDA, SCL)
}
・データの受信(読み取り)方法
I2C通信でのデータ送受信は以下のような手順で行います。
// I2C通信データ要求コマンド送信
Wire.beginTransmission(I2C_ADDR); // デバイスアドレスを指定して通信開始
Wire.write(REG_ADDR1); // 読み取りレジスタアドレス(要求コマンド)を指定して書き込み
Wire.write(REG_ADDR2); // 複数指定する必要がある時は続けて書き込み
Wire.endTransmission(true); // 書き込み完了
delay(100) // データ受信待機(時間はデータシートで確認)
// データ受信(読み取り)
Wire.requestFrom(I2C_ADDR, byte); // 受信データリクエスト(I2Cアドレスと受信データバイト数指定)
data = Wire.read(); // データを受信し変数(複数バイトは配列)に格納
①「Wire.beginTransmission」でデータを受信したい対象デバイスのアドレス(I2C_ADDR)を指定して通信を開始します。
②「Wire.write」で対象データのレジスタアドレス(要求コマンド)(REG_ADDR)を指定(書き込み)します。
③レジスタ(要求コマンド)の送信が完了したら「Wire.endTransmission(true)」で一度通信を終了します。
④確実にデータ受信を行うために待機時間を設けます。(時間はデータシートで確認)
⑤スレーブ側から指定したレジスタのデータが送信されてくるので、データを受信するために「Wire.requestFrom」で対象デバイスのアドレス(I2C_ADDR)と受信バイト数(byte)を数値で指定してデータ受信を開始します。
⑥送信されてきたデータを「Wire.read()」で受信(読み取り)し変数に格納して使用します。
データが複数の場合は「for文」等で連続して配列に格納して使用します。
・データの送信(書き込み)方法
I2C通信でのデータ送信(書き込み)は受信(読み込み)の時の要求コマンド送信と同様の方法で以下のような手順で行います。
// I2C通信データ送信(書き込み)※受信の時と同じ手順
Wire.beginTransmission(I2C_ADDR); // デバイスアドレスを指定して通信開始
Wire.write(REG_ADDR); // 書き込みレジスタアドレス指定して書き込み
Wire.write(data1); // データ書き込み(複数の場合はfor文等で連続指定)
Wire.endTransmission(true); // 書き込み完了
①受信の時と同様に「Wire.beginTransmission」でデータを送信したい対象デバイスのアドレス(I2C_ADDR)を指定して通信を開始します。
②先に「Wire.write」で書き込み先のレジスタアドレス(REG_ADDR)を指定して書き込みます。
③続けて「Wire.write」で送信(書き込み)したいデータ(data1)を指定して書き込みます。
データが複数の場合は「for文」等で「Wire.write」を連続で実行して配列のデータを送信します。
④全てのデータを送信したら「Wire.endTransmission(true)」で送信(書き込み)完了です。
6.サンプルプログラム(ライブラリ使用)
温度と湿度はライブラリ無しでも簡単に測定できますが、気圧の測定はデータの換算が複雑なため、ライブラリの使用がおすすめです。
ライブラリを使用したサンプルプログラムを書き込むと以下のように温度、湿度、気圧が確認できます。
使用するライブラリは以下になります。
事前に「ArduinoIDE」や「PlatfornIO」等の開発環境にインストールしておいてください。
Sensirion I2C SHT4x
Sensirion Core
Adafruit BMP280 Library
Adafruit Unified Sensor
「ArduinoIDE」については以下のリンクで詳しく紹介しています。
「PlatformIO」については以下のリンクで詳しく紹介しています。
サンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#include <M5StickCPlus2.h>
#include <SensirionI2cSht4x.h>
#include <Adafruit_BMP280.h>
#include "Adafruit_Sensor.h"
Adafruit_BMP280 bmp; // 気圧センサBMP280用のインスタンスを作成
SensirionI2cSht4x sht4x; // 温湿度センサSHT40用のインスタンスを作成
M5Canvas canvas(&M5.Lcd); // 液晶表示用、メモリ描画領域表示(スプライト)のインスタンスを作成
// 変数宣言
float temperature, pressure, humidity; // 測定値格納用
uint16_t error; // SHT40エラー格納用
char errorMessage[256]; // SHT40エラーメッセージ格納用
// 初期設定 -----------------------------------------
void setup() {
auto cfg = M5.config(); // 本体初期設定
StickCP2.begin(cfg);
Wire.begin(32, 33); // I2C通信初期化 SDA=32, SCL=33
Serial.begin(9600); // シリアル通信初期化
while (!Serial) {
delay(100);
}
// ベース画面の初期設定
M5.Lcd.fillScreen(BLACK); // 背景色
M5.Lcd.setRotation(1); // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)
M5.Lcd.setTextSize(1); // 文字サイズ(整数倍率)
canvas.setTextWrap(true); // 改行をする(画面をはみ出す時自動改行する場合はtrue。書かないとtrue)
canvas.createSprite(M5.Lcd.width()-10, M5.Lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
canvas.setCursor(0, 0); // 表示座標
canvas.setFont(&fonts::Font4); // フォント
// 気圧センサ BMP280初期化
while (!bmp.begin(0x76)) { // 通信失敗でエラー処理
Serial.println("BMP280 fail"); // シリアル出力
canvas.setCursor(0, 0); // 液晶表示
canvas.println("BMP280 fail");
canvas.pushSprite(&M5.Lcd, 10, 15); // 画面を指定座標に一括表示実行
delay(1000);
}
// BMP280のサンプリングレートとフィルタ設定
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, // モード:ノーマル
Adafruit_BMP280::SAMPLING_X2, // 温度サンプリングレート:2倍
Adafruit_BMP280::SAMPLING_X16, // 圧力サンプリングレート:16倍
Adafruit_BMP280::FILTER_X16, // フィルタ:16倍
Adafruit_BMP280::STANDBY_MS_500); // 待ち時間:500ms
Serial.println("BMP280 OK!");
// 温湿度センサ SHT40初期化
sht4x.begin(Wire, 0x44);
uint32_t serialNumber; // シリアルナンバー格納用
error = sht4x.serialNumber(serialNumber); // シリアルナンバー取得実行
if (error) { // シリアルナンバー取得失敗でエラー処理
Serial.print("SHT40 Error: ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else { // シリアルナンバー取得成功で準備完了
Serial.println("SHT40 OK!");
Serial.print("Serial Number: ");
Serial.println(serialNumber);
}
}
// メイン -----------------------------------------
void loop() {
// LCD表示設定
canvas.fillScreen(BLACK); // 画面初期化
canvas.setFont(&fonts::lgfxJapanGothicP_28); // フォント
canvas.setCursor(0, 0); // メモリ描画領域の表示座標指定
// 圧力データ取得
pressure = bmp.readPressure();
// 温湿度データ取得、エラー処理
error = sht4x.measureHighPrecision(temperature, humidity);
if (error) { // trueならエラー処理
errorToString(error, errorMessage, 256); // エラーを文字列に変換
Serial.print("SHT40 Error: "); // シリアル出力
Serial.println(errorMessage);
canvas.setFont(&fonts::Font4); // 液晶表示
canvas.printf("SHT40 Error:\n");
canvas.print(errorMessage);
} else { // falseで測定データ表示実行
Serial.printf("Press:%.0fhPa, Temp:%.1fc, Hum:%.1f%%\n", pressure, temperature, humidity); // シリアル出力
canvas.printf("気圧:%.0fhPa\n", pressure / 100); // 液晶表示
canvas.printf("温度:%.1f℃\n", temperature);
canvas.printf("湿度:%.1f%\n", humidity);
}
canvas.pushSprite(&M5.Lcd, 10, 15); // 画面を指定座標に一括表示実行
delay(1000); // 遅延時間
}
7.まとめ
「M5StickC Plus2」を使用して、I2C通信の温湿度気圧センサユニット「ENV IV」の使い方を詳しく紹介しました。
「I2C通信」でのデータの送受信はライブラリを使用すると簡単にできますが、通信手順やデータの換算方法が簡単な場合は、ライブラリを使用せずに「I2C通信」で直接データ取得した方がシンプルでメモリも節約できる場合もあるため「I2C通信」の手順を理解しておくと、効率の良いプログラムの作成ができると思います。
今回使用した「ENV IV」は温度と湿度のデータ取得手順がシンプルでデータの換算も簡単なため、「I2C通信」を理解するのには最適なデバイスと思います。
温度、湿度、気圧の表示というと実用的というより、作って満足という感じもしますがw 自然に変化するデータが連続して得られるため、IoTでのデータ監視や、データロガーを作成する時のサンプルデータとして便利に使うことができます。
このデータを利用して、Wi-Fi通信を使用した遠隔データ監視やデータロガーの作成についても今後紹介していければと思います。
コメント
Y.Iさんいらっしゃいませ^^
確認しましたが、こちらも最初はライブラリの検索でヒットしませんでした。
PlatformIOでは「Sensirion I2C SHT4x」のようにスペースを入れるとヒットしました。
ArduinoIDEは出てくるアップデートをやっているうちにヒットするようになりました。(スペース不要)
「Sensirion I2C SHT4x」 は先週アップデートがあったようでその影響でしょうか?
どうしてもヒットしない場合は以下のGitHubからダウンロード可能です。
https://github.com/Sensirion/arduino-i2c-sht4x/tree/master
ダウンロードしてインストールする方法は以下を参考にしてください。
https://logikara.blog/m5nanoc6-setting/#toc11
(ダウンロードファイル名はarduino-i2c-sht4x-master.zipですが中にSensirionI2cSht4xが含まれています。)
また、「Sensirion Core」というライブラリも必要なようで、ArduinoIDEなら一緒にインストールできますが、一応記事の方にも追記しました。
コピペで動作確認したところArduinoIDEではそのまま動作しました。
PlatformIOは「M5StickCPlus2」ライブラリをアップデートして、以下のようにヘッダーを追加したら動きました。
#include
#include
ひとまず動くようになりましたが、他のライブラリも出てきているようで、もう少し確認して必要に応じて記事の方も更新していきます。
ご報告ありがとうございました^^/