I2C: マスターとしてデータを読み書き

SPIはコンピューター同士でデータをやり取りする通信方式です。といってもUSBのようにちゃんとしたものではなく、シンプルな通信に使われます。特に、I2Cはセンサーなどと通信するのに使われます。

I2Cは複数台繋げられるというのが最大の特徴です。そのためたくさんセンサーがあっても同じI2Cに全部つなぐこともできて配線が楽です。また、相手とやり取りしながらデータを送ったりするので、データを失ったりする心配が少ないです。そのかわり通信速度はSPIなどと比べるとそれほど速くありません。

I2Cの特徴

  • 2本の線だけで双方向通信する上に、複数台で通信できる。
  • 親子関係があり、親1つに対して子をたくさん繋げられる。
  • 子はアドレスを持つ。
  • 親が好きなタイミングで1つの子に対して通信を始める。書き込みと読み込みがある。
  • 子は書き込みでも読み込みでも必ず”返事”をして、返事がないとエラーになる。
  • 子は親に対して「ちょっとまってね、今準備してるから」とか「それ無理」という返事ができる。

配線

I2Cはsdaとsclという2本の線で通信しますが、どちらも双方向通信するようになっています。
そのために、オープンドレイン+プルアップ抵抗という構成で通信する必要があります。

obnizは各IOにプルアップ抵抗があり、3v,5vそれぞれにプルアップできますが、内部プルアップなのでとても弱いです。
安定した通信をするためには外部で数kオームの抵抗でプルアップする必要があります。

使ってみる

では、obnizのI2Cを使ってみましょう。obnizのI2Cは1つだけでi2c0のみ利用できます。
ioとi2cは別のもので、i2cのsda, sclそれぞれを、12あるioのうちどれかで使えるようにして利用する。という感じになります。

例えば、io0をsdaに、io1をsclにする場合は、このようにします。

var i2c = obniz.getFreeI2C();
i2c.start({mode:"master", sda:0, scl:1, clock:400000}); 

obniz.getFreeI2C()とは使われていないi2cを下さい。という意味です。
i2cは1つしかないため

obniz.i2c0.start({mode:"master", sda:0, scl:1, clock:400000}); 

このように書いても同じですが、基本的にはこのようにせずにgetFreeI2C()を使って下さい。

modeはobnizをmasterにして自分からデータを送れるようにするのかslaveで受け取ったりするのかを設定します。

frequencyは通信周波数となります。I2Cでは100khzと400khzが一般的です。
高速に通信したい場合はそれだけ”小さな”抵抗でプルアップする必要があります。
外部抵抗無しでobnizのプルアップだけでI2Cを使う方法は推奨できませんが、使う場合はこのように設定できます。

obniz.i2c0.start({mode:"master", sda:0, scl:1, clock:400000, pull:"5v"}); 

pullでsdaとsclの内部プルアップを指定できます。io.pull()で設定できるものが利用できます。
内蔵プルアップ指定時は400lkhzまでとなっています。特に3vの内蔵プルアップは弱いため、3vの内蔵プルアップを指定した場合は100khzまでとなっています。

相手の回路やセンサーとgndをつなぎたい場合はgndを指定することもできます

obniz.i2c0.start({mode:"master", sda:0, scl:1, gnd:2, clock:400000, pull:"5v"}); 

書き込み

それでは、実際にデータを書き込んでみましょう。
今回はスレーブとして0x50というアドレスを持つ回路をつなぎます。
確認が難しいためプログラムの方法だけ紹介します。

書き込みにはwrite関数を使います。
書き込みたい相手のアドレスが0x50で、送りたいデータが[1,2,3]だった場合はこのようになります。

i2c.write(0x50, [1, 2, 3]);

この関数はawait関数ではありません。つまり、obnizに対して「1,2,3送っといてね!」と言うだけ言って、さっさと次のプログラムに進みます。

早速使ってみましょう。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
  var i2c = obniz.getFreeI2C();
  i2c.start({mode:"master", sda:0, scl:1, clock:400000}); 
  i2c.write(0x50, [1, 2, 3]);
}

これで書き込めるかと思います。

もし、配線が正しくなかったり、アドレスを間違っていたりすると、エラーがobnizから送られてきますので、配線などを見直さないといけないです。

7bitアドレスと10bitアドレス

I2Cのアドレスの長さは2種類あります。7bitと10bitです。
ほとんどのセンサーなどは7bitアドレスになっていますが、一部10bitも存在します。

obnizでは現在7bitアドレスのみに対応しています。

読み込み

今度は相手からデータを読み込んでみましょう。
つまり相手に対して「データちょうだい!」と伝えてデータを送らせるわけです。
使う関数はこれです

await obniz.i2c0.readWait(0x50, 1);

このようになります。I2Cでは、データを読み取るときに相手に対して「何バイト欲しい」と、データの長さを指定して読み取る必要があります。readWait関数の1つめの0x50は相手のアドレスですが、1は1バイトのことです。

awaitですので、obnizから応答があるのを待ちます。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
  var i2c = obniz.getFreeI2C();
  i2c.start({mode:"master", sda:0, scl:1, clock:400000}); 
  var data = await i2c.readWait(0x50, 1);
  console.log(data)
}

dataには読み取れたバイト配列が入っています。
こちらも同じく相手とうまく通信できない場合はエラーとなります。

終了

i2cを終了して、ioを開放するにはend()を利用します。

end()によりioはフロートの状態に戻ります。

var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
  var i2c = obniz.getFreeI2C();
  i2c.start({mode:"master", sda:0, scl:1, clock:400000}); 
  var data = await i2c.readWait(0x50, 1);
  console.log(data)
  i2c.end();
}


Next : I2C: Slave-receive data

You will Get in Few Days

Circuit for Starter “obniz Board” is available on Amazon and other online stores.
You can get it at below

Our products and resellers

Forum

Visit our developer’s forum to discuss and discover technologies.

Forum

Contact

Feel free to contact out support and technical team.

Contact us