前回は
I2Cの基本動作理解のために無理矢理動かしましたが、今回はもう少し真面目に
動かしてみます。
関連
I2CとはI2Cの設定(1)無理矢理動かすI2Cの設定(3)関数化I2Cを試してみるバスをI2C本来の姿であるプルアップ仕様にします。
前回はポートを出力設定にしたままでHまたはLを出力していました。
しかし、このままではマスターからHを出力している際にスレーブがLを返信すると
マイコンのポートが壊れてしまいます。
これを防ぐためには出力を制御しつつ、マスターから直接Hを出力しないようにする
必要があります。バスはプルアップされているため、何も出力されていない状態では
Hになります。
そこで0を送信するときはLを出力し、1を送信するときは何も出力しないようにすれ
ばマスターのHとスレーブのLが衝突して壊れる事はなくなります。
また、H送信中はスレーブからLが送信されたことを検出する必要があります。
入出力独立仕様(今回は使わない)

これについてはトランジスタとポートを使用する方法もありますが、今回はシンプルに
L送信時はポートを出力設定にして0を出力し、H送信時はポートを入力設定にしてプル
アップでバスをHにしつつ入力を受け付けることにします。
入出力統合仕様(今回使用する)
SCLについても同様の処理を行います。
入出力の切り替えはマイコン内で処理するため、マイコン外部はプルアップだけになります。
ポート設定
PE0,PE1にはLEDが繋がっているため他のポートを使用します。
通信系を一ヵ所にまとめたいので、I2CにはPA2,PA5を使用します。
外部割込みの会でPA2,PA5を外部割込み端子に設定していましたが、今後は外部割り込み
機能をPB2,PB5へ移植します。

