M5StickC Plus2 I2C通信で温度、湿度測定ENV IVセンサの使い方

温湿度気圧センサENV IVの使い方アイキャッチ

「M5StickC Plus2」でI2C通信を使用した、温湿度気圧センサユニット「ENV IV(M5Stack社製)」の使い方を詳しく紹介します。

各データはライブラリを使用することで、I2C通信で簡単に取得でき、「M5StickC Plus2」の液晶画面にデータを表示させることができます。

「ENV IV」は前モデルの「ENV III」よりも温度、湿度データの取得手順がシンプルになったため、温湿度についてはライブラリを使用せずにデータ取得を行い「I2C通信」の手順についても確認していきます。

「M5StickC Plus2」については以下のリンクで詳しく紹介しています。

M5StickC Plus2の使い方、初期設定、旧モデルとの違い等サンプルプログラムで詳しく紹介
M5StickCの最新版M5StickC Plus2について、旧モデルとの違いを確認しながら、初期設定や端子配列、機能、使い方をサンプルプログラムで詳しく紹介します。

前モデルの「ENV III」を使用したI2C通信の使い方については以下のリンクで詳しく紹介しています。

I2C通信の使い方をサンプルプログラムで詳しく紹介(Arduinoコマンド)
温度と湿度の測定できるセンサ(ENV Ⅲ)からライブラリ使用せずにデータを取得する方法を例にI2C通信の使い方を紹介します。データはM5StickC Plusの液晶表示器に表示します。
スポンサーリンク

1.使用するセンサ(ENV IV)について

「ENV IV」は「I2C通信」を使用して温度、湿度、気圧のデータを測定することができる「M5Stack社」製の温湿度気圧センサユニットです。(下写真)
「Groveコネクタ」付きで「M5StickC Plus2」とは付属のケーブルで接続するだけで、I2C通信でデータを取得できます。

温湿度気圧センサENV IV外観
温湿度気圧センサENV IV外観
温湿度気圧センサENV IV外観
温湿度気圧センサENV IV外観
温度と湿度を測定するセンサ「SHT40」と、気圧を測定するセンサ「BMP280」を内蔵していて、それぞれのセンサからI2C通信で測定データを取得することができます。
スポンサーリンク

2.I2C通信とは

I2C通信とは「アイスクエアドシー」と読み、通称「アイ・ツー・シー」と呼ばれます。
フィリップス社によって開発されたシリアル通信方法で、同じ基板内などの近距離デバイス同士の通信を目的に開発されたものです。

通信速度はスタンダードモードで最大100kbps、ファストモードで最大400kbps、さらに高速な通信モードもありますがArduinoコマンドを使用する場合は標準でスタンダードモードとなります。

通信はマスターとスレーブ間で行われ、スレーブとしてデバイスアドレスが違うものであれば1つのマスターからの指示で複数のスレーブデバイスを制御することができます。

通信には以下の2本の信号線を使用します。
・SDA:データ送受信用
・SCL:クロック(通信タイミング)信号用
マスター側から送信したクロック信号のタイミングでスレーブ側と通信するため、同期通信と呼ばれます。(通信デバイス同士で0Vは共通にしておく必要があります。)
スポンサーリンク

3.温湿度センサ SHT40の通信仕様確認

「ENV IV」に内蔵されている、温度と湿度を測定するセンサー「SHT40」は通信手順がシンプルなため「I2C通信」の動作確認をするのに最適です。

ここでも、まずはライブラリを使用せずに「Arduino」の「I2C通信」コマンドを使用して、温湿度データを取得するサンプルプログラムから紹介しているので「SHT40」の通信仕様について確認しておきましょう。


「I2C通信」を行うためには、通信相手デバイスのアドレスを確認する必要があります。
このアドレスは各デバイスのデータシートで確認することができます。

「SHT40」のI2C通信アドレスは「0x44」です。

「I2C通信」手順はデータシートにブロック図で記載されているため、以下に抜粋します。

温湿度センサSHT40通信手順

通信手順は以下になります。
 ①デバイスアドレスを指定して、データ(要求コマンド)送信
 ②データ受信待ち
 ③受信データ数分データ受信


データシートにはデータ送受信のプログラム例も記載があるので以下に抜粋して紹介します。

温湿度センサSHT40通信例

上画像右側が「I2C通信」のプログラム例です。「Arduino」のコマンドとは異なりますが、1行目でデバイスアドレス「0x44」を指定してデータ(要求コマンド)「0xFD」を送信しています。
送信完了後、2行目でデータ受信するまで「0.01秒」待機して、3行目からデータの受信を行なっています。
以降は受信したデータを温度、湿度データに換算する方法が書かれています。

