home1.gif

next1.gif
back1.gif
 

Input / Output Port

 

基礎編
 PORT入出力
 シリアル通信
 タイマー機能
 A/Dコンバータ
 D/Aコンバータ
 外部割り込み
 液晶モニタ

応用編
 アウトプットコンペア
 インプットキャプチャ
 SRAM増設

Tips
 関数集
 シリアルEEPROM
 20桁×4行液晶モニタ
  (SC2004C)
 加速度センサを読む

 

PORT入出力

 イントロダクション
 そもそもポートとは何か? たった今マイコンの袋を破ったばかりの人にはそこから分からないと思います。ポートとは、「電気信号を出したり受け取ったりする端子」と言って良いでしょう。たとえばLEDを灯す為に電気を出したり、スイッチの入力を読むために電気を受け取ったりするわけです。

 ポートの種類
 H8/3048Fには入出力のどちらにも使用できるポートが10種類と、入力専用ポートが1種類有ります。それぞれは4〜8本のポートを持ち、合計で78本の入出力ポートがあります。
 これらの中にはあらかじめプルアップ抵抗を内蔵している物もあり、極端な言い方をすればスイッチとLSIを抵抗を介さずにつなげてもOKという物もあります(大声でお勧めする接続方法ではありませんが、現実的には大丈夫です)。また、10mAくらいの電流を流せるポートもあり、トランジスタ無しでもLEDくらいならば駆動できるポートもあります。詳しくは日立のハードウェアマニュアル9章「I/Oポート」の最初に書いてあります。

 さて、ここで注意しておかなければ行けないのは、どこのポートに何を繋いでも良いというわけではないと言うことです。AKI-H8の説明書付属のコネクタ一覧表の裏面の回路図を見てみましょう。たとえば、ポート9を見たとき、「TXD/P9-0」のように書かれていると思います。つまり、Port9-0はRS-232Cの送信端子としても割り当てられているということです。これは秋月電子の回路設計の都合によるのではなく、日立の設計による物です。ですから、Port9-0を他の用途に使った場合、RS-232C通信の送信はできなくなるということです。
 そうやって見たとき、ほとんど全部のポートが何らかの別機能を備えていることが分かると思います。

 では具体的にはどこのポートならば他の機能とぶつからずに使えるのでしょう? 即答の難しい問題なのですが、SRAMを増設しない場合、もう少し専門的に言うと「モード7(シングルチップモード)」で使用する場合には(ほとんどの場合はこのモードを使います)次のような使い方をすると思います。

Port-1

入力/出力

Port-2

LED出力/スイッチ入力

Port-3

出力(液晶モニタなど)

Port-4

スイッチ入力

Port-5

LED出力/スイッチ入力

Port-6

入力/出力

Port-7

D/Aコンバータ A/Dコンバータ

Port-8

外部割り込み入力

Port-9

シリアル通信

Port-A

入力/出力

Port-B

LED出力/入力

 ここで「LED出力」「スイッチ入力」と書いた物はべつにその用途にしか使ってはいけないというのではなく、大電流駆動やプルアップ抵抗があるので、こういう用途に特に使いやすいという意味です。

  出力ポートとして使ってみる
 いつまでもあーたらこーたら言っていても分からないと思うので、具体的な使い方を紹介します。

 まずは基本中の基本と言うことで、単純にLEDを灯すという事からやっていきます。LED8個と500オームくらいの抵抗8本を用意してください。ちなみになぜ500オームなのか? 普通のLEDは10mAもあれば灯ります。そしてH8のポート電圧は5V。中学生の算数ですね。

   E=RI  つまり、 5=R×0x020 

 よって R=500(オーム)です。これ以下の抵抗値だとLEDが焦げるかポートが痛むかのどちらかなので、見つからなければこれよりも大きな値の抵抗を探してください。

 使うポートは上の表に従ってPort-Bを使いましょう。回路は右の図のようになります。

 次に、このファイルをダウンロードしてください。解凍すると中にtest01.cというファイルが含まれています。これがメインプログラムです。他のファイルはコンパイルする上で必須のファイルばかりですが、全部HEW(日立の統合開発環境)が勝手に作ってくれるので、今回はどこも触る場所は有りません。

 重要なのは main() 文の中身で、このようになっているはずです。

 

 void main(void)
 {

     PB.DDR = 0xff;               // Port-B is Output
     PB.DR.BYTE = 0x00;           // ●●●●●●●●
	

     PB.DR.BIT.B0 = 0;            // ●○●○●○●○
     PB.DR.BIT.B1 = 1;
     PB.DR.BIT.B2 = 0;
     PB.DR.BIT.B3 = 1;
     PB.DR.BIT.B4 = 0;
     PB.DR.BIT.B5 = 1;
     PB.DR.BIT.B6 = 0;
     PB.DR.BIT.B7 = 1;

     while(1);
	
 }

また、上の方に
  #include "iodefine.h"
と書いてある部分もポートを使う上で必須なので注意してください。(今後紹介するプログラムでは必ず登場しますので、忘れずに書くようにしてください。これを抜かすとH8の機能を何も使えません。)

 さて、何をやっているかですが、まず

  PB.DDR = 0xff;

