[IchigoJam メニューへ戻る]

ボクにもわかる I2C インタフェース方式
for IchigoJam ・ Raspberry Pi

IchigoJam TのCN5を使ってI2Cの実験をしてみよう



はじめに

 I2Cインタフェース(以下I2Cインタフェース)は、1982年にPhilips(現NXP)が開発した IC間の通信規格です。クロック信号SCL、データ信号SDA、GNDの3本の配線で複数のI2C機器との通信が行えます。
 本ページでは、110円で販売されているI2C温度センサモジュール(IC単品だと100円)を IchigoJam T マイコンボードへ接続し、I2Cインタフェースの基礎的な使い方を学びます。
 専門知識が必要で、未経験者やお子様が理解するのは少し難しい内容になっていますので、分からない部分は読み飛ばしてください。動かしてみて、流れをつかみ、なんとなく達成感が得られれば十分です。さぁ、チャレンジしてみましょう。

本ページの主な学習内容
項目名 内容
配線方法 SCL、SDA、GNDとプルアップ抵抗を接続する
アクセス方法 スレーブのI2Cアドレスを指定し、i2crコマンド(またはi2cwコマンド)で送信する
検索方法 i2cdetectでスレーブノードを検索する

 なお、ウェブではIchigoJam Tを中心に解説しますが、Raspberry Piでも実験することが出来ます。Raspberry Pi用のプログラムはGit Hubからダウンロードしてください。

親機のマスター・ノードと子機のスレーブ・ノード、配線方法

 I2C機器には通信の親機となるマスターノードと、子機となるスレーブノードの2種類があります。通常は、マイコンなどの頭脳を持った機器がマスターノードです。また、そのマイコンの周辺機器(ディスプレイやセンサ等)がスレーブノードです。
 マスター、スレーブのそれぞれのI2C機器に備わっているクロック信号SCLと、データ信号SDA、GND同士を下記の回路図のように接続して使用します。


親機マスタノードのSCL、SDAのそれぞれの信号線に、子機スレーブノードのSCL、SDAを接続する。子機スレーブ側では、それぞれの信号線をプルアップ抵抗(数kΩ~10kΩ程度)で電源へ接続する(マスター、スレーブともに同じ電源電圧を想定)
回路の説明:図中の上部の4本の線(VCC)は途切れているように見えるが、4本が相互に接続されていることを示している。また、明示されていないが、この4本のVCCは、3.3Vの電源に接続されている。図中の下部のGND端子については、その近くにあるアース記号によって、GNDへ接続されていることを示している。アース記号があれば、GND端子を線で結ぶ必要は無いが、この回路図では分かりやすいように左右のICのGNDを相互に接続した。SCL信号は左のマイコンから右の周辺機器へ送信されるが、その信号の戻り電流がGNDを通してマイコンへ帰ってくる。このように、GNDには様々な信号の戻り電流が複雑に入り混じって流れる。SDA信号の途中でSCLのプルアップ抵抗が交差しているように見えるが、ドット「●」の無い交差は接続しない。

 本ページでは、より詳しい情報を【Column】として紹介しています。【Column】のタイトルを見て、興味が湧かない場合や、疑問に思わない場合は、読み飛ばしても良いでしょう。

【Column】なぜマスターノードとスレーブノードが必要なのか?
 マイコンの周辺機器のように、親子関係が明確な通信インタフェースでは、マスターとスレーブに分かれていることによるメリットが大きいので、例えばUSBについても、ホストとデバイスに分かれています。
 I2Cインタフェースでは、親機となるマスターノードがクロックを出力し、子機となるスレーブノードはマスターのクロックに合わせてデータを送受信します。このようにマスターが主管となって通信を行うことで、一つの親機マスタノードのSCL、SDA信号線に、複数台のスレーブノードを接続することが容易に出来るようになります。
 また、クロック信号の速度が既定の100kbps以外であっても動作させることが出来るので、マイコン側の処理能力に合わせてクロック信号の速度を加減することも出来ます。スレーブ側には通信インタフェース用クロック発振器が不要で簡単なロジック回路で実装できる点も低価格化や普及に貢献しました。

少し分かりにくいI2Cアドレス

 マスターがスレーブと通信を行うには、I2Cアドレスが必要です。例えば、教室での授業中に先生Aが生徒Cへ命令するときには、先生Aは生徒Cの名前を呼んでから本題である命令を話します。このように生徒Cの名前を付与するのは、複数の生徒から生徒Cを特定するためです。そして、その命令に対して行動を起こしたり、結果を先生に報告するのは生徒Cだけです(他の生徒は口出しせずに黙っていることが前提)。
 同じように、I2Cのマスター(親機・先生)は、I2Cスレーブ(子機・生徒)へコマンドを送る前に、スレーブを特定するための情報(生徒の名前)を付与します。このときに付与する情報がI2Cアドレスです。

 I2Cアドレスは予めI2C機器に設定されている8番から119番までの番号です。I2C機器を入手したら、まずは機器の説明書や部品のデータシートなどに記載されているI2Cアドレスを確認して下さい。I2Cアドレスの表記方法には、10進数表記、16進数表記、2進数表記、7ビット表記、8ビット表記などがあります。詳しくは理解できなくても大丈夫です。複数の表記方法があることを知っておきましょう。
 例えば、10進数表記のIC2アドレスが60だった場合、データシートには、60、0x3C、0x78、0b0111100、0b01111000のいずれかが記載されています。もし、ここで7ビット表記の0x3Cを8ビット表記の0x3Cだと勘違いしてしまったら、10進数表記のアドレスは30となってしまいます。先生が「佐藤さん」を「国野さん」と、呼んでも伝わらないのと同じで、I2Cアドレスが一致せずに通信が行えなくなります。

少し分かりにくいI2Cアドレスの表記方法
表記方法 範囲 表記例
位取り ビット 最小 最大 60 62 72
10進数 7 bit 8 119 60 62 72
16進数 7 bit 0x08 0x77 0x3C 0x3E 0x48
16進数 8 bit 0x10 0xEE 0x78 0x7C 0x90
2進数 7 bit 0b0001000 0b1110111 0b0111100 0b0111110 0b1001000
2進数 8 bit 0b00010000 0b11101110 0b01111000 0b01111100 0b10010000

 親機マスタノードのSCL、SDA信号線には、最大112台までの子機スレーブノードのSCL、SDAを接続することが出来ます。しかし、もし教室に二人の佐藤さんが居たとして、先生が「佐藤さん」と呼ぶと2人が返事をしてしまい、特定することが出来ません。I2Cアドレスは、マスターが個々のスレーブを特定するために用います。このため、同じ信号線(I2Cバス上)に同じI2Cアドレスの機器を接続することは出来ません。
 多くのI2C機器には、I2Cアドレスを変更する機能がついています。片方の「佐藤さん」を「国野さん」に変更することが出来るのです。複数台の同じI2C機器を使用するときや、たまたま同じI2Cアドレスの機器があったときは、各I2C機器のI2Cアドレスが重複しないように設定してください。

【Column】7ビット表記のI2Cアドレスを8ビット表記へ変換する
 もっとも分かりにくいのは、8ビット表記と7ビット表記の部分でしょう。7ビット表記のアドレスを左へ1桁シフトすると8ビット表記になります。つまり7ビット表記値を2倍すれば8ビット表記値が得られます。10進数、16進数、2進数の記数法に慣れていない人は、デジタル回路や、論理回路の入門書、教科書などを参考にすると理解が深まりやすいでしょう。
【Column】8ビット表記のI2Cアドレスの最下位ビット
 インタフェース規格上、I2Cアドレスは7ビットで表記されていますが、最下位ビットに0を挿入し、8ビットで表記する場合もあります。8ビット表記の最下位ビットはマスターからスレーブへの書き込み/読み取りの識別値として利用されます。実際の通信においても、書き込み/読み取りの識別値が付与され、バイト単位で通信を行います。
 一例として、8ビット表記のI2Cアドレスが0x90の場合、最下位ビットは0です。この0は、「マスターからスレーブへの書き込み」を示します。読み取り時は、8ビット表記I2Cアドレス0x90の最下位ビットが1となり、0x91になります。

I2C温度センサ ABLIC製S-5851A をIchigoJam Tへ接続する

 それでは、実験用のハードウェアの準備に移りましょう。I2C機器として温度センサをIchigoJam Tへ接続してみます。下図はABLIC製のI2C温度センサを搭載した2ワイヤデジタル温度センサモジュールS-5851AAA-M6T1U(秋月電子通商製)です。12ビットの高分解能なセンサにもかかわらず税込み110円と低価格で販売されています。また、国内メーカ品であることから、日本語データシートが理解しやすいと考え、この部品を選定しました。


