忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

I2Cの設定(2)もう少し真面目に動かす

前回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を受信できているらしいことが確認できます。
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント