電子工作初心者のESP32勉強会②~I2C編~

#前回までのESP32
[前回](https://qiita.com/networkyohan69/items/13de6f8ee28d9f130dae)は書き込み完了までの環境構築を行いました。Lチカとかはすっ飛ばして、電装に必要なセンサーを動作させたいなと思います。
今回動かすセンサーは今後長期にわたって電装で使う可能性があるものです。

#対象
- 電子工作一年生の完全初心者向けです。
- 僕自身も中級者まで達していないので上級者の怖い質問には対応できませんが、ご指摘があればよろしくお願いします。
- データシートを読みながらセンサー回路を組んでみましょう

#センサーを扱うにあたって
##重要なことはデータシートに大体載っていた
- 何を取得できるか
- 必要な電圧
- 通信方式
  - 配線(ヒントが書いてある)
  - プログラム(載ってない)

##MPU9250について
- データシートは[こちら](https://strawberry-linux.com/pub/mpu-9250-manual.pdf)
- 9軸(加速度、ジャイロ、地磁気)を測定できる。
- 今回はI2C通信(SPIも可能)
- I2Cの場合、最大クロック400kHz
- 電源電圧は3.3Vで動作


#センサーを使ってみよう
##I2Cの概要

I2Cとは通信方式です。
SCLとはシリアルクロック、SDAはシリアルデータで2本のデータ線を軸に形成されています。

##配線

<img width="70" alt="スクリーンショット 2018-04-30 16.56.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/33ce3487-63d0-5774-d7d4-9427c587cd5f.png">

| 左側ピン       |       右側ピン| 
|:-----------------|------------------:|
| 1 : VDD(+側=>電源接続) |    10 : GND(-側=>グランド接続) | 
| 2 : VDDIO        |       9 : INT |   
| 3 : SCL             |      8 : AUX_DA |     
| 4 : SDA              |     7 : AUX_CL |   
| 5 : AD0          |      6 : ~CS   |  

ここで大事なことがデータシートに書いてある。

> ・I2C モードで通信する場合は~CS ピンを VDDIO に接続します。AD0 ピンは I2C スレーブアドレス設定のピンですので必ずH(=VDDIO), L(=GND)のどちらかに接続します。これにより１つの I2C バスに２つの MPU-9250 センサを接続することができます。マイコンとは SCL, SDA の２線で配線してください。プルアップは行われていませんのでお客様側回路で行ってください。

I2CとSPIモードで配線は違いますが、このような文面があるとその指示通り組んでみましょう。
このMPU9250は日本語データシートが存在していて、なおかつかなり分かりやすいので初心者向けとしては最高です。

以下、少しレベルが上がります。今は理解する必要なないです。
**太線**のところだけは実装しないと動作が安定しません。

>ここでは I2C バス接続を想定します。マイコンに SCL, SDA を接続します。**マイコン側でプルアップを行ってください。**標準的な I2C 通信です。AD0=L にした場合は MPU-9250（加速度,ジャイロ部）のスレーブアドレスが 0b1101000（AD0=H は0b1101001）になります。内部レジスタの 0x75(WHO_AM_I)を読んで 0x71 が読めれば正常です。３軸コンパスのスレーブアドレスは 0b0001100 です。

###では、MPU9250から出した先は一体どうやって繋げるのか？？


| 左側ピン       |       右側ピン| 
|:-----------------|------------------:|
| 1 : ESP32からのVDD線|    10 : ESP32からのGND線 | 
| 2 : ~CSと接続      |       9 : 未接続 |   
| 3 : ESP32におけるSCL   |      8 : 未接続 |     
| 4 : ESP32におけるSDA    |     7 : 未接続 |   
| 5 : VDDIOもしくはGND   |      6 : VDDIOと接続   | 


SCL、SDAでプルアップを実装してください。プルアップの説明と回路は[こちら](http://www.geocities.jp/zattouka/GarageHouse/micon/circuit/pullup.htm)。
分かりやすく言うと、先ほど説明したSCL(シリアルクロック)やSDA(シリアルデータ)は信号線。デジタルセンサーの場合、信号はHIGHとLOWの値で制御しており、HIGHとLOWの区別をはっきりさせるためにプルアップを行なっている。

以下のような回路で繋げてください。ESP32のピンは以下のサイトを参照にしてください。

<img width="642" alt="スクリーンショット 2018-04-30 18.13.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/b674c86f-ea63-3310-f553-ac72ffcfa0ad.png">

##プログラム

ライブラリをgithubから取ってきてインクルードしたいと思います。githubからライブラリを取得することによって本来複雑に書かなければならないコードを初心者でも使えるようになります。

今回、使用するライブラリは[こちら]{https://github.com/asukiaaa/MPU9250_asukiaaa)です。
ライブラリからCloneをします。

<img width="543" alt="スクリーンショット 2018-04-30 23.22.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/882a70ba-0ac0-f0b2-2e9d-54e21467e459.png">

Arduino IDEに戻ってクローンしたzipファイルをインストールします。これで外部ライブラリを扱えます。
この操作は結構重要なので覚えておく必要があります。

```c:MPU9250.ino
//ライブラリを使用
#include <MPU9250_asukiaaa.h>
#ifdef _ESP32_HAL_I2C_H_

// デバイスのI2Cアドレス(Default モード)
#define SENSOR_ADRS  0x48

//SCL、SDAのピンをここで指定
#define SDA_PIN 21
#define SCL_PIN 22
#endif

//センサー名を定義
MPU9250 mySensor;

//MPU9250の設定に関する関数
void MPU_setup(){
  //MPU9250との通信準備
#ifdef _ESP32_HAL_I2C_H_
Wire.begin(SDA_PIN, SCL_PIN); 
#else
//シリアル通信の開始
Wire.begin();
#endif

//加速度、地磁気、ジャイロの値を取得
mySensor.setWire(&Wire);
mySensor.beginAccel();
mySensor.beginMag();
mySensor.beginGyro();
 
// 地磁気の値を調節(コメントアウト)
// mySensor.magXOffset = -50;
// mySensor.magYOffset = -55;
// mySensor.magZOffset = -10;

//データを収集、SDに格納に関する関数
void data(){
//変数を定義
float ax,ay,az,gx,gy,gz,mx,my,mz,a_sqrt,m_hori;

//データを変数に代入
ax = mySensor.accelX();
ay = mySensor.accelY();
az = mySensor.accelZ();
gx = mySensor.gyroX();
gy = mySensor.gyroY();
gz = mySensor.gyroZ();
mx = mySensor.magX();
my = mySensor.magY();
mz = mySensor.magZ();
a_sqrt = mySensor.accelSqrt();
m_hori = mySensor.magHorizDirection();

//シリアル通信よりデータの表示
mySensor.accelUpdate();
Serial.println("print accel values");
Serial.println("accelX: " + String(ax));
Serial.println("accelY: " + String(ay));
Serial.println("accelZ: " + String(az));
Serial.println("accelSqrt: " + String(a_sqrt));

//初期関数
void setup() {
//シリアル通信エラー時の条件分岐
while(!Serial);

//シリアル通信の開始
//通信速度を設定
//シリアルモニタの通信速度と同じ値に設定しないと文字化けします
Serial.begin(9600);
Serial.println("started");

//関数を実行
MPU_setup();
}

//メイン関数(動作は繰り返す)
void loop() {
  data();
  delay(500);
}

```

ここで「コンパイル」=>「書き込み」

##シリアルモニタでセンサーの値を確認

シリアル通信を行うことによって、センサーの値をIDEで確認できます。
画面右上のシリアルモニタを開くと良いです。

<img width="240" alt="スクリーンショット 2018-04-30 23.36.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/17c7a171-96ff-4e87-743c-ba960fb7522c.png">

#I2C通信について

<img width="465" alt="スクリーンショット 2018-04-30 19.51.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/38bd9df0-b036-df04-0a54-3a01c02f36ce.png">

複数のセンサーを扱う場合においては、それぞれのSCL、SDA信号線を用いて以上までと同様に回路を組むことができます。その場合、センサーの区別をつけるためにレジスタのアドレスを指定する必要があります。上の引用ではその旨が記述されています。

もっと理解したいと言う方はGitHubのコードとにらめっこするのもいいかもしれません。

##やってみよう
BMP180(温度、気圧、湿度、高度センサー)でセンサーデータ取得
ライブラリは以下の通りです。
(https://github.com/adafruit/Adafruit-BMP085-Library)

##[次回](https://qiita.com/networkyohan69/items/f40dd4e63d2d85bbc968)はSDモジュールを使ってみようと思います。