I2C温度センサ ABLIC製 S-5851A使用2ワイヤデジタル温度センサモジュール。基板へ実装済みのモジュールが110円。ICはハンダ付けされているが、写真の左右のピンヘッダを基板へハンダ付けする必要がある。ABLIC社は、世界に誇るSEIKOブランドの時計を研究・開発・製造しているセイコーインスツル社の半導体事業を継承した会社。温度センサとしては、CMOS技術を活かしたS-8120Cが世界中で使用されている。S-5851AはI2Cインタフェースを搭載した製品だが、データシートやカタログでは「2ワイヤシリアルインタフェース(I2Cバス)」という表現で記載されている(NXP社の商標を意識したものと思われる)

 下図は温度センサモジュールS-5851AAA-M6T1Uをミニ・ブレッドボード上に実装したときの様子です。ICのマーカ部が写真の上側に来るように実装してください。プルアップ抵抗には10kΩを使用しました。
 本品に限らず、CMOS ICのVDD(VCC)とVSS(GND)にはデカップリング用のコンデンサを追加し、電源へのノイズ混入を防止します。ここでは0.1μFを使用しました。コンデンサをつけ忘れたとしても、実験程度であれば何も変わらないと思います。ここでは、原則として必要な部品につき省略しませんでした。ただし、実験には差し支えない程度の罠を仕掛けてあります。読み進めると、発見できるかもしれません。


I2C信号のSCLとSDAにはプルアップ抵抗が必要。プルアップ抵抗の値は各デバイスの仕様や伝送速度、伝送距離などを考慮して概ね数kΩから10kΩ程度の範囲内にする。抵抗値が小さいほどIC側のドライブ能力に負担をかけるが、より高い速度で遠くまで伝えることが出来る。今回のように10cm程度の短いブレッドボード用ジャンパワイヤで接続する場合は、10kΩくらいにしておくことで、ドライブ能力不足による不具合を避けることが出来る。

 製作したブレッドボード上のGND(VSS)、VCC(3.3V,VDD)、SCL、SDAを、IchigoJam TのCN5へ接続します。初代IchigoJamやIchigoJam Uの場合は、SCLをEX1端子へ、SDAをIN3端子へ接続してください。


IchigoJam TのCN5のGND(VSS)、VCC(3.3V,VDD)、SCL、SDAを温度センサモジュールS-5851AAA-M6T1Uへ接続した完成例。配線を行うときは電源用のUSBコネクタを外し、電源スイッチSW1を右側にスライドさせておくこと

 下図はI2C温度センサを接続した IchigoJam T のCN5の拡大したときの様子です。下から順に、黒(GND)、赤(3.3V)、黄(SCL)、緑(SDA)の順にジャンパワイヤを接続しました。一番上の5V端子は空けておきます。


IchigoJam TのCN5の様子。赤いジャンパワイヤの電源VCC(VDD)は3.3Vへ接続する。基板間に接続する長いジャンパワイヤの色には一定のルールを設けておくと誤配線の対策となる。一般的に電源のプラス側には赤を、GNDには黒を使うことが多い。ただし電池のマイナス極には青を、GNDをアースととらえる時は緑を使用する場合もある。その他の信号については、主要信号、出力側、速度が高いものなどに目立つ色(橙、黄など)、その対になるものを目立たない色(青、緑など)を使用するなど、自分なりのルールを決めておくと良い

 以上でハードウェアの製作は完了です。製作に必要な部品のリストを以下に示します。

実験に必要な主要な部品のリスト
  • S-5851A 使用 2ワイヤデジタル温度センサモジュール (秋月電子通商・110円)
  • ミニブレッドボードBB-601(汎用品・130円)
  • 抵抗 10kΩ(汎用品×2個)
  • 積層セラミックコンデンサ 0.1μF(汎用品×2個)
  • ブレッドボード用ジャンパワイヤ(汎用品10cm程度×4本)
  • ブレッドボード用ジャンパワイヤ(橙1本、紫1本、灰1本、ほかに+2本)
  • IchigoJam T マイコンボード(またはRaspberry Pi) および 周辺機器
【Column】VCC、VEE、VDD、VSS、3.3V、3V3、GNDなどの表示について
 これらは電源に用いられる信号名です。VCC、VDD、3.3V、3V3は、プラス側の電源を示し、VEE、VSS、GNDはマイナス側を示します。それだけを理解しておけば十分ですが、本コラムでは、これらの使い分けについて説明します。
 GNDには単にマイナス側という意味だけでなく、各種の電源や各種の信号の戻り電流が流れる共通の基準電位を示す意味もあります。GND以外には電源電圧を意味する「V」のアルファベットが用いられます。
 VCCとVEEはTTLロジック回路(トランジスタを使った回路)に用いられた電源の表記方法で、トランジスタのコレクタ側のプラス電源をVCC、エミッタ側のマイナス電源をVEEと示します。CMOSロジック回路(FETを使った回路)の時代に入ると、FETのドレイン側のプラス電源をVDD、ソース側のマイナス電源をVSSと示すようになりました。
 回路図の信号名で3.3Vの電圧値とともに電源であることを示す場合には、3V3のように記します。近年は回路CADなどのエンジニアリングシステムの進化により、信号名に小数点が使えるようになってきたので3.3Vと記すことも出来るようになってきました。
 以上のように、ロジック回路の構造の移り変わりや、システムの進化によって、様々な表現がされるようになりました。ICや部品のピン名には、どのような名称が来ても、極性を理解する必要があります。回路配線の信号名(ネット名)をつける際に、統一するようにしましょう。

分からないときはI2Cアドレス検索を行う

 この節のタイトルを見て、これまでのI2Cアドレスの説明は何だったのかと思う人も居るでしょう。てっとり早く解を得て、物事の本質に時間をかけることは、技術進歩には欠かせない重要な手法です。教室の先生や生徒のたとえ話なんて聞きたくなかったかもしれません。
 しかし、ボクの中で定着している製作手法には、I2Cアドレスの検索という手順はありません。検索すれば簡単に答えが得られる時代への反発かもしれませんが、もう少し読み進めると、適切な理由があることに気づくかもしれません。

 無駄話はさておき、IchigoJamまたはRaspberry Pi(マスターノード)にI2C機器(スレーブ)を接続し、i2cdetectというソフトでI2Cアドレスを検索すれば、簡単にアドレスを知ることが出来ます。
 以下にIchigoJam用のi2cdetectプログラム(IchigoJam BASIC 1.1.1および1.2.2で動作確認済み)と実行結果を示します(Raspberry Pi用は後述)。見つかったI2Cアドレスが16進数・7ビット表記で表示されます。

プログラム IchigoJam用i2cdetectプログラム「I2C Detector」
' I2C Detector for IchigoJam 1.1.1~
' CC BY (c) 2016-2017 Wataru KUNINO
' https://bokunimo.net/ichigojam/i2c.html

new
1 ?"I2C Detector by W.Kunino"
2 ?"   https://bokunimo.net/ichigojam/i2c.html":?
10 Q=0:clt
20 for I=8 to 119
30 D=i2cr(I,#8EC,1,#8ED,0)
40 if TICK()>240 ?"ERR":end
50 if D ?" --"; else ? " ";hex$(I,2);
60 if I%8=7 ?
70 next:end


 下図は、5つのI2C機器を接続した場合の実行結果です。見つかったI2C機器のアドレスが16進数で表示されました。

実行結果 IchigoJam用i2cdetectプログラム「I2C Detector」
RUN ⏎
I2C Detector by W.Kunino
https://bokunimo.net/ichigojam/i2c.html

-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- 3C -- 3E --
-- -- -- -- -- -- -- --
48 -- -- -- -- -- -- --
50 -- -- -- 54 -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
OK

 I2C温度センサS-5851の場合、上から9行目の左端にI2Cアドレス「48」の16進数値が表示されれば、ハードウェアの動作確認が完了です。
 次節では、このI2C機器の理解を深めるために、少しだけデータシートを確認します。この段階で、すぐにでも温度を測定したい人は「I2Cコマンドで温度データを取得する」へ進んでください。

【Column】Raspberry Piでもi2cdetectでI2Cアドレスを探せる
 Raspberry Piでも同じようにI2Cアドレスを探すことが出来ます。下記の黄色文字のコマンドを実行してGitHubからプログラムをダウンロードしてください。

実行結果 Raspberry Pi用 i2cdetectプログラム「raspi_i2cdetect」
$ git clone https://github.com/bokunimowakaru/RaspberryPi
Cloning into 'RaspberryPi'...
Checking connectivity... done.
$ cd RaspberryPi/gpio/
$ make
$ ./raspi_i2cdetect
I2C Detector by W.Kunino
https://bokunimo.net/ichigojam/i2c.html

-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- 3C -- 3E --
-- -- -- -- -- -- -- --
48 -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- 76 --
$ ■

念のためにデータシートと合っているかどうかを確認する

 念のための確認というのも大切です。前述の通り、I2C Detectorを使って検索すると、I2C温度センサS-5851AのI2Cアドレスは16進数で0x48でした。I2C Detectorを実行すると下図のように16進数値「48」が表示されました。
 IchigoJamでは16進数を示すのに数値の先頭に「#」を付与します。10進数へ変換するには16進数に「#」を付与し、たとえば「? #48」のように入力します。下図の下の方に変換結果「72」が表示されました。2進数は「`」を付与するので、たとえば「? `1001000」のように入力すると2進数から10進数へ変換して表示することが出来ます。16進数で表示したいときはhex$を使用します。

I2C Detectorで、S-5851Aを検索する
RUN ⏎
I2C Detector by W.Kunino
https://bokunimo.net/ichigojam/i2c.html

-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
48 -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
OK
? #48 ⏎
72
OK
? `1001000 ⏎
72
OK
? "#";hex$(72) ⏎
#48
OK

 もし時間に余裕があるようでしたら、念のためにI2C温度センサS-5851Aのデータシートで最後の確認をしておきましょう。下表にはICのAD1端子(3番ピン)、AD0端子(5番ピン)の状態とI2Cアドレス(スレーブアドレス)との関係が記載されています。これらの端子の状態に応じて8種類のI2Cアドレスが選択できます。
 表の最上段のAD1端子=0、AD0端子=0を見てみると、スレーブアドレスは2進数7ビットで「1001000」、すなわち10進数の72、16進数の0x48であることが分かります。ちゃんと検証できたので、問題なさそうです。まだまだ気になる人は、じっくりと下表と回路を見比べてください。謎が解けたときの嬉しさは、応用への強いバネとなって身につきます。解けなくても支障が無いので、正解は書きません。見つけた人に優越感を味わっていただきたいです。


上記は「S-5851Aシリーズ データシート 1.0-2016.01」P.16 から本デバイス使用する目的で引用。AD1とAD0端子が0の状態のときは、7ビットのスレーブアドレスが「1001000」すなわち16進数で0x48、10進数で72になることが分かった。

I2Cコマンドで温度データを取得する

 我慢強い人も、そろそろ「一体、温度は何℃なんだ!」と、いら立ってきたころでしょう。安心してください。以下のコマンドを実行すれば、いますぐに温度を取得できます。ボクも冷静では無いかもしれません。こんな暑い部屋でこの記事を書いていたのです。

A=0:?!i2cr(72,#8CC,1,#8CC,1)*A;"゚C" ⏎
33゚C
OK

 これまでのややこしいI2Cアドレスの説明を忘れるくらい簡単に温度が得られました。

 この1行コマンドについて、少しだけ説明しておきます。はじめの「A=0」は変数Aに0を代入する命令です。次の「?」は表示命令、「!」は論理を反転する演算子です。肝心なのは次のi2cr命令です。i2cr命令は、I2Cインタフェースを使ってI2C機器から値を取得するコマンドです。括弧内には、複雑そうな5つの引数が並んでいます。初めの「72」はI2Cアドレスです。16進数で書きたい場合は7ビット表記で「#48」と書きます。第2引数以降については、次節で説明します。
 i2cr命令を実行し、通信に成功すると、変数Aに温度値が代入され、表示命令?で単位「℃」とともに表示されます。「℃」はカタカナの「プ」などを入力した時に表示される半濁点「゚」とアルファベットの「C」の2文字を使用します。
 なお、この方法で得られた温度は1℃単位と荒い上、小数点以下が四捨五入で無く、切り捨てになります。また、0℃未満の時は正しく表示されません。

取得した温度データを温度値に変換する

 先ほど取得した温度は1℃ごとの荒い値でしたが、S-5851Aには12ビットのADコンバータが内蔵されており、より細かな値を得ることも出来ます。下図はデータシート内に書かれた温度レジスタ(S-5851A内のメモリーの一部)の構成図です。


上記は「S-5851Aシリーズ データシート 1.0-2016.01」の P.12から本デバイス使用する目的で引用。温度データは2バイトに分かれており、ADコンバータの解像度に相当する12ビットのうち、上位8ビットが1バイト目に、下位4ビットが2バイト目に含まれていることが分かる。

 上図のように計12ビット分の温度データが2バイトのデータ構造で保持されていることが分かりました。そこで、こんどは下記のコマンドを入力し、2バイト分のデータを受信し、表示してみましょう。最初の応答値の0は通信の成功を意味します。次の応答値は16進数2バイト分の温度データです。温度データが変数Aへ代入されたことが確認できました。

Q=0:P=#84A ⏎
OK
?i2cr(72,2*asc("Q")+P,1,2*asc("A")+P,2):?hex$(A) ⏎
0
A022
OK

 温度値を得る前にi2crコマンドについて、もう少し、詳しく説明しておきます。下記(箇条書き)のように、第1引数はI2Cアドレスでした。第2引数は温度センサへ送信するデータやコマンドです。ここでは変数Qへ代入した0x00を送信します。第3引数は送信するバイト数です。ここでは1バイト送信を行います。第4引数はI2C機器から得られた受信データの代入先です。ここでは変数Aへ代入します。第5引数は受信データのバイト数です。ここでは2バイトの受信を行います。
 なお、IchigoJamの変数は2バイトなので、3バイト以上の命令やデータを送信したり受信したりする場合は、配列変数や他のメモリ空間を使用します。

i2cr命令 (I2Cデータの受信)
  • 第1引数:I2Cアドレス
  • 第2引数:受信を行うためにスレーブへ送信する命令やデータ
  • 第3引数:第2引数の送信バイト数
  • 第4引数:受信データの格納先 (i2cw命令の時は送信データ)
  • 第5引数:第4引数の受信バイト数 (i2cwの時は送信バイト数)

 第2引数と第4引数はIchigoJam内のメモリのアドレスです。メモリアドレスについては、【Column】を参照してください。第2引数の変数Qのアドレスを求めるには「2*asc("Q")+P」を計算します。「2*」や「+P」はアドレスを計算するための定数です。第4引数の変数Aについても同じように計算しています。はじめから、変数Qのときは#8ECを、変数Aのときは#8CCを記載しておくと、より短いプログラムで、より高速に動作します。

P=#84A ⏎
OK
? "#";hex$(2*asc("Q")+P) ⏎
#8EC
OK
? "#";hex$(2*asc("A")+P) ⏎
#8CC
OK
Q=0:?i2cr(72,#8EC,1,#8CC,2):?hex$(A) ⏎
0
D022
OK


 次は、得られた温度データを摂氏温度へ変換します。I2Cインタフェースを搭載したセンサの多くは、特別な変換なしに温度値が計算できるように工夫されています。本S-5851Aも計算が簡単になるように1バイト目に整数部、2バイト目に小数部で構成されています。
 1バイト目の整数部は変数Aの下位8ビットへ、2バイト目の小数部は上位8ビットの最上位側4ビットへ代入されています。ただし、負の値が2の補数で表記されるので、一度、IchigoJam BASIC用の符号付の2バイトの変数として扱った方が簡単です。そこで、以下のような手順で変換してみました。

プログラム IchigoJam用 I2C温度センサ プログラム「I2C Temprature」
' I2C Temprature for IchigoJam 1.1.1~
' CC BY (c) 2017 Wataru KUNINO
' https://bokunimo.net/ichigojam/i2c.html

new
1 ?"I2C オンド センサ S-5851A"
2 Q=0:'Read Temprature Command
3 A=0:'Temprature Data
4 P=#84A:'Pointer for Variable
10 'Main
20 I=i2cr(72,2*asc("Q")+P,1,2*asc("A")+P,2)
30 if I ?"ERR":end
40 A=(A>>8)|(A<<8)
50 B=A:C=0
60 if A<0 B=-B:C=asc("-")
70 A=B/256:B=B%256/26
80 ? chr$(C);A;".";B;"゚C"
90 end

RUN ⏎
I2C オンド センサ S-5851A
34.6゚C
OK

【Column】メモリアドレスと変数のメモリマップ
 I2CインタフェースをIchigoJamで利用する際に、メモリマップを把握しておくと便利です。変数A~Zのメモリアドレスは#8CC~#8FFに割り当てられており、前例のとおり変数Qであれば「2*asc("Q")+#84A」のようにしてメモリアドレスを計算することが出来ます。配列変数[0]~[101]は#800~#8CBです。他にも自作文字用の領域 #700~#7FFなどを使用することも出来ます。

#700~#7FF自作文字用PCG領域
#800~#8CB配列変数[0]~[101]用
#8CC~#8FF変数A~Z用

 メモリアドレスは1バイトごとですが、変数は2バイトごとになります。たとえば、配列変数[0]は、#800と#801の2バイトが用いられ、下位1バイトが#800、上位1バイトが#801に割りあたります。
 メモリ領域へ、直接、数値を書き込むにはpoke命令を使用します。poke #700,#00で、メモリアドレス#700へ#00を書き込みます。POKE #700,#00,#00のようにデータ続けることで2バイト以上を書き込むことも出来ます。数値を読みたいときはpeek命令を使います。メモリアドレス#700の内容を16進数で表示するには「? hex$(peek(#700))」のように入力します。
 下記はメモリアドレス#700を使用した一例です。poke命令で#700へ#00を書き込んでから、i2crコマンドでI2Cアドレス72へ#00をコマンド(温度取得)送信し、受信データを同じメモリアドレス#700へ読み取り、peek命令で表示します。

poke#700,#00:?!i2cr(72,#700,1,#700,1)*peek(#700);"゚C"

メモリアドレスは、慣れていないと理解しにくい部分です。上記のコマンドを分割して実行してみたり、アドレスを変更してみてみたりすると、理解が深まるでしょう。概念を理解するのは断念し、使い方だけをまねても良いでしょう。
 なお、使用するメモリの範囲は、#700~#8FFまでにしておくのが無難です。他のアドレスだと書き込みが行えなかったり、書き込みによって表示やプログラムなどに支障をきたす場合があるからです。
【Column】バイトオーダーの入れ替えについて
 I2C温度センサS-5851Aの信号フォーマットは上位バイトを先に送信しますが、IchigoJamの変数のメモリ構成では下位バイトを先に保存します。この違いにより、プログラム「I2C Temprature」の行番号40ではバイトオーダーの入れ替えを行いました。
 多くのI2C機器が上位バイトを先に送信しますが、中には下位バイトを先に送信するもの(一例=ADXL345)もあり、その場合はバイトオーダーの入れ替えを行うことなくIchigoJamの変数へ取り込むことが出来ます。
 I2Cインタフェースでは上位バイト、上位ビットから順に送信する場合が多いです。これは、信号波形をオシロスコープで見たときに数値を分かりやすくするための工夫です。こういったインタフェース間のやり取りは他社や他人が設計したものとのやり取りであることが多く、仕様としての機能よりも仕様の明瞭さが重要になるからです。
 一方、WindowsやIchigoJamのように下位バイトを先に格納する手法(リトルエンディアンと呼ぶ)が用いられる場合があります。例えば2バイトの変数において1バイトしか使っていないときに、同じポインタへアクセスすることが出来るようになり、機能面での利便性があるからです。こういったシステムに合わせたI2C機器も、多少存在しています。
 さらに、1バイト内のビットの順序であるビットオーダーにも(念のために)知っておく必要があります。I2Cインタフェースでは、基本的に上位ビットから順に送信するMSB Firstとなっています。しかし、UARTでは下位ビットから送信するLSB Firstとなっています。
【Column】Raspberry PiでI2C温度センサのデータを取得する

 Raspberry Pi用のプログラムは「raspi_s5851a.c」です。前述のi2cdetectのRaspberryPi/gpioフォルダ内に収録しました。makeコマンドでコンパイルしてから「./raspi_s5851a」を実行してください。下記はプログラムの抜粋です。

プログラム Raspberry Pi用 I2C温度センサ プログラム「raspi_s5851a.c」
#include "../libs/soft_i2c.h"
typedef unsigned char byte;
byte i2c_address=0x48;

uint16_t _getReg(byte data){
    byte rx[2];
    i2c_write(i2c_address,&data,1);
    delay(10);
    i2c_read(i2c_address,rx,2);
    return (((uint16_t)rx[0])<<8)|((uint16_t)rx[1]);
}

float getTemp(){
    uint16_t ret;
    ret = _getReg(0x00);
    return (float)ret / 256.;
}

int main(){
    i2c_init();
    delay(20);
    printf("%3.2f\n",getTemp());
    i2c_close();
    return 0;
}

 IchigoJamやRaspberry Piを使った実験は以上ですが、当サイト内の他のページでは、LCDやOLED、RTC、モータドライバなどのI2Cの利用方法についても説明しています。詳細は下記のページをご覧ください。

 IchigoJam T にはI2Cインタフェースを開発したPhilips(現NXP社)のマイコンが搭載されています。正真正銘の正当な純正I2Cインタフェースといっても過言ではないでしょう(少し言い過ぎです)。また、開発された時代もBASICが主流だった頃です。こういった原点かもしれない組み合わせで、I2Cインタフェースについて学習することで、関連する様々な物事に興味が湧いたり、歴史を意識することが出来ると思います。このような意義を感じながら、本ページを執筆しましたので、参考にしていただければ幸いです。

2017年7月 国野 亘




以下はI2Cインタフェースに関するより詳しい情報です。




CQ出版社 IchigoJam用コンピュータ電子工作学習キット

 IchigoJam用コンピュータ電子工作学習キット(IF ICH-KIT)に付属のプリント基板には、I2Cを扱うための便利な工夫があります。一つ目はArduino似の拡張IOポート状のI2C端子(下図)です。I2Cインタフェースを利用したArduino用シールドを、接続することが出来ます(すべてのArduino用シールドと互換性があるわけではありません)。
 また、Seeed Studio の Grove インタフェース用のI2Cコネクタへの変換アダプタも付属しており、I2Cインタフェースを扱ううえで便利なキットです。通常のUARTシリアルについてもスイッチ操作でUSBシリアルと拡張IOとの信号切替が出来るなど、通信インタフェース開発用として様々な工夫を行いました。


IchigoJam用コンピュータ電子工作学習キット(IF ICH-KIT)に付属の「Personal Computer基板」。通信インタフェース開発用としての仕掛けが満載で、IchigoJam用の通信プログラム開発にはとてもお手軽。ただし、¥17,280円(税込み)は、アナログレコードを聞きながら組み立てるくらいのちょっぴり大人向け。販売元=CQ出版社、中身=ブログなどを参照。

I2Cデータ波形

 ここで、実際のI2Cデータの波形を見てみましょう。下図は自作したI2C信号をキャプチャした結果です。上側のSCLの立ち上がり時にSDAのデータの読み書きが行われます。



I2C接続LCDモジュールAQM0802へ、2バイト分のI2Cデータを送信したときの信号波形の様子。IC2アドレスは先頭の1バイトの上位7ビットに配置される。下位1ビットは0で書き込み、1で読み取りであることを示す。続く2バイトのうち1バイト目は、スレーブノードへのコマンド、もしくはスレーブノードのレジスタアドレスを示すことが多い。また、2バイト目にコマンドの属性値やレジスタへ書き込む内容が構成される。こういったルールはI2C機器によって異なるので、ドライバソフトウェアを作成するときは、データシートをよく読んで実装する。

ソフトウェアによるI2Cドライバ

 I2Cインタフェースをソフトウェアで構成することで、様々なGPIO端子をI2Cポートとして使用することが出来ます。下記はソフトウェア I2C ドライバ soft_i2cの主要部のソースリストです。上図の波形は本ドライバで出力しました。ソースリスト全体はGitHubへ公開しています。

ソフトウェア I2C ドライバ
// ソフトウェア I2C ドライバ soft_i2c
// Copyright (c) 2014-2017 Wataru KUNINO
// https://github.com/bokunimowakaru/RaspberryPi/blob/master/libs/soft_i2c.c

byte i2c_SCL(byte level){
    byte ret=0;
    if( level ){
        ret += !pinMode(PORT_SCL, INPUT);
    }else{
        ret += !pinMode(PORT_SCL, OUTPUT);
        ret += !digitalWrite(PORT_SCL, LOW);
    }
    _delayMicroseconds(I2C_RAMDA);
    return !ret;
}

byte i2c_SDA(byte level){
    byte ret=0;
    if( level ){
        ret += !pinMode(PORT_SDA, INPUT);
    }else{
        ret += !pinMode(PORT_SDA, OUTPUT);
        ret += !digitalWrite(PORT_SDA, LOW);
    }
    _delayMicroseconds(I2C_RAMDA);
    return !ret;
}

byte i2c_tx(const byte in){
    int i;
    for(i=0;i<8;i++){
        if( (in>>(7-i))&0x01 ){
                i2c_SDA(1);
        }else   i2c_SDA(0);
        /*Clock*/
        i2c_SCL(1);
        i2c_SCL(0);
    }
    /* ACK処理 */
    _delayMicroseconds(I2C_RAMDA);
    i2c_SDA(1);
    i2c_SCL(1);
    for(i=3;i>0;i--){
        if( digitalRead(PORT_SDA) == 0 ) break;
        _delayMicroseconds(I2C_RAMDA/2);
    }
    if(i==0 && ERROR_CHECK ){
        i2c_SCL(0);
        i2c_log("no ACK");
        return 0;
    }
    return (byte)i;
}


掲載情報について

  • こどもパソコン IchigoJamを用いた電子工作、プログラム等を紹介しています。
  • IchigoJamは株式会社jig.jpの登録商標です。当ページはjig.jp社の作成物ではありません。(本サイトでは jig.jp の商品やソフトの名称として使用しています。)
  • 出典を明記した情報については前項に関わらず出典元の権利を継承します。

IchigoJam メインメニューへ戻るページの先頭へ戻る