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