【I2C通信】
I2C(Inter-Integrated Circuit)は、フィリップス社が提唱した周辺デバイス
とのシリアル通信の方式で、主にEEPROMメモリICなどとの高速通信を実現
する方式です。
《参照》フィリップス社のI2Cの英文の仕様書は下記からダウンロード
できます
★フィリップス社I2Cホームページ
この当初の目的から推定されるように、I2Cは同じ基板内などのように近距離
で直結したデバイスと、100kbpsまたは400kbpsの速度でシリアル通信を行うよう
に使われるのが主で、離れた装置間の通信には向いていません。
I2Cは、マスタ側とスレーブ側を明確に分け、マスタ側が全ての制御の主導権
を持っています。
I2Cはパーティーライン構成が可能となっており、1つのマスタで複数のスレーブ
デバイスと通信することが可能です。
まずI2C通信のしくみは下図の構成を基本としています。
図のように1台のマスタと1台または
複数のスレーブとの間を、SCLとSDAと
いう2本の線でパーティーライン状に
接続します。
マスタが常に権限を持っており、マスタ
が送信するクロック信号SCLを基準に
して、データ信号がSDAライン上で転送
されます。
通信方式で類似のSPIと大きく異なるのは、個々のスレーブがアドレスを持って
いて、データの中にアドレスが含まれていることと、1バイト転送毎に受信側から
ACK信号の返送をして、互いに確認を取りながらデータ転送を行っていることです。
SSPをI2Cモードで使う時の通信手順の基本は、SCLとSDAの2本の信号線
ですべてのデータの送受信を行います。
SCLピン、SDAピンともに複数のスレーブを接続しますので、I2Cモードを選択
すると両ピンともオープンドレイン構成となります。
またスレーブ側は両ピンとも常時は入力モードにしてハイインピーダンス状態
にし、アドレスで指定された出力するデバイスだけ出力モードにする必要があ
ります。
(1) まずマスタ側が、Start Conditionを出力し続いてアドレスとRead/Write要求を
出力します。
(2) 全スレーブがこの時のSCLのクロックを元にSDAのデータを受信し、SSPADD
レジスタにセットされたアドレスと一致したデバイスだけが、その後の送受信を
継続します。
(3) 受信した側がデータを受信完了すると自動的にACKビットを返送し、同時に
SSP割込みを発生します。
(4) これをマスタがStop Conditionを出力するまで続けます。
このようにI2C通信もブロック転送ができますので、大量のデータを一気に転送
する時に便利に使うことが出来ます
【I2C通信のタイミング】
I2C通信の基本的な転送タイミングは下図のようになっています。
(1) マスタ側がSCLがHighの時にSDAをLowにしたときをスタートコンディション
とする。
(2) その後続けてマスタがクロックの供給を続けながらアドレスとRead/Write
要求のデータを送信します。
(3) この後は、アドレスで指定された1台のスレーブが、マスタと1対1で、指定
された方向で通信を行います。
つまり、SCLのクロックに従って送信側から8ビットのデータが出力され、
続いて受信側からアクノリッジ(ACK)信号が返送されます。
この時、受信する側は、受信データの取り出しが完了するまで、ビジーとして
SCLを強制的にLowにすれば、この間は見かけ上クロックが無くなるので、
送信側は次のデータを出力するのを待つことになります。
(4) 最後のデータを送り終わり、ACKを確認したあと、スレーブはSDAを解放する
ので、マスタがSDAをLowにしてクロックを停止してHighにしてから、SDAをHigh
にすることでストップシーケンスとなり通信は完了します。
【I2Cの通信データフォーマット】
I2C通信の基本的な通信のデータフォーマットは、アドレスフォーマットとデータ
フォーマットがあります。
まずアドレスフォーマットは下図のようになります。アドレスには7ビットモードと
10ビットモードがあり、図中の(a)(b)がそれぞれに対応します。
図中のACKビットは受信側から自動返信されるビットです。
![]()
通信データ全体のフォーマットは下図のようになり、マスタ側が送信側になるか
受信側になるかによって図の(a)(b)のように2種類のフォーマットとなります。
ここで、マスタが受信側になる場合には、まず最初にアドレスフォーマットの部分
で、受信側になることを特定スレーブに向けて送信し、それに続いて指定された
スレーブがデータの送信を始めます。マスタはデータを受信したらACKを返信します。
![]()
【C言語による使い方】
CCS Cコンパイラには、I2C通信をサポートする組込み関数が用意されています。
この関数を使うためには、プリプロセッサ関数でI2C通信を使うことを宣言して、関数
ライブラリを組み込む必要があります。
(1) プリプロセッサ関数
I2C用に用意されたプリプロセッサは、下表のようになっています。
プリプロセッサ関数 機能内容 #USE I2C(Master、
SDA=Pin,SCL=Pin options)I2Cライブラリをリンクし、I2Cとして使用する入出力ピンを特定します。
スレーブモードは内蔵のSSPモジュールがあるときのみ可能となりますが、マスターモードはどのPICでも有効となります。
NOFORCE_SW指定が無いときは、プログラムで機能するよう自動的に必要なプログラムモジュールを生成します。
optionsのパラメータ(複数指定可)
MASTER マスターモードにする
SLAVE スレーブモードにする
SCL=Pin SCLピンの指定
SDA=Pin SDAピンの指定
ADDRESS=nn スレーブモードのアドレスを設定
FAST 高速I2Cを指定(400kpbs)
SLOW 低速I2Cを指定(100kbps)
RESTRAT_WDT
I2CのREAD待ちの間WDTの自動リセットを
するように指定
NOFORCE_SW
内蔵SSPモジュールでI2Cを機能させるよう
指定
《例》
#USE I2C(master,sda=PIN_B0,scl=PIN_B1)
#USE I2C(slave,sda=PIC_C4,scl=PIC_C3
address=0xa0,NOFORCE_SW)
(2) I2C用組込み関数
前項のプリプロセッサでI2Cの使用を指定すると、下表の関数が組み込まれ使用
可能となります。これで、I2C通信をC言語で扱うことが可能となります。
組込み関数
機 能 内 容
I2C_START( ) I2Cのマスタモードの時、Start Conditionを出力する。このあとSCLはI2C_READかI2C_WRITEの実行までLowレベルに保たれます。 I2C_STOP( ) I2Cのマスタモードの時、Stop Conditionを出力します。但し出力するためには条件が整っていることが必要です。例を参照 b=I2C_WRITE(byte) 1バイトのデータをI2Cに出力します。マスタのときはこれでクロックを出力し,スレーブのときはクロックを待ちます。内蔵SSPモジュールを使わないときはタイムアウトは無いので送信完了まで永久待ちとなります。送信が完了すると、ACKビットをOnで返します
《例》
i2c_start( ); //start condition
i2c_write(0xa0); //device address
i2c_write(5); //device command send
i2c_write(12); //device data send
i2c_stop( ); //stop conditioni=I2C_READ( ) I2Cインターフェースからデータを読込みます。マスタモードの時はこの命令でクロックが出力されますが、スレーブモードの時はクロック出力を待ちます。
この命令は永久にデータを待ちます。従ってWDTを使用しているときはUSE関数でRESTART_WDTをパラメータ指定しておく必要があります。オプションパラメータで '0'を指定すると受信データに対しACKを返信しません。
《例》
i2c_start( ); //start condition
i2c_write(oxa1); //device address
r = i2c_read( ); //read first byte
r2 = i2c_read( ); //read second byte
i2c_stop( ); //stop conditionb=I2C_POLL( ) この命令は内蔵SSPモジュールを使っているときだけ有効です。受信バッファにデータが入っている時TRUEを返します。
TRUEがかえされたらできるだけ早くI2C_READ命令を実行する必要があります。
《例》
マスタが受信する場合
i2c_start( ); //start condition
i2c_write(0xc1); //deveice address
count=0;
while(count!=4) {
if(i2c_poll( ) )
r[count++]= i2c_read( ); //read next
} //do something here
i2c_stop //stop condition
【プログラムの作り方】
I2C通信は、外付けのEEPROMやA/D変換などとの通信になるので、PICがマスタ
になることが大部分ですので、マスタモードでのプログラミング方法について説明
します。
まず初期化で、I2C通信のモード設定でマスタモードを設定しておきます。
あとは、通信を始めるのはすべてマスタ側からとなります。
マスタ側がデータを送るか受けるかによって下図のようにプログラムの流れが変わ
ります。
![]()
【プログラム実例】
CCS Cコンパイラを使って簡単な例題を説明します。
この例題は、2つのPICの間でI2C通信を使ってデータ転送を行うものです。
(1)回路構成
回路を、下図に示しますが、PIC16F84がI2Cのマスタとなりデータを送信すると同時に
液晶表示器に送信データを表示します。
これに対し、I2Cで接続されたPIC16C73がスレーブとなってマスタからのデータを受信
すると同時に、液晶表示器に受信データを表示します。
送信データは0x30から0xFDまでを順次8個づつまとめてブロック転送します。
従って、I2C通信では、アドレスに続いて8個のデータが送信されることになります。
★I2Cテスト回路図(クリックして直接見られます)
(2)マスタ側プログラム
マスタとなるのはPIC16F84となります。当然SSPモジュールは内蔵していませんから、
プログラムでI2Cのマスタ機能を実現することになります。
また、液晶表示器も接続して表示制御をしていますが、これにはライブラリを利用して
います。このプログラムは下記リストとなります。
///////////////////////////////////////////////////////
// This program is a sample of I2C communication.
// This is a master mode program.
// This includes next functions.
// 1.Send ASCII code periodically to slave
// 2.Display send datas on LCD display
///////////////////////////////////////////////////////
#include <16f84.h>
#use fast_io(a)
#use delay(CLOCK=10000000)
//////// Port define and link LCD library
#define Bmode 0x0F //port B initial mode
#define Amode 0 //port A initial mode
#byte db = 6 //port B
//////// Port define and link LCD library
#define rs PIN_A2 //chip select
#define rw PIN_A1 //read/write
#define stb PIN_A0 //strobe
#include <lcd_lib.c> //LCD library of low byte mode
//////// I2C define
#use I2C(master, sda=PIN_A4, scl=PIN_A3)
/////////////////////////////////////////////////
main(){
int asci,i;
set_tris_a(Amode); //mode set of port
set_tris_b(Bmode); //lower is input
set_tris_c(0); //all output
lcd_init(); //initialize LCD
lcd_data("Start I2C test"); //display start message
delay_ms(3000); //delay 3sec
while(1){ //endless loop
asci=0x30; //initial start
lcd_clear(); //display clear
do {
i2c_start(); //start condition
i2c_write(0xa0); //address send
for(i=1;i<=8;++i) {
i2c_write(asci); //send data 8bytes
lcd_data(asci); //display send data
asci=asci+1;
delay_us(100); //delay 100usec
}
i2c_stop(); //stop condition
delay_ms(1000); //interval 1sec
}while(asci<0xFE); //30 to FD asci code
}
}
【解説】
#use I2C(master, sda=PIN_A4, scl=PIN_A3)
ここでI2CをマスタモードでSSPモジュール無しで使うことを宣言
している。また使う入出力ピンも指定している。
i2c_start();
スタートコンディションのシーケンス
i2c_write(0xa0);
アドレス送信のシーケンス
i2c_write(asci);
データ送信のシーケンス
i2c_stop();
ストップコンディションのシーケンス
(3)スレーブ側のプログラム例
スレーブ側は、PIC16C73で作成していますので、こちらはSSPモジュールを
使用します。
CCS Cコンパイラではスレーブ側にはSSPモジュールがあることを前提にして
いるようです。
SSPモジュールを使うといっても関数上は区別が無く、同じ形のプログラムと
なります。
ここでのスレーブは受信専用の使い方になっています。また液晶表示器に
受信データを表示しますのが、この制御にも液晶表示器用のライブラリを
使っていますが、マスタ側とはピン接続が異なるので別のライブラリとなって
います。
下記リストがスレーブ側のプログラム例となっています。
///////////////////////////////////////////////////////
// This program is a sample of I2C communication.
// This is a slave mode program.
// This includes next functions.
// 1.Receive data from I2C master CPU
// 2.Display received datas on LCD display
///////////////////////////////////////////////////////
#include <16c73.h>
#use fast_io(a)
#use delay(CLOCK=10000000)
//////// Port define and link LCD library
#define Bmode 0xF0 //port B initial mode
#define Amode 0x13 //port A initial mode
#byte db = 6 //port B
#define rs PIN_A5 //chip select
#define rw PIN_A3 //read/write
#define stb PIN_A2 //strobe
#include <lcd2_lib.c> //LCD library of low byte mode
/////// I2C define
#use I2C(slave, sda=PIN_C4, scl=PIN_C3, address=0xa0, NOFORCE_SW)
////////////////////////////////////////////
main(){
int indata;
set_tris_a(Amode); //mode set of port
set_tris_b(Bmode); //lower is input
set_tris_c(0x99);
lcd_init(); //initialize LCD
lcd_data("Start I2C test"); //display start message
while(1){ //endless loop
if(i2c_poll()){
indata = i2c_read(); //get data from I2C
lcd_data(indata); //display data on LCD
}
}
}
【解説】
#use I2C(slave, sda=PIN_C4, scl=PIN_C3, address=0xa0, NOFORCE_SW)
これでI2C通信をSSPモジュールで使用することを宣言している。同時に
スレーブアドレスと使用する入出力ピンも指定しています。
if(i2c_poll()){
indata = i2c_read();
ここで、受信が完了したかをチェックし、完了していればデータを
読込みます。