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モジュールデータシートより
© Copyright 2024 ExpyDoc