I2C接続について
wikipediaにると、I2C(アイ・スクエアド・シー)はフィリップス社で開発されたシリアルバスとのことです。低速周辺機器をマザーボードへ接続したり、組み込みシステム、携帯電話などでも使用されている様です。
I2C接続を用いるメリットは2本の信号線を使ってシリアル通信を行い、複数の周辺機器を制御できることだと思います。Arduinoも含めて、マイコンは必ずしもたくさんの信号入出力がありませんので、その様な点を補う方法の一つです。
I2Cの接続の考え方を下の図に示します。1つのマスターに対し、複数のスレーブデバイスをバス接続出来ます。各デバイスは異なるアドレスが設定されていて、権限を持つマスターマイコンがデバイスをアドレス指定し、制御します。
I2C接続の考え方(SCL:SerialCLOCK , SDA:SerialDATA)
ADT7410 温度センサー接続
秋月電子通商で販売しているADT7410使用の温度センサーを使って、I2C接続について具体的に確認していきます。
ADT7410使用温度センサー(写真引用:秋月電子通商HP)
ADT7410温度センサーモジュール取り扱い説明書によると、上図で J1,J2 をはんだでショートすると、SCL,SDA用の内部プルアップ抵抗を有効に出来るとのことです。しかし、今回はこの次に実験するMMA8451加速度センサーも 一緒に配線してしまうので外付抵抗を接続することにします。
また、ADT7410使用 温度センサーモジュールのデバイスアドレスは、J3,J4の接続により変更できます。各端子の接続状態とアドレスを下の表に示します。(取り扱い説明書記載内容を写しています) 今回、同じI2Cバス上でアドレスが重複することはないので、J3,J4 いずれもオープンの状態(デバイスアドレス:0x48)でプログラム作成を進めることにします。
ADT7410温度センサーモジュールのバスアドレス設定
I2Cデバイスアドレス | J3 | J4 |
0x48 | オープン | オープン |
0x49 | ショート | オープン |
0x4A | オープン | ショート |
0x4B | ショート | ショート |
配線は次の写真・図の通りです。この次に、確認する予定の加速度センサー(MMA8451)もまとめて配線しておきます。
プルアップ抵抗については、他の方のサイト等も確認しましたが、1~10KΩ程度の範囲で設定されている様です。実際の波形を測定し決めるのが良い様ですが、現状の私の環境では難しいので、とりあえず写真では1KΩの抵抗を設定しています。今のところ問題は確認していません。
ADT7410制御レジスタ
マスター機器はI2C通信で、接続している対象機器をデバイスアドレスで指定します。そのあと対象となるスレーブ機器を制御しますが、レジスタと呼ばれるデータ領域にデータを書き込んだり、読み出したりすることで機器をコントロールします。今回、プログラムで使用するADT7410のレジスタは以下の通りです。
アドレス | レジスタ名 | 内 容 |
0x00 | Temperature value most significant | 温度値(上位) |
0x01 | Temperature value least significant | 温度値(下位) |
0x03 | Configuration | 設定 |
ADT7410センサーモジュールは分解能を指定できます。測定温度データは二つのレジスター(‘0x00’,‘0x01’)に格納されますが、2つのレジスター合計16bitすべてを温度データ格納に使う場合(高分解能)と、16ビット中の13ビットを温度データ格納に使う場合(標準)の変更ができます。デフォルトは13bitで、通常の用途では十分と思います。ただ、折角なので練習も兼ねて、設定変更できるプログラムを考えてみたいと思います。
ADT7410温度センサーモジュール制御プログラム
今回作成したADT7410を I2C 通信によって制御するテストプログラムを示します。先ず、‘Wire.h’という I2C 通信を行うライブラリを呼び出します。このライブラリによって細かな通信手順を知らなくても I2C バス上に接続されているデバイスの制御が可能になります。プログラム4行目では、変数(DVC_ADRS)に制御対象のデバイスアドレスを格納します。以後、この変数を使ってデバイスとの接続を行います。
//ADT7410 I2Cサンプリング #include <Wire.h> int DVC_ADRS = 0x48; //スレーブ機器バスアドレス // (0x00:連続,0x20:OneShot(240ms),0x40:1SPS(60ms),0x60:shutDown)|(0x80:16bit,0x00:13bit) uint16_t g_md = 0x40 ; uint16_t g_rs = 0x00 ; // 初期化 void setup(void) { Serial.begin(9600); // モニター通信用 Wire.begin(); // マスタ初期化 Wire.beginTransmission(DVC_ADRS); // 接続開始 Wire.write(0x03); // Configurationアドレス指定 Wire.write(g_md | g_rs); // 操作モードと分解能指定 Wire.endTransmission(); // 接続終了 } // メインループ void loop(void) { uint16_t ui_val ; long int in_val ; float fl_tmp ; Wire.beginTransmission(DVC_ADRS); // 接続開始 Wire.write(0x00); // 読込開始アドレス指定 Wire.endTransmission(false); // 送信完了(接続維持) Wire.requestFrom(DVC_ADRS, 2); // 2バイト要求 ui_val = (uint16_t)Wire.read() << 8 ; // データの読み出し(上位) ui_val |= Wire.read(); // データの読み出し(下位) if (g_rs == 0x80){ in_val = (long int)ui_val; if(ui_val & 0x8000) { // 符号判定 in_val = in_val - 65536 ; } fl_tmp = (float)in_val / 128.0 ; }else{ ui_val >>= 3 ; in_val = (long int)ui_val; if(ui_val & 0x1000) { // 符号判定 in_val = in_val - 8192 ; } fl_tmp = (float)in_val / 16.0 ; } Serial.print(fl_tmp, 5); Serial.print(" , "); Serial.print(ui_val); if (g_rs == 0x80){ Serial.println(" (16bit)"); }else{ Serial.println(" (13bit)"); } delay(500); }
①分解能と操作モードの設定
分解能と操作モードの設定について説明します。下図に示すレジスタアドレス(0x03)を書き換えることで分解能と操作モードの変更が可能となります。今回のプログラムでは、分解能:0(13bit),操作モード:10:1sps と設定していますが、分解能のみ考えた時、アドレス0x03に‘00000000’(=0x00) を書き込めばよく、同じく操作モードのみを考えた場合は、アドレス0x03に‘01000000’(=0x40) を書き込めば良いということです。プログラム内では6,7行目でそれぞれの設定値を変数に格納し、15行目で書き込みアドレス指定、16行目で2つの設定値のビットOR(論理和)演算結果を書き込んでいます。(‘00000000’(=0x00) と‘01000000’(=0x40) のビットORの結果‘01000000’(=0x40))
例えば、分解能:1(16bit),操作モード:01:one shot と設定する場合は、‘10000000’(=0x80) と‘00100000’(=0x20) のビットORの結果‘10100000’(=0xA0)を書き込みます。
今回のプログラム内で I2C 通信を行い、デバイスにデータを書き込む処理の流れは以下の様になります。
(dvc_adrs=0x48 , reg_adrs=0x03, value=0x40(0x00と0x40のビットOR))
②温度データの読み込み
温度データは、下図の様なフォーマットで格納されます。上段が13bitモード、下段が16bitモードの場合です。
今回のプログラムで I2C 通信でデータを読み込む処理の流れは以下の様になります。最初の3行が読込開始アドレスの指定、残り3行が読込処理になります。(dvc_adrs=0x48 , reg_adrs=0x00)
1回目に読み込んだデータ(0x00)を8ビットシフト後、次に読み込むデータ(0x01)とのビットOR(論理和)演算結果を16ビット変数(ui_val)に格納します。13ビットモードの場合は、更に3ビットシフトさせ、無効データを除外します。処理の流れを下のイメージ図に示します。
16bit モードの場合は、上図の(4)の結果、13bit モードの時は(5)の結果に対し、それぞれ符号判定、10進数変換を行った後、下記演算式により温度変換します。
プログラム実行結果の確認
Arduino UNOにプログラムを書き込んで実行結果を確認してみます。統合開発環境(IDE)の「ツール」―「シリアルモニタ」をクリックして下さい。
下記の様なシリアルモニタが起動し、連続的に温度・センサーから取得したデータ(変換前)・操作モードの順で結果を出力表示します。プログラム内に ‘Serial.begin(9600)’ と書いていますが、シリアルモニターに出力する為の通信開始と通信速度 9600を宣言するものです。下記シリアルモニター右下に「9600bps」が選択されていますが、もし違っている場合はプログラム記載の通信速度と一致させて下さい。
<注記>
私自身Arduinoも含むマイコンのプログラム経験がないものですから、手探り状態で調べながら実験しています。いろいろ不適切な表現、解釈の誤り等あるかと思いますが、ご容赦お願いいたします。また、もし本サイトを参考にして頂くことがあれば、自己責任で実施いただきます様お願いいたします。