忍者ブログ

Fグループ電子工作講座

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

使用ポート数増加

例として
PE4~7出力
PA10~15入力
に設定してみます。


ポートEとポートAの中途半端な位置に設定しています。

PE0,1:既にLEDに接続されているのほっときます。
PE2,3:PE2は既にスイッチに接続されています。PE3も入力にしておきます。
PE4~7:汎用出力として設定します。
PE8~15:今後特殊機能(PWM出力)に設定するのでほっときます。

PA0~9:今後特殊機能(通信、パルス入力等)に設定するのでほっときます。
PA10~15:汎用入力として設定します。

今回はPA10~15およびPE4~7をまとめて設定する関数を作成します。

※マイコンにLEDを直結するとマイコンとLEDが壊れます。



前回LEDの点灯関数として以下を作成しました。

void set_LED_R(int on){
  if(on!=0)
    PE.DRL.BIT.B0=1;
  else
    PE.DRL.BIT.B0=0;
}


int get_sw1(void){
    return PE.DRL.BIT.B2;
}


入出力の点数が少ない場合はこの様な関数で問題無いと思います。
しかし、入出力の点数が多い場合はどうでしょう。

たとえば入力が50ピン、出力が50ピンあった場合。
1端子につき1つ関数を作るならこれだけで100個もの関数を作る羽目になります。
これは労力の無駄です。

そこで、入力と出力をまとめて操作する関数を作成します。

今回は未設定の部分を新規に使用するのでまずは初期化関数の変更から

初期化関数の更新

/*============= マイコン端子の初期化関数 =============*/
void hardware_setup(void){
    //ポートEの特殊機能設定
    //今回はポートEの0~15を全て汎用IOに設定する(特殊機能不使用)
    PFC.PECRL4.WORD = 0x0000;    //PE15-12
    PFC.PECRL3.WORD = 0x0000;    //PE11-08
    PFC.PECRL2.WORD = 0x0000;    //PE07-04
    PFC.PECRL1.WORD = 0x0000;    //PE03-00

    //ポートEの入出力を設定する
    //7,6,3,2を入力それ以外は出力 ⇒ 訂正:3,2を入力それ以外は出力
    //1111 1111 1111 0011(2進数)
    //   F    F    F    3(16進数)
    PFC.PEIORL.WORD = 0xFFF3;
    // !!!注意!!!
    //ベースボードを接続する場合PE02は出力に設定しないこと。

    //ポートAの特殊機能設定
    PFC.PACRL4.WORD = 0x0000;    //PA15-12
    PFC.PACRL3.WORD = 0x0000;    //PA11-08

    //ポートAの入出力を設定する
    PFC.PAIORL.WORD = 0x0000;    //全部入力

}

コメント
あるポートを使用したい場合には本来どの設定を変更するかはベースボード付属CDの「資料」フォルダ内にあるハードウェアマニュアルを調べる必要があります。ハードウェアマニュアルはマイコンCPUの取扱説明書に相当しますが、マイコンの種類によって数百ページ数千ページあります。しかもこの内容はマイコンの種類ごとのに異なります。このサイトを見てマイコンの勉強を始めた人にこのハードウェアマニュアルから特定の情報を探し出すことは困難だと思います。
現時点ではハードウェアマニュアルは気にせず、そのままコピー&ペーストで動かしてしまってもかまわないと思います。

※私の手元にあるファイルでは「rjj09b0249_sh7125_7124hm.pdf」となっていました。
 ハードウェアマニュアルは時々更新されるので「rjj09b0249」の部分はベースボードの
 出荷時期によって異なるかと思います。
※SH7125の最新版ハードウェアマニュアルはルネサスのHPからダウンロードできます。

この設定が何を意味するかは秋月sh7125サンプルプログラム解説を参照ください。


入力関数の作成

/*============= PortA入力関数 =============*/
int get_PortA_bit(int bit){
    int state=0;    //変数を宣言しておく
    int outdata=0;    //変数を宣言しておく

    if( bit<10 || bit>15 )    //関係ない端子を指定した場合
        return -1;            //0,1以外の数値を返して強制終了
   
    state = PA.DRL.WORD&(0x0001<<bit);    //0または0以外の値として取得
    outdata = (state==0)? 0 : 1 ;        //0-1に変換
    return outdata;    //指定したポートの状態を返す
}

<解説>

ビット演算も合わせてご参照ください。
state = PA.DRL.WORD&(0x0001<<bit);

スイッチを1つずつ読む場合は
PE.DRL.BIT.B2
と書いていましたが、今回はポートAを一度に読む機能を使用するため
PA.DRL.WORD
としてアクセスします。

(0x0001<<bit)
この部分はビットシフト演算です。
例えばbitの値が12(13番目)だった場合を考えます。
分かりやすくするため0x0001を2進数で表記してみます