「Arduino」のコマンドを使用したプログラムの詳細は「4.サンプルプログラム(ライブラリ未使用)」を参照してください

送信データ(要求コマンド)は「0xFD」の他にもいくつかあります。
実用的には「0xFD」だけで十分と思いますが、他のコマンドもデータシートから抜粋して以下表にまとめました。

要求コマンド受信データ数受信データ説明
[2 * 8ビット温度データ+8ビットCRC/ 2 * 8ビットRHデータ+8ビットCRC]
0xFD6高精度(高い再現性)で温湿度を測定。
0xF66中精度(中程度の再現性)で温湿度を測定。
0xE06最も低い精度(低再現性)で温湿度を測定。
0x896シリアル番号を読み取る。
0x946ソフトリセット[ACK](受信データ無し)
0x396200mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。
0x326200mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。
0x2F6110mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。
0x246110mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。
0x1E620mWで1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。
0x15620mWで0.1秒のヒーターをアクティブにする。無効化直前の高精度測定を含む。

要求コマンド送信後は6byte(8bit × 6)のデータがデバイスから送信されてきます。
温度と湿度でそれぞれ「測定データ:8bit ×2 と CRC:8bit で、合計6byte」のデータになります。

ヒーターについて、センサに結露等で水滴が付着していると、空気中の水分量の測定ができないため、一時的にヒーターを作動させる機能があります。
ヒーター使用時のデータ受信までの待機時間は、ヒーターアクティブ時間より長くする必要があります。
ヒーター使用時の測定データは実際の雰囲気温湿度とは異なります。
また、ヒーター使用時には大きな電流が流れるため、電源容量についても考慮しておく必要があります。
同様に気圧センサ「BMP280」も「I2C通信」でデータ取得することができますが、受信データの換算が複雑なため、気圧についてはライブラリを使用した方が効率が良いと思います。

4.サンプルプログラム(ライブラリ未使用)

最初のサンプルプログラムではライブラリは使用せずに温度と湿度だけを「I2C通信」で取得します。

プログラムを書き込んで実行すると、以下のような表示が確認できます。

温湿度気圧センサENV IVの使い方

サンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#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行目」でデータを温湿度データに換算しています。

PCBGOGOバナー600_1
PCBGOGOバナー600_2

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.サンプルプログラム(ライブラリ使用)

温度と湿度はライブラリ無しでも簡単に測定できますが、気圧の測定はデータの換算が複雑なため、ライブラリの使用がおすすめです。

ライブラリを使用したサンプルプログラムを書き込むと以下のように温度、湿度、気圧が確認できます。

温湿度気圧センサENV IVの使い方

使用するライブラリは以下になります。
事前に「ArduinoIDE」や「PlatfornIO」等の開発環境にインストールしておいてください。

Sensirion I2C SHT4x
Sensirion Core
Adafruit BMP280 Library
Adafruit Unified Sensor

「ArduinoIDE」については以下のリンクで詳しく紹介しています。

M5StackシリーズのためのArduino IDEのインストール方法と初期設定、使い方紹介
ArduinoIDEバージョン2のインストール方法から初期設定、スケッチ例の書き込み、コピペでの使い方まで詳しく紹介します。インストールはArduinoでも同じです。

「PlatformIO」については以下のリンクで詳しく紹介しています。

プログラミング
Visual Studio Code (VSCode)のインストールと日本語化から基本設定まで紹介
プログラムを書くために必要なエディタのインストールをします。他のプログラミングにも便利な定番エディタです。
pythonのインストール
pythonのダウンロードからインストール方法の紹介
次にインストールするPlatformIOをインストールするために必要なプログラム言語のpythonをインストールします。
PlatformIOでプログラミング
PlatformIO のダウンロードからインストールの紹介。Arduino IDEより速い!高性能!
プログラミングするためのIDE(統合開発環境)のインストールです。
ATOM LITE本体
ATOM LITE の初期設定。プログラミング初心者におすすめ
ATOM LITEにプログラムを書き込むための初期設定とプログラミングの書込みから動作確認まで行います。

サンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#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通信を使用した遠隔データ監視やデータロガーの作成についても今後紹介していければと思います。

M5StickC Plus2の使い方、初期設定、旧モデルとの違い等サンプルプログラムで詳しく紹介
M5StickCの最新版M5StickC Plus2について、旧モデルとの違いを確認しながら、初期設定や端子配列、機能、使い方をサンプルプログラムで詳しく紹介します。
PCBGOGOバナー600_1
PCBGOGOバナー600_2

コメント

  1. logikara より:

    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

    ひとまず動くようになりましたが、他のライブラリも出てきているようで、もう少し確認して必要に応じて記事の方も更新していきます。
    ご報告ありがとうございました^^/

タイトルとURLをコピーしました