ArduinoスケッチでESP32のI2Cを使う方法
I2Cとは、SCLとSDAの2線だけでデバイス間の通信ができる規格です。
今回はESP32をマスターとしてI2Cでデータを書き込んだり読み取ったりする基本的な方法について解説した後、実際に温湿度センサーにつないで温度と湿度を読み取ってみたいと思います。
Raspberry Piでの制御方法はこちら
I2C対応ポートと接続方法
ESP32のI2C対応ポートは次のようになっています。
端子名 | 機能 |
---|---|
GPIO22 | SCL |
GPIO21 | SDA |
ESP32とセンサーなどのデバイスとの接続は下図のようになります。
I2Cに使われる端子は、オープンドレインになっており、自分でHighを出力することができません。
そのため、SCL、SDAにはプルアップ抵抗が必要になります。
プルアップ抵抗は、1kΩ~10kΩの範囲で選べば大抵の場合問題なく動作します。
マスターとして使う場合の基本スケッチ
ESP32をマスターとして使う場合の基本的なArduinoスケッチについて解説していきます。
書き込み
スレーブデバイスを初期化したり、設定を変えたりするときに、マスター側からスレーブ側へ情報の書き込みを行います。
基本となる書き込みプログラムを示します。
#include <Wire.h>
void setup() {
Wire.begin(); //I2Cをマスターとして動作させる
}
void loop() {
Wire.beginTransmission(address); //接続するIC2デバイスを選択
Wire.write(register); //I2Cデバイスのレジスタを指定
Wire.write(value); //レジスタにデータを書き込み
Wire.endTransmission(); //送信を完了
delay(500);
}
読み取り
センサーなどのスレーブ側が取得した情報を読み取ります。
基本となる読み取りプログラムを示します。
#include <Wire.h>
void setup() {
Wire.begin(); //I2Cをマスターとして動作させる
}
void loop() {
Wire.beginTransmission(address) //接続するIC2デバイスを選択
Wire.write(register) //I2Cデバイスのレジスタを指定
Wire.endTransmission(false) //送信完了するが接続は維持
Wire.requestFrom(adress, count) //IC2デバイスに指定したレジスタアドレスから指定サイズ分のデータ取得を要求
Wire.read() //データを取得 (受け取ったバイト数繰り返す)
delay(500);
}
温湿度センサーSHT31の値をI2Cで読む
I2Cの基本的な制御方法が分かったところで、実際にセンサーを動かしてみたいと思います。
使用するのは温湿度センサー:SHT31です。
例えばAmazonではこのようなモジュール化されたものがあります。
SHT31の仕様は下記の通りです。
項目 | 特性 |
---|---|
最大通信速度 | 1MHz |
動作電圧範囲 | 2.4V~5.5V |
湿度の測定精度 | ±1.5%RH |
温度の測定精度 | ±0.2℃ |
回路図
ESP32とSHT31との接続は下図のようになります。
今回使ったモジュール内部にプルアップ抵抗があるので追加不要です。
このように、モジュールによっては内部抵抗を持っているものもあるので、接続するデバイスの内部回路をしっかり確認しておきましょう。
ADR端子はオープンにしています。
ADR端子はモジュール内部で電源にプルアップされているので、オープンの場合はHighとなります。
したがって、SHT31のアドレスは0x45となります。
ADR端子をGNDに接続した場合はLowとなるので、アドレスは0x44です。
Arduinoスケッチ
まずはプログラム全体を見てみましょう。
#include <Wire.h>
int SHT31_Addr = 0x45; // SHT31のアドレスを設定
void setup() {
Wire.begin(); //I2Cをマスターとして動作させる
Serial.begin(115200); //シリアル通信の速度
//ソフトリセット
Wire.beginTransmission(SHT31_Addr);
Wire.write(0x30); //8bitずつ
Wire.write(0xA2); //8bitずつ
Wire.endTransmission();
delay(500);
//ステータスレジスタクリア
Wire.beginTransmission(SHT31_Addr);
Wire.write(0x30);
Wire.write(0x41);
Wire.endTransmission();
delay(500);
//内部ヒーターOFF
Wire.beginTransmission(SHT31_Addr);
Wire.write(0x30);
Wire.write(0x66);
Wire.endTransmission();
delay(500);
}
void loop() {
Wire.beginTransmission(SHT31_Addr);
//単発測定モード
Wire.write(0x24); //クロック・ストレッチ無効
Wire.write(0x00); //繰り返し精度レベル高(測定時間が伸びる)
Wire.endTransmission();
delay(500);
int data[6];
float temperature, humidity;
Wire.requestFrom(SHT31_Addr,6); //6バイト要求
while (Wire.available()<6); //受信データが6バイトになるまで待つ
for (int i=0; i<6; i++) { //6バイトのデータを読み込み
data[i] = Wire.read();
}
//温湿度の計算
temperature = -45.0 + (175.0 * ((data[0] * 256.0) + data[1]) / 65535.0);
humidity = (100.0 * ((data[3] * 256.0) + data[4])) / 65535.0;
//シリアルで送信
Serial.print("温度: ");
Serial.print(temperature);
Serial.println(" ℃");
Serial.print("湿度: ");
Serial.print(humidity);
Serial.println(" %");
delay(1000);
ソフトリセット
ソフトリセット(初期化)を行います。
10行目~の部分です。
コードは0x30A2です。
2バイトになっているので、上位8bit(0x30)と下位8bit(0xA2)に分けて送信します。
ステータスレジスタクリア
ステータスレジスタ内にある下記情報を消去します(17行目~)
- 発信中のアラートの有無
- 相対湿度のアラート発信状態
- 温度のアラート発信状態
- リセット履歴
コードは0x3041です。
内部ヒーターをオフにする
動作確認用に内部にヒーターが設けられています。
測定時には不要なので初期設定でオフにしておきます(24行目~)
コードは0x3066です。
測定
単発測定モードと周期的連続測定モードがありますが、単発測定モードで測定を行います。
クロスストレッチは行わず、測定精度は「High」とします(34行目~)
測定データは下図のように6バイトで読み出されます。
そのため、読み取りは6バイトを要求します(42行目~)
温湿度の計算
湿度と温度の計算式は下記のようにデータシートに記載されています。
SRHは相対湿度の測定データを10進数値にしたもので、STは温度の測定データを10進数値にしたものです。
この式に従って温湿度を計算します(49行目~)
シリアルで送信
計算した湿度と温度をシリアルで送信します(53行目~)
Arduino IDEのシリアルモニタで確認した結果がこちらです。