ArduinoのI2C通信でセンサのレジスタにアクセスする。

# 概要
Arduino UNO R3のI2C通信機能を使って、[カラーセンサモジュール(S11059-02DT/浜松フォトニクス)](https://www.hamamatsu.com/jp/ja/product/type/S11059-02DT/index.html)

から情報を取得するためのコードを書いた。センサモジュールとArduinoの間に電圧変換のモジュールが必要だったものの、I2C通信は問題なくできた。しかし、カラーフィルターの機能確認としてはイマイチ。色味よりも輝度で値が大きく変わってしまったため、機能確認は別の機会に譲りたい。

# 背景
- [ArduinoのI2C通信でデバイスのレジスタにアクセスする。](https://qiita.com/MasterKoda/items/f911faf8614e7061b1ff)
で記載した方法が実用に耐えうるかどうか確認したかった。
- 手元に1つぐらいは、まともに動かせるセンサーが欲しかった。

# 想定読者
- 身近にあるマイコンを使ってI2Cデバイスをお手軽に制御したい人。(後に、あんまりお手軽な方法ではないことがわかる。)

# 目的
- Arduinoを使ってセンサにI2C通信をすること。

# 実験環境
カラーセンサ > I2C電圧変換IC > Arduino
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266167/d07a8789-1e4a-8f1b-0215-01cbd396281d.jpeg" width=50%>

# 参考情報
[秋月電商の販売ページ](http://akizukidenshi.com/catalog/g/gI-06793/)

# ソースコード
コードは[ArduinoのI2C通信でデバイスのレジスタにアクセスする。](https://qiita.com/MasterKoda/items/f911faf8614e7061b1ff)で記載した内容を基本に、本アプリケーションに合わせて実装している。I2C通信として使い回す部分以外、つまりアプリケーション毎に異なる実装になる部分は、アプリケーション層として定義すべきだと思うが、そこまで賢い実装にはなっていない。でも、１つのセンサーに書き込む/読み込むだけであれば、この程度の実装で十分。

~~~C++

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
}

int i=0; //initiarize
int w=119;
int r=114;
int DeviceAddress = 0x2A; // 0b0101010 42

int Address[100]={
  0x00, // Control
  0x00, // Control
  //0x01, // 
  //0x02, // 
  0x03, // Red MSB
  0x04, // Red LSB
  0x05, // Green MSB
  0x06, // Green LSB
  0x07, // Blue MSB
  0x08, // Blue LSB
  0x09,
  0x0A
  };

int Value[100]={
  0x8F, // ADC reset, awake
  0x0B, // Control initialize 0B:correct
  //0x0C, 
  //0x30, 
  0x00, // Red MSB initialize
  0x00, // Red LSB initialize
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x00
  };

void loop() {
  delay(100);
  Serial.println("Please send command either w or r");
  delay(1000);
  Serial.print("Serial.available()=");
  Serial.println(Serial.available());
  if(Serial.available()>0){
    Serial.println("Serial avalable!");
    int x=0;
    x = Serial.read();
    Serial.print("x=");
    Serial.println(x,HEX);
    if(x==w){
      Serial.println("Write");
      WriteReg();
      }
    if(x==r){ 
      Serial.println("Read");
      ReadReg();
      }
    }
  }

void WriteReg(){
  for (i=0; i<10; i++) {
    Wire.beginTransmission(DeviceAddress);
    Wire.write(Address[i]);
    Wire.write(Value[i]);    
    Wire.endTransmission(false);
    Insert0x0(Address[i]);
    Serial.print(Address[i],HEX);
    Serial.print("=");
    Insert0x0(Value[i]);
    Serial.println(Value[i],HEX);
    delay(0);
  } // while(1){}//finalize
  }

void ReadReg(){
  for (i=0; i<10; i++) { 
  Wire.beginTransmission(DeviceAddress);
  Wire.write(Address[i]);
  Wire.endTransmission(false);
  Wire.requestFrom(DeviceAddress, 1,true);
  Value[i] = Wire.read();
  Insert0x0(Address[i]);
  Serial.print(Address[i],HEX);
  Serial.print("=");
  Insert0x0(Value[i]);
  Serial.println(Value[i],HEX);
  delay(0);
  } // while(1){}//finalize
  }

void Insert0x0(int num){
  Serial.print("0x");
  if (num<16){ Serial.print("0"); }
  else Serial.print("");
  }

~~~

# 結果１：I2C通信できた
Writeでカラーセンサーの各アドレスにデータを格納
(0x00には0x0Bを格納、0x03~0x0Aは初期化で0x00を格納)し、
Readで値を確認
(0x00を呼び出すと0x0Bが格納されていて、0x03~0x0Aにはセンサから読み込んだ値が格納されている。)

```
Write
0x00=0x0B
0x03=0x00
0x04=0x00
0x05=0x00
0x06=0x00
0x07=0x00
0x08=0x00
0x09=0x00
0x0A=0x00

Read
0x00=0x0B
0x03=0x0D
0x04=0x5F
0x05=0x03
0x06=0x64
0x07=0x01
0x08=0xC3
0x09=0x01
0x0A=0xD0
```

# 結果２

// 何もかざしていない時
0x03=0x11
0x04=0xB4

// 赤い下敷きをかざしたとき
0x03=0x0D
0x04=0xE7
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266167/ae1f67f2-2b8e-9cd8-f68f-0af4fb5387f7.jpeg" width=50%>

// iPhoneのLEDで光を当てたとき
0x03=0x58
0x04=0x14

// 赤い下敷きをかざしてiPhoneのLEDで光を当てたとき
0x03=0x27
0x04=0x54
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266167/075af338-c821-155c-d29e-b32613d7d0eb.jpeg" width=50%>

赤い下敷きをかざす方が暗くなるから、結果の値が小さくなる。。。
この程度の実験では、カラーセンサの機能が十分に果たせているかわからないため、同じ輝度で、緑、青の値も比較して見る必要がありそうだ。

# 考察１：ADCの初期化
ADCの初期化は自分の理解通りに動いていない。アドレス：0x00にデータ：0x0Bを書き込んで初期化しているのだが、データシートの指示通りであれば、0x0Fを書き込んでも正しく動作するはずと理解している。根本原因は不明。本検討では、センサーにI2Cアクセスすることを目的にしているので、初期化の細かい検討は不問に止めるが、今後の検討で理由を明らかにしていきたいと思っている。これでは全く考察になっていないのだが、考察できるほどの材料が揃っていないのが実際のところ。考察を揃えるためには、まず、カラーセンサーの動作検証環境を整備する必要があると考えている。今の所、カラー光源にまともなものがないため、I2通信していること以外は、センサーがどのように動いているか詳細な動きが理解できていない。まずは、環境を整えたい。しかし、初期化の検討をしているので、カラー光源なんぞなんでも関係ない、というツッコミもまた一理あり。

# 結論
- カラーセンサにI2C通信できた。
- 正確なカラー値が取得可否の確認ができなかった。

# 所感
- 実験していると、往々にして本来の目的外の部分でハマる。本来の目的に立ち戻って、まずは目的達成しているかどうか確認して、一歩一歩進める方が吉。
- 問題にぶつかったら、散歩するなり、時間を置くなりして問題と距離を置くことが有効。散歩すると足の血流が良くなり、脳の働きにも好影響を及ぼすらしい。
- 世の中の人々は、どうやってI2Cデバイスを動かしているのだろうか。もちろん、やり方は色々あるのは知っているのだが、Aruduino使ってセンサにアクセスする方法の説明はあまりない。SoCレベルであればベンダーからのサポート資料などありそうだが、エンジニアの手元で起きることに対するソリューションとして、こういった検討を続けていきたい。

＊この記事は若手もくもく会＠クラウドワークスへ、台湾からのリモート参加中に実験した内容をもとに執筆しました(^^)