0b0000000000000001 << 12

0b0001000000000000
ヒットシフトを行うとこの様にビットの位置がずれます。

PA.DRL.WORD&ビットシフト値
これによりビットシフトした場所の情報を抜き出すことができます。

   0b0110111000100110
& 0b0001000000000000
   ↓
   0b0000000000000000

   0b1001010100111001
& 0b0001000000000000
   ↓
   0b0001000000000000

ビットシフトした場所のビットが0だった場合は0になります。
ビットシフトした場所のビットが1だった場合は0以外(ビットシフト値)になります。

outdata = (state==0)? 0 : 1 ;
?:の組み合わせは三項演算子と呼ばれています。
内部処理で良く使われていますが、授業で目にすることはほとんど無いでしょう。

三項演算子の使い方は以下となります。
 出力先変数(条件)? 条件が一致した場合の値 : 一致しない場合の値;

if文に置き換えると
if(state==0) outdata=1;
else outdata=0;
となります。

また、3項演算子はelse ifの要領で連結することができます。
 出力先変数(条件1)? 条件1が一致した場合の値 :
       (条件2)? 条件1が一致せず、条件2が一致した場合の値 :
       (条件3)? 条件1,2が一致せず、条件3が一致した場合の値 :
       (条件4)? 条件1~3が一致せず、条件4が一致した場合の値 :
       どの条件にも一致しない場合の値;



出力関数の作成

/*============= PortE 4-7出力関数 =============*/
void set_PortE_bit(int bit,int on){
    int outdata=0;

    if( bit<4 || bit>7 )    //関係ない端子を指定した場合
        return;                //ここでこの関数を強制終了

    outdata=0x0001<<bit;

    if(on==0){    //OFFする場合
        PE.DRL.WORD &=~outdata;    //OFF 指定したビットのみ0にする
    }else{
        PE.DRL.WORD |= outdata;    //ON 指定したビットのみ1にする
    }
}

<解説1>

state=0x0001<<bit;までは入力の場合と一緒です。
同じくビット演算も合わせてご参照ください。

まずは簡単なelseの方の中身から。
問題となるのはこの部分
PE.DRL.WORD |= outdata;

これをもう少し分かりやすく書くと
PE.DRL.WORD = PE.DRL.WORD | outdata;

PE.DRL.WORDとoutdataのOR演算を行い、この結果をPE.DRL.WORDに代入します。

  0b0110111000100110
| 0b0001000000000000
   ↓
  0b0111111000100110

  0b1001010100111001
| 0b0001000000000000
   ↓
  0b1001010100111001

特定のビット1で上書きすることができます。

<解説2>

ちょっと難しい方

PE.DRL.WORD &=~outdata;
これをもう少し分かりやすく書くと
PE.DRL.WORD = PE.DRL.WORD &~outdata;

この部分
~outdata;

~はビット反転の演算子で、ビットに対して0→1、1→0の処理となります。
~ 0b0001000000000000
   ↓
   0b1110111111111111
この様に特定のビットのみを簡単に0にすることができます。

このビット反転したビットシフト値とビットAND演算を行っています。
   0b0110111000100110
& 0b1110111111111111
   ↓
   0b0110111000100110

   0b1001010100111001 &
& 0b1110111111111111
   ↓
   0b1000010100111001

この手順により特定のビット0で上書きすることができます。

<解説3>

ORNOT+ANDを用いなくてもビットシフトした値の加算減算するだけで
なんとかなりそうな気がします。演算してみます。

1にする(加算)
   0b0110111000100110
+ 0b0001000000000000
   ↓
   0b0111111000100110
成功

   0b1001010100111001
+ 0b0001000000000000
   ↓
   0b1010010100111001
失敗

ビットを足す先に1があったため、1つ上のビットが変化してしまいました。
更に本来1としたい部分が0になってしまいました。


0にする(減算)
  0b0110111000100110
- 0b0001000000000000
   ↓
  0b0101111000100110
失敗

  0b1001010100111001
- 0b0001000000000000
   ↓
  0b1000010100111001
成功

今度はビットを引く先が0だったため、1つ上のビットが変化してしまいました。
更に本来0としたい部分が1になってしまいました。

この様に加算減算のみではビットを変化させたい部分の状態によって関係ない箇所を変化させてしまいます。
ビットを変化させたい箇所の状態に応じて処理方法を変えることで対応は可能ですが、行数(無駄な処理)が増えてしまいます。

特定のビットのみ変化させたい場合はORNOT+ANDの組み合わせを用いるのがスマートです。

今回の内容を記載したファイルを置いておきます。
sw4.c 4ポート操作
PR

コメント

プロフィール

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

最新コメント