ですが、これはPort-Bをどのように使うかを指定します。Port-Bは全部で8本の端子がありますが、これらは全部独立に入出力ポートとして設定できますが、それは言い換えると1個1個個別に指定してやる必要があるということですので、このような書式になっています。最上位ビットがPortB-7で、最下位がPortB-0に相当します。「0」が入力設定で、「1」が出力設定です。今回は全部出力設定なので、

  1111 1111(2進数) => 0xff (16進数)

となります。コンパイラは

  PB.DDR = 11111111;

と書いても通らないので、必ず16進数で書いてください。(C言語ではほとんど常識ですね)

余談ですが、上位4ビットを入力に、下位4ビットを出力として使う場合は
  PB.DDR = 0x0f;
というように書きます。

 

 次に、

  PB.DR.BYTE = 0x00;

とあります。これは、Port-Bの最初の状態を指定しています。「0」で出力無し(0V)、「1」で出力有り(5V)ですから、0x00だとLEDは全部消えた状態になります。この「.BYTE」という表記は8本のポートを全部一括で扱う場合で、1本ずつ個別に扱いたいときにはその下から8行つづいている

  PB.DR.BIT.B0 = 0;

のように、「.BIT.Bn」という表現を使います。ここで「n」には扱いたいポートのビット番号を入れます。
もう勘のいい人は分かったと思いますが、

  PB.DR.BYTE = 0xaa;

と書くのと、

  PB.DR.BIT.B0 = 0;
  PB.DR.BIT.B1 = 1;
  PB.DR.BIT.B2 = 0;
  PB.DR.BIT.B3 = 1;
  PB.DR.BIT.B4 = 0;
  PB.DR.BIT.B5 = 1;
  PB.DR.BIT.B6 = 0;
  PB.DR.BIT.B7 = 1;

と書くのは同じ意味を持ちます。

なぜ同じ事ができるのに2通りの表現があるかですが、少し考えれば分かることで、たとえば他のポートはそのままの状態で、ひとつだけ状態を変えたいときなどは論理演算子を使うよりもビット単位で書いた方が間違いが少ないし、何よりも高速です。また、高速性が求められる時に1個1個順番に状態を変えていくよりも8本一括で変更できた方が便利であることも確かですから、ケースバイケースで2通り使い分けれた方が便利なのです。

  入力ポートとして使ってみる
 
今度は逆に入力ポートとして使ってみましょう。さきほどのPort-Bは入力プルアップMOSが使えないので、入力としてそのまま使うと壊してしまうおそれがあります。そのためにわざわざ抵抗を用意するのも面倒なので、Port-2を使いましょう。

 回路はさきほどの物を流用し、Port-2にスイッチを8個増やしてください。次に、このファイルをダウンロードしてください。展開すると先ほどと同じようなファイル構成の物が出てくると思いますが、この中で重要なのは、
test02.c だけです。他のファイルはやはりHEWが作ってくれます。

 void main(void)
 {

     P2.DDR = 0x00;
     P2.PCR.BYTE = 0xff;
    
     while(1){
         PB.DR.BYTE = P2.DR.BYTE;
     }

	
 }
	    

このプログラムはポート2のスイッチがONの時にポートBの対応するビットのLEDが灯ります。

では最初から見ていきましょう。まず、

  P2.DDR = 0x00;

これはもう分かりますね。Port-2は8ポートとも入力に使うという意味です。

  P2.PCR.BYTE = 0xff;

これは入力プルアップをどうするのかという設定です。「0」がOFFで「1」がONです。ここでは全ポートONにしています。

  while(1){

    PB.DR.BYTE = P2.DR.BYTE;

  }

このプログラムはスイッチの状態を見るわけで、起動して一巡してそれで終わりでは困ります。常にプログラムは入力ポートの状態を監視したいわけですから、このようにwhile文(またはdo〜while文)で無限ループを作ってやります。そして、その中にある文は

  int i;

  i = P2.DR.BIT.B0;

  if( i == 1 )
     PB.DR.BIT.B0 = 1;
  else
     PB.DR.BIT.B0 = 0;

  i = P2.DR.BIT.B1;

  if( i == 1 )
     PB.DR.BIT.B1 = 1;
  else
     PB.DR.BIT.B1 = 0;
      ・
      ・
      ・

という内容を簡潔にまとめた物であることは分かるかと思います。 

 

  まとめ
 これで入出力ポートを扱う基礎はわかりましたね? ポイントを整理すると、

  • 入力に適したポート、出力に適したポートを使い分ける(→無駄なパーツが省ける)
  • 入出力設定は Pn.DDR = 0xnn で設定
  • 入力でプルアップが必要なときは Pn.PCR = 0xnn の必要なビットを立てる
  • 出力設定で、信号を出すときは「1」、出さないときは「0」を Pn.DR.BIT.Bn に書く
  • 入力設定で、ポートの状態(Hi or Lo)は Pn.DR.BIT.Bn に「1」か「0」で入っている

 これは本当に基礎中の基礎です。このページを100%理解できなければ次からの説明は全くと言っていいほど理解できません。また、これからマイコンを使う上で、ずっとつきまとってくる内容です。たとえば入力プルアップの無いポートに直接何かの入力を入れてポートが壊れるなんてことは初歩的ながらも見落としかねないトラブルです。だからこそしっかりと理解して自分の物にしてください。

  
home1.gif
 next1.gif back1.gif
 

 

 


funfly@kisweb.ne.jp