説明資料

IC
2
Inter Integrated Circuit
2線(データとクロック)でIC間の通信を行う.(注,実際にはGNDも必要)
たくさんのデバイスがあっても,2つの線だけで接続できる.
それぞれのデバイスには,アドレス(7bit = 128個)が割り振られて,識別できる.
バス上には一つのマスターデバイスが存在
(マスターデバイスは動的に変更できるが,通常はマイコンをマスターとして固定して使う)
(USBなどと比べて)通信規則が単純なので,マイコンやセンサーなどの小さいデバイス間の通信
に適している.
誤り検出,訂正の仕組みがないので,大きなノイズがのる可能性のある長距離伝送にはあまり向かない
I2C,マスタとスレーブ
マスタ-
スレーブ
バス上に(同時には)1つのみ存在が許される,唯一絶対の存在
クロック(SCL)は常にマスターが駆動
ー>通信のタイミングはすべてマスタが支配する
データ通信の相手は,初めにマスタが指定する.
この指定されたデバイスのみがマスターとデータを送(受)信する.
指定されなかったデバイスは,通信が終わるまで何もしない(通信に燗する動作は).
その他大勢.
それぞれ個別の名前(=アドレス)を持っていて,自分と他人を区別できる.
マスタからご指名があったら,その要求(送信か受信)にしたがってデータを通信する
(1)通信相手と通信方向を指定
I2C,マスタとスレーブ
マスタ-
スレーブ
バス上に(同時には)1つのみ存在が許される,唯一絶対の存在
クロック(SCL)は常にマスターが駆動
ー>通信のタイミングはすべてマスタが支配する
データ通信の相手は,初めにマスタが指定する.
この指定されたデバイスのみがマスターとデータを送(受)信する.
指定されなかったデバイスは,通信が終わるまで何もしない(通信に燗する動作は).
その他大勢.
それぞれ個別の名前(=アドレス)を持っていて,自分と他人を区別できる.
マスタからご指名があったら,その要求(送信か受信)にしたがってデータを通信する
(2)データを送信,または受信
他のデバイスは何もしない
I2Cの通信信号
通信開始信号
通信終了信号
通信の最小単位(1バイト)
最初の1バイトでアドレスと送受信方向を指定
2バイト目からは,実際のデータの送受信
LIS3DH
MEMS 3軸加速度センサ
(3-axis Accelerometer)
http://akizukidenshi.com/img/goods/C/K-06791.jpg
LIS3DHデータシート, STMicroelectronics NV
LIS3DHの使い方
LIS3DHのレジスタへの数値の書き込み
Protocol to write data to the register of the LIS3DH.
S
Start
Address(0x18)
W
0
Register address
Data
P
Stop
LIS3DH datasheet
LIS3DHの使い方
LIS3DHのレジスタへの数値の書き込み
Protocol to write data to the register of the LIS3DH.
S
Ex.)
Address(0x18)
W
0 0 1 1 0 0 0 0
0
Register address
0 0 1 0 0 0 0 0
0x20
… CTRL_REG_1
LIS3DH datasheet
Data
P
0 1 0 1 0 1 1 1
Data rate = 100 Hz
Normal mode
All X, Y and Z axis enabled
LIS3DHの使い方
LIS3DHのレジスタからのデータの読み込み
Protocol to read data from the register of the LIS3DH.
S
Address(0x18)
W
0
Register address
レジスタアドレスのセット
Set register address
Data
...
レジスタのデータ
Data from the register
P
Repeated start
Sr
Address(0x18)
読み込みスタート
Start reading
R
LIS3DHの使い方
LIS3DHのレジスタからのデータの読み込み
Protocol to read data from the register of the LIS3DH.
S
Address(0x18)
W
0 0 1 1 0 0 0 0
0
Register address
0 0 0 0 1 0 0 0
レジスタアドレスのセット (0x08 = OUT_1_L)
Set register address
Data
P
X-軸の計測値(の下位8bit)
Least significant byte of X-axis acceleration
Repeated start
Sr
Address(0x18)
R
0 0 1 1 0 0 0 1
読み込みスタート
Start reading
レジスタアドレスの自動更新
Auto increment of register address
S
Address(0x18)
W
0 0 1 1 0 0 0 0
0
Register address
1 0 0 0 1 0 0 0
レジスタアドレスのセット (0x08 = OUT_1_L)
Set register address
Sr
Address(0x18)
R
0 0 1 1 0 0 0 1
読み込みスタート
Start reading
ここを1にすると
Data
Data
Data
OUT_1_L(0x08)
の値
OUT_1_H(0x09)
の値
OUT_2_L(0x0A)
の値
一つ読み出すことに,レジスタのアドレスが一つづつ増える.
→ 連続してデータを読み出せる
Register address is automatically increased
...
P
I2C通信用関数
Start コンディション送信用関数
(Function for start condition)
I2Cバスが空いているか調べる
int i2c_start(){
(is I2C bus idle?)
i2c_wait_idle();
I2C1CONbits.SEN = 1;
Startを送信する
while(I2C1CONbits.SEN)
(Send Start condition)
;
if(I2C1STATbits.BCL) return ERR_I2C_BUS_COLLISION; //Bus collision
return 0;
Start送信が終わるのを待つ
もし,他のデバイスが同時にスタータを送信
(Wait Start condition ends)
したら,衝突が生じる (Bus collision ?)
ー>エラー (Return error code)
Stop コンディション送信用関数
(Function for stop condition)
int i2c_stop(){
I2C1CONbits.PEN = 1;
while(I2C1CONbits.PEN)
;
}
Stopを送信する
(Send Stopt condition)
Stop送信が終わるのを待つ
(Wait Stop condition ends)
I2C通信用関数
1byte 送信用関数
(Function for 1 byte transmission)
送信したいデータをレジスタ(I2C1TRN)に入れる
int i2c_write(unsigned char data){
(Copy transmit data into the register “I2C1TRN”)
I2C1TRN = data;
送信が終わるのを待つ
while(I2C1STATbits.TBF)
(Wait to finish the data transmission)
;
i2c_wait_idle();
スレーブからAckが帰ってきたか確認
if( I2C1STATbits.ACKSTAT){ //Ack??
(Slave returns “ACK”?)
//If NACK received
I2C1CONbits.PEN = 1;
//Stop condition
while(I2C1CONbits.PEN)
;
return ERR_I2C_SLAVE_NAK;
}
}
もしNAKなら,スレーブはデータを受け取れていない
ー>エラーを返す
(If “NAK” returns, the slave device didn't receive the data
→ return error code )
I2C通信用関数
1byte 受信用関数
(Function for 1 byte receive)
int i2c_read(unsigned char *data){
i2c_wait_idle();
受信動作を開始
(Start receiving the data from slave device)
I2C1CONbits.RCEN = 1; //Enable the receiver
while( ! I2C1STATbits.RBF)
受信が終わるのを待つ
;
(Wait to complete receiving)
i2c_wait_idle();
*data = I2C1RCV;
}
受信レジスタのデータを読み込む
(Read the data from “I2C1RCV” register)
I2C通信用関数(例1)
例えば,以下のような通信をしたいときには,以下の関数のような処理をすれば良い.
(When you want to send the data as below, the procedure is like below)
S
Ex.)
Address(0x18)
W
0 0 1 1 0 0 0 0
0
Register address
0 0 1 0 0 0 0 0
int ST_putc(BYTE addr, BYTE reg, BYTE data){
int ret;
if( ret= i2c_start() ) return ret;
if( ret= i2c_write( addr | I2C_WR) ) return ret;
if( ret= i2c_write( reg ) ) return ret;
if( ret= i2c_write( data ) ) return ret;
i2c_stop();
return 0;
}
Data
0 1 0 1 0 1 1 1
P
I2C通信用関数(例2)
S
Address(0x18)
Data
W
0
Register address
Sr
Address(0x18)
R
P
int ST_getc(BYTE addr, BYTE reg, BYTE* data){
int ret;
if( ret = i2c_start() ) return ret;
if( ret = i2c_write( addr | I2C_WR ) ) return ret;
if( ret = i2c_write( reg ) ) return ret;
if( ret = i2c_rep_start() ) return ret;
if( ret = i2c_write( addr | I2C_RD ) ) return ret;
i2c_read(data);
i2c_master_nak();
i2c_stop();
読み込みを終了するときは,マスターはNAKを送信する.
(When finish reading the data, master send “NAK”)
return 0;
}
I2Cジュールの初期化
(I2C module initialize)
void InitI2C(){
I2C1BRG = 157; //100 kHz @ Fcy = 16MHz
I2C1CON = 0x00;
通信速度の設定
(Data transfer rate)
I2C1CONbits.DISSLW = 0; //Slew rate controle(0:enable, 1:disable)
I2C1CONbits.I2CEN = 1; //Enable I2C module
}
LIS3DH用関数
加速度データが準備できているか調べる
(Inquire whether the data is available)
I2Cのアドレス
(Register address of I2C)
LIS3DH レジスタアドレス
(Register address of LIS3DH)
int LIS3DH_is_new_data(){
BYTE data;
ST_getc(LIS3DH_I2CAddr, LIS3DH_STATUS_REG, &data);
if( data | 0x0f){
変数dataに結果を読み込む
return (int)data;
(read to a variable “data”)
}else{
変数dataが0x0fならデータが準備出来ている
return 0;
(If “data=0x0f”, data is available)
}
詳しくはデータシート参照
}
(Refer the data sheet)
この関数は myI2C.cで定義されている.
(This function is defined in MyI2C.c)
LI3DHデータシートより
LIS3DHから加速度データを読み出す関数
Function to read acceleration
//Return data: short acc[3]
int LIS3DH_read_Acc(short acc[]){
void* data;
int len;
int i, ret;
BYTE reg_start;
reg_start = LIS3DH_OUT_X_L;
data = acc;
Len = 6;
レジスタアドレスを設定
if( ret = i2c_start() )
(Register address setting)
return ret;
if( ret = i2c_write( LIS3DH_I2CAddr | I2C_WR ) )
return ret;
if( ret = i2c_write( reg_start | 0x80 ) )
return ret;
Auto increment
if( ret = i2c_rep_start() )
return ret;
if( ret = i2c_write( LIS3DH_I2CAddr | I2C_RD ) )
return ret;
データ受信開始
(Start receiving)
//Data read
for(i=0; i<len; i++){
i2c_read( (BYTE*)(data)+i );
if(i<len-1){
i2c_master_ack();
}else{
i2c_master_nak();
}
}
i2c_stop();
return ret;
}
1バイト受信
(受信後,レジスタアドレスは+1
される)
(Read 1 byte, Register
address will be increment)
LIS3DH_read_acc()
short acc[3]
Address n
n+1 n+2 n+3 n+4 n+5
acc[0]
void* data;
:
data = acc;
acc[1]
acc[2]
data (ポインタ)が指し示す場所
①1回目(i=0)
i2c_read( (BYTE*)(data)+i );
まずは,ここにデータが書き込まれる
//Data read
for(i=0; i<len; i++){
i2c_read( (BYTE*)(data)+i );
if(i<len-1){
i2c_master_ack();
}else{
i2c_master_nak();
}
}
i2c_stop();
return ret;
}
LIS3DH_read_acc()
short acc[3]
Address n
n+1 n+2 n+3 n+4 n+5
済
acc[0]
void* data;
:
data = acc;
acc[1]
acc[2]
data+1 が指し示す場所
②2回目(i=1)
i2c_read( (BYTE*)(data)+i );
次に,ここにデータが書き込まれる
//Data read
for(i=0; i<len; i++){
i2c_read( (BYTE*)(data)+i );
if(i<len-1){
i2c_master_ack();
}else{
i2c_master_nak();
}
}
i2c_stop();
return ret;
}
これを len(=6)回繰り返すと,acc[3]にすべてデータが書き込まれる.
(注)shortみたいな多バイト変数の場合は,データの詰め込み方に注意(リトル/ビックエンディアン)
例えば0x1234の2バイトデータは 0x12,0x34の順にメモリに配置される場合と,0x34, 0x12の順に
メモリに配置される場合がある.(今回の場合は後者)
LIS3DHからは,Lower Byte, Higher Byteの順で送ってくるので,上のようにしてやればうまく行く
加速度センサへの配線(追加分のみ)
3.3V
LIS3DH(モジュール)
PIC24FJ32GA002
1
2.4k
17
18
GND
SCL
SDA
2
3
4
http://akizukidenshi.com/img/goods/C/K-06791.jpg
※モジュールは裏面のAとC
をはんだ付しておくこと
LIS3DHモジュールデータシートより