-
I2Cの設定
CSCコンパイラで 16F88に対し、I2C のマスタを機能を設定するには以下のようにします。
#use i2c(master,sda=PIN_B1,scl=PIN_B4)
先頭の master が、マスタとなる設定、sda=PIN_B1, scl=PIN_B4 はsda 信号とscl 信号の端子を指定します。スレーブの場合は以下のように設定します。
#use I2c(slave,sda=PIN_B1,scl=PIN_B4,address=0x62,force_hw)
先頭の slave でスレーブ機能を設定します。異なるのは、address=0x62 でアドレスを設定することと、最後の force_hw
です。これは、i2c の機能をハードウエアで実行することを指示します。実は、16F88 の場合、スレーブの機能はハードウエアで実装されていますが、マスタの機能は実装されていないため、ソフトウエアで行う必要があります。16F88
に対し、
#use i2c(master,sda=PIN_B1,scl=PIN_B4,force_hw)
を指定すると、期待通りの動作はしませんから、注意してください。ただし、16F873の場合、マスタ機能もハードウエアで実装されていますから、上記の設定が可能です。
-
I2Cのマスタ側アクセス関数
マスタとして、スレーブにデータを送るには、以下のような関数呼び出しをします。
i2c_start(); //スタートコンディション
i2c_write(Leddva);
//delay_us(20);
i2c_write(val %12 );
i2c_stop();
i2c_start(); で開始し、スタート状態を設定します。次に、i2c_write(Leddva); で、スレーブのアドレスを指定します。自分のアドレスを受け取ったスレーブのみが、以下のデータを受け取ります。i2c_write(val
%12 ); でLEDの点灯パタンを送ります。val %12 は特に意味がありません。スレーブのLED が4個なので、15以内のデータであれば表示ができます。続くデータがあれば、i2c_write(val
%12 ); で次のデータを送りますが、ここでは不要なので、i2c_stop(); で終了します。
この呼び出しは、16F88でも16F873でも同じです。
-
I2Cのスレーブ側のアクセス関数(ハード処理の場合)
I2Cをハードウエアで処理できる場合、スレーブ側は割り込み機能を利用できます。マスタが指定したアドレス以外のスレーブは割り込みがありませんから、殆ど負荷はかかりません。
#INT_SSP
void ssp_interupt (){ }
で、I2C の割込み関数を宣言します。state = i2c_isr_state(); で割込みの状態を知ります。state が 0 より大きく
0x7F 以下なら、データを受信したことを意味します。val2=i2c_read() でデータを受け取ることができます。
データが 0x80 以上の場合は、マスタからのデータ要求を意味します。i2c_write( ) で直ちにマスタにデータを送り必要があります。
スレーブはマスタの要求に対して応答すればよいので、ハードウエアの支援がある場合割り込み処理で I2C の処理を行うことができます。
-
16F873のマスタ側プログラム
16F873によるマスター側のプログラムを紹介します。valの値を増やしながら、I2Cのスレーブに送ります。#use i2C()は FORCE_HW
でハードウエア機能を利用します。
//////////////////////////////////////////////////
// I2Cマスターテストプログラム //
//I2CでLED点灯
//I2Cデバイスアドレスは0x64
//コマンド (val)、valは4bit
//マスタの回路は、C4,C3をI2C接続
//A0 をLED表示(動作確認用)
#include <16f873.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT
#use delay(clock = 20000000)
#use i2c(MASTER,sda=PIN_C4,scl=PIN_C3,FORCE_HW)
//メイン関数/////////////////////////////////////////
#define Leddva 0x64
int val;
//int tm,num;
void main(){
val=0;
//tm=0;
//set_tris_c(0x99); //RB 7-4:IN 3-0:OUT
output_float(PIN_C3); //I2C pin float
output_float(PIN_C4); //I2C pin float
//Cポートに出力する場合、set_tris_c()が必要
delay_ms(100); //wait for Client up
while(1){
output_toggle(PIN_A0);//動作確認
i2c_start(); //スタートコンディション
i2c_write(Leddva);
//delay_us(20);
i2c_write(val %12 );
i2c_stop();
val++;
delay_ms(20);
}
}
-
16F873のスレーブ側プログラム
マスタがデバイスアドレス 0x64 にデータを送信した場合、マスタからのデータを受け取り LED に表示します。ハードウエアの機能でI2C割り込みを利用して受信します。
//i2cLEDSlv873.c
//割り込みでi2cからデータを受け取りLEDを点灯
//
#include <16F873A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT
#use delay(clock = 20000000)
#use I2c(slave,sda=PIN_C4,scl=PIN_C3,address=0x64,force_hw)
#use fast_io(C)
#use fast_io(B)
int val2;
int state;
#INT_SSP
void ssp_interupt (){
state=i2c_isr_state();
//output_toggle(PIN_A0);
if(state>=0x80){//addrs match with master read
//i2c_write(0);//return value
}
else if(state >0){//adrs match with master write
val2=i2c_read();//1:ack,default 0:nack
output_b(val2);
}
}
void main (){
set_tris_b(0xF0);
output_float(PIN_C4); //I2C pin float
output_float(PIN_C3); //I2C pin float
set_tris_c(0xFE);
val2=0;
enable_interrupts(INT_SSP); //SSP割り込みを許可
enable_interrupts(GLOBAL); //全ての割り込みを許可
while (1) {
//output_a(val2);
}
}
このプログラムの流れは、16F88 の場合も同様です。データ受信後に表示するLEDのポートが異なる(AポートにLEDを接続)のみです。