実際に配線は以下となります。
プログラム
前回のプログラムに追記します。
太字が追記部分です。
#include "iodefine.h"#include "io_setup.h"
//I2Cプロトタイプ宣言void init_I2C(void);//I2C初期化void set_SCL(int); //SCL出力設定void set_SDA(int); //SDA出力設定int get_SCL(void); //SCL状態取得int get_SDA(void); //SDA状態取得main(){
int i=0;
int count=0;
//内部カウント int scl=1,sda=1;
//バス状態は1 int addless;
int data[2];
int stop_f=0;
hardware_setup();
//入出力の初期化 init_I2C(); //I2C機能の初期化 set_LED_R(scl);
//LED赤の初期化(クロック) set_LED_G(sda);
//LED緑の初期化(データ) set_SCL(scl); //クロックの初期化 set_SDA(sda); //データの初期化 /*変数の初期化*/ addless=0xC8;
//アドレスの設定 data[0]=0;
//データ0の設定(サブアドレス) data[1]=0x49;
//データ1の設定(電圧、正転逆転) /*メインループ*/ while(1){
i++;
if(i>40000){
//40000カウントごとに処理 i=0;
count++;
//内部カウントを1増加 }
//クロック出力の設定 if(stop_f){
//通信停止中 scl=1;
//バス開放 count=0;
//カウントリセット i=0;
//カウントリセット }
else if((count/2)%2){
//2で割って、更に2で割った余りが0でないとき2,3,6,7,10,11・・・・ scl=0;
}
else{
//それ以外 scl=1;
}
//end count switch(count){
//内部カウントに応じてSDAを設定 case 0:
sda=1;
break;
case 1:
//スタートコンディション sda=0;
break;
case 3+4*0:
//3 アドレスbit7 sda=(addless&0x80)?1:0;
break;
case 3+4*1:
//7 アドレスbit6 sda=(addless&0x40)?1:0;
break;
case 3+4*2:
//11 アドレスbit5 sda=(addless&0x20)?1:0;
break;
case 3+4*3:
//15 アドレスbit4 sda=(addless&0x10)?1:0;
break;
case 3+4*4:
//19 アドレスbit3 sda=(addless&0x08)?1:0;
break;
case 3+4*5:
//23 アドレスbit2 sda=(addless&0x04)?1:0;
break;
case 3+4*6:
//27 アドレスbit1 sda=(addless&0x02)?1:0;
break;
case 3+4*7:
//31 アドレスbit0 sda=(addless&0x01)?1:0;
break;
case 3+4*8:
//35 ACK待ち sda=1;
break;
case 3+36+4*0:
//39 データ0bit7 sda=(data[0]&0x80)?1:0;
break;
case 3+36+4*1:
//43 データ0bit6 sda=(data[0]&0x40)?1:0;
break;
case 3+36+4*2:
//47 データ0bit5 sda=(data[0]&0x20)?1:0;
break;
case 3+36+4*3:
//51 データ0bit4 sda=(data[0]&0x10)?1:0;
break;
case 3+36+4*4:
//55 データ0bit3 sda=(data[0]&0x08)?1:0;
break;
case 3+36+4*5:
//59 データ0bit2 sda=(data[0]&0x04)?1:0;
break;
case 3+36+4*6:
//63 データ0bit1 sda=(data[0]&0x02)?1:0;
break;
case 3+36+4*7:
//67 データ0bit0 sda=(data[0]&0x01)?1:0;
break;
case 3+36+4*8:
//71 ACK待ち sda=1;
break;
case 3+36*2+4*0:
//75 データ0bit7 sda=(data[1]&0x80)?1:0;
break;
case 3+36*2+4*1:
//79 データ0bit6 sda=(data[1]&0x40)?1:0;
break;
case 3+36*2+4*2:
//83 データ0bit5 sda=(data[1]&0x20)?1:0;
break;
case 3+36*2+4*3:
//87 データ0bit4 sda=(data[1]&0x10)?1:0;
break;
case 3+36*2+4*4:
//91 データ0bit3 sda=(data[1]&0x08)?1:0;
break;
case 3+36*2+4*5:
//95 データ0bit2 sda=(data[1]&0x04)?1:0;
break;
case 3+36*2+4*6:
//99 データ0bit1 sda=(data[1]&0x02)?1:0;
break;
case 3+36*2+4*7:
//103 データ0bit0 sda=(data[1]&0x01)?1:0;
break;
case 3+36*2+4*8:
//107 ACK待ち sda=1;
break;
case 3+36*3:
//111 ストップコンディション準備 sda=0;
break;
case 3+36*3+2:
//113 ストップコンディション sda=1;
stop_f=1;
break;
default:
// 2018/09/22 誤記修正 break;
}
//end switch set_LED_R(scl);
//LED赤(クロック)を出力 set_LED_G(sda);
//LED緑(データ)を出力 set_SCL(scl); //クロックを出力 set_SDA(sda); //データを出力 }
//end while}
//end main//I2C初期化void init_I2C(void){ //ポートAの入出力を設定する PFC.PAIORL.BIT.B2 = 0; //入力 PFC.PAIORL.BIT.B5 = 0; //入力 //出力値を初期化する PA.DRL.BIT.B2=0; //出力値は0 PA.DRL.BIT.B5=0; //出力値は0}//end init_I2C//SCL出力設定void set_SCL(int value){ PA.DRL.BIT.B2=0; //出力値は0 if(value){ PFC.PAIORL.BIT.B2 = 0; //H(入力) }else{ PFC.PAIORL.BIT.B2 = 1; //L(出力) }}//end set_SCL//SDA出力設定void set_SDA(int value){ PA.DRL.BIT.B5=0; //出力値は0 if(value){ PFC.PAIORL.BIT.B5 = 0; //H(入力) }else{ PFC.PAIORL.BIT.B5 = 1; //L(出力) }}//end set_SDA//SCL状態取得int get_SCL(void){ return PA.DRL.BIT.B2;}//SDA状態取得int get_SDA(void){ return PA.DRL.BIT.B5;}前回同様に実行してモーターが回れば成功です。
LEDとバスのプルアップ抵抗より十分大きな抵抗を使えば、バスの状態を視認する事が
できます。
10kΩを使用しました。
ベースボードのLEDと比較するとスレーブからのACK返信の確認ができます。
受信テスト(2018/09/22)
このまま受信してみます。
switch部分を以下の様に変更します。
<設定>
switch(count){
//内部カウントに応じてSDAを設定 case 0:
sda=1;
break;
case 1:
//スタートコンディション sda=0;
break;
case 3+4*0:
//3 アドレスbit7 sda=(addless&0x80)?1:0;
break;
case 3+4*1:
//7 アドレスbit6 sda=(addless&0x40)?1:0;
break;
case 3+4*2:
//11 アドレスbit5 sda=(addless&0x20)?1:0;
break;
case 3+4*3:
//15 アドレスbit4 sda=(addless&0x10)?1:0;
break;
case 3+4*4:
//19 アドレスbit3 sda=(addless&0x08)?1:0;
break;
case 3+4*5:
//23 アドレスbit2 sda=(addless&0x04)?1:0;
break;
case 3+4*6:
//27 アドレスbit1 sda=(addless&0x02)?1:0;
break;
case 3+4*7:
//31 アドレスbit0 sda=(addless&0x01)?1:0;
break;
case 3+4*8:
//35 ACK待ち sda=1;
break;
case 3+36+4*0:
//39 データ0bit7 sda=(data[0]&0x80)?1:0;
break;
case 3+36+4*1:
//43 データ0bit6 sda=(data[0]&0x40)?1:0;
break;
case 3+36+4*2:
//47 データ0bit5 sda=(data[0]&0x20)?1:0;
break;
case 3+36+4*3:
//51 データ0bit4 sda=(data[0]&0x10)?1:0;
break;
case 3+36+4*4:
//55 データ0bit3 sda=(data[0]&0x08)?1:0;
break;
case 3+36+4*5: //59 データ0bit2
sda=(data[0]&0x04)?1:0;
break;
case 3+36+4*6:
//63 データ0bit1 sda=(data[0]&0x02)?1:0;
break;
case 3+36+4*7:
//67 データ0bit0 sda=(data[0]&0x01)?1:0;
break;
case 3+36+4*8:
//71 ACK待ち sda=1;
break;
case 3+36*2+0:
//75 リスタート準備 sda=1;
break;
case 3+36*2+2:
//77 リスタート sda=0;
break;
case 3+4+36*2+4*0:
//79 アドレスbit7 sda=(addless&0x80)?1:0;
break;
case 3+4+36*2+4*1:
//83 アドレスbit6 sda=(addless&0x40)?1:0;
break;
case 3+4+36*2+4*2:
//87 アドレスbit5 sda=(addless&0x20)?1:0;
break;
case 3+4+36*2+4*3:
//91 アドレスbit4 sda=(addless&0x10)?1:0;
break;
case 3+4+36*2+4*4:
//95 アドレスbit3 sda=(addless&0x08)?1:0;
break;
case 3+4+36*2+4*5:
//99 アドレスbit2 sda=(addless&0x04)?1:0;
break;
case 3+4+36*2+4*6:
//103 アドレスbit1 sda=(addless&0x02)?1:0;
break;
case 3+4+36*2+4*7:
//107 アドレスbit0 sda=1;
//読出しなので1 break;
case 3+4+36*2+4*8:
//111 ACK待ち sda=1;
break;
case 3+4+36*3+4*0:
//115 データ受信bit7 sda=1;
break;
case 3+4+36*3+4*1:
//119 データ受信bit6 sda=1;
break;
case 3+4+36*3+4*2:
//123 データ0bit5 sda=1;
break;
case 3+4+36*3+4*3:
//127 データ0bit4 sda=1;
break;
case 3+4+36*3+4*4:
//131 データ0bit3 sda=1;
break;
case 3+4+36*3+4*5:
//135 データ0bit2 sda=1;
break;
case 3+4+36*3+4*6:
//139 データ0bit1 sda=1;
break;
case 3+4+36*3+4*7:
//143 データ0bit0 sda=1;
break;
case 3+4+36*3+4*8:
//147 NOACK sda=1;
break;
case 3+4+36*4:
//151 ストップコンディション準備 sda=0;
break;
case 3+4+36*4+2:
//153 ストップコンディション sda=1;
stop_f=1;
break;
default:
break;
}
//end switchまともに受信処理を作成していませんが、デバッグLEDにて0を受信できているらしいことが確認できます。