2001/02/21 【ソフトウエア編TOPに戻る】
PIO(ピーアイオー)とは、ビットごとに入出力の操作ができるパラレルポートのことです。AKI-H8/3048Fボードでは、以下のパラレルポートがあります。
| PORT | 機 能 | DDR | DR | PCR |
| PORT1 | 8bit LED駆動 | FFFC0 | FFFC2 | --- |
| PORT2 | 8bit LED駆動 入力プルアップ | FFFC1 | FFFC3 | FFFD8 |
| PORT3 | 8bit | FFFC4 | FFFC6 | --- |
| PORT4 | 8bit 入力プルアップ | FFFC5 | FFFC7 | FFFDA |
| PORT5 | 4bit LED駆動 入力プルアップ | FFFC8 | FFFCA | FFFDB |
| PORT6 | 7bit | FFFC9 | FFFCB | --- |
| PORT7 | 8bit | FFFCE | --- | --- |
| PORT8 | 5bit 2〜0シュミット入力 | FFFCD | FFFCF | --- |
| PORT9 | 6bit | FFFD0 | FFFD2 | --- |
| PORTA | 8bit 7〜0シュミット入力 | FFFD1 | FFFD3 | --- |
| PORTB | 8bit LED駆動 3〜0シュミット入力 | FFFD4 | FFFD6 | --- |
表のDDR,DR,PCRは、各ポートの動作を設定するためのレジスタや、データの受け渡しを行なうレジスタのことで、表中のFで始まる文字は、各レジスタのアドレスを表します。
■DDR データディレクションレジスタ
DDRとはPORTをBITごとに入力か出力かに設定するレジスタのことです。出力に設定したいBITを1、入力に設定したいBITを0にします。例えばPORT1の0〜3BITを出力、4〜7BITを入力に設定したければ、FFFC0のアドレスに以下のデータを書き込みます。
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| data | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
16進数にすると、0Fhを書き込むということになります。
■DR データレジスタ
DRとはPORTとのデータのやり取りを行なうレジスタのことです。出力ポートに設定してあれば、DRからBITデータを読み出し、入力ポートに設定してあれば、DRに対してBITデータを書き込みます。例えば、PORT1に入力されているデータを読み出したければ、FFFC2のアドレスのデータを読み出します。
■PCR プルアップMOSコントロールレジスタ
PCRとはPORT2,4,5だけにある機能で、PORTを入力に設定したときに、プルアップ抵抗を付けるか、付けないかを設定するためのレジスタです。プルアップしたいBITを1、したくないBITを0に設定します。例えばPORT2の0〜3BITをプルアップ有り、4〜7BITを無しにしたければ、FFFD8のアドレスに以下のデータを書き込みます。
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| data | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
16進数にすると、0Fhを書き込むということになります。
101−2.PIO出力のプログラム例 その1
このプログラムは、3.C言語コンパイル手順のページで紹介したものです。ここをクリックするとダウンロードできます。(ledtest1.c)
これを動作させるためのハードウエアは、電子回路編 3.AKI-H8開発キットの回路 [11]PORT5 LEDランプ LED1,LED2を参照して下さい。
| /* C TEST PROGRAM BY RIKIYA 2001.02.18 */ /* for AKI-H8/3048F CPU BOARD */ /* PROGRAM NAME LEDTEST1.C */ /***************************************/ /*メインプログラム************************/ main(){ char *p5ddr = (char *)0xFFFC8; /* port5 ddr */ char *p5dr = (char *)0xFFFCA; /* port5 dr */ char *p5pcr = (char *)0xFFFDB; /* port5 pcr */ *p5ddr = 0xff; /* port5を全て出力に設定 */ *p5pcr = 0x00; /* port5のプルアップ抵抗なし */ while(1){ *p5dr = 0x01; wait(); *p5dr = 0x02; wait(); } } /*時間稼ぎ関数*************************/ wait(){ int i; for (i=0;i<0xffff;i++){ /*なにもしない*/ } return; } |
/* と*/に挟まれた部分はコメントとして扱われ、プログラムの動作には無関係となります。プログラムソースの説明文などを好きなように書き込みます。
このプログラムはmain( ){ }で囲まれた部分のメイン関数と、wait( ){ }で囲まれた部分の時間稼ぎ関数から構成されています。
■メイン関数では、最初にポート5のDDR,DR,PCRの各レジスタとデータのやり取りを行なうための変数*p5ddr,*p5dr,*p5pcrを宣言しています。各ポートのレジスタはそれぞれアドレスが決まっているため、変数宣言の際にアドレスも指定しています。
char *p5ddr = (char *)0xFFFC8; /* port5 ddr */
char *p5dr = (char *)0xFFFCA; /* port5 dr */
char *p5pcr = (char *)0xFFFDB; /* port5 pcr */
charで1byte(8bit)のデータであることの宣言を行い、各変数の頭に*を付けることによりポインタ型の変数にしてアドレスが扱えるようにし、その後の=で直接 変数のアドレスを指定しています。なので、*p5ddrはアドレス0xFFFC8、*p5drはアドレス0xFFFCA、*p5pcrはアドレス0xFFFCBとなります。
次に、DDRとPCRの設定を行なっています。
*p5ddr = 0xff; /* port5を全て出力に設定 */
*p5pcr = 0x00; /* port5のプルアップ抵抗なし */
コメント文にある通り、*p5ddrには0xff (1111 1111)を書き込んでいるため、全てのbitを出力に設定しています。また、*p5pcrには0x00 (0000 0000)を書き込んでいるため、全てのbitをプルアップ抵抗なしに設定しています。ポート5の場合は下位4bit(右側)だけしか扱えないため、上位4bit(左側)の指定は必要ありませんが、他のポートと合わせておく意味で8bit分の指定としておきます。
次のwhile(1){ }は、{ }で挟まれた部分の処理を無限に繰り返します。
*p5dr = 0x01;
先ず、ポート5のDRに0x01 (0000 0001)を書き込みます。すると1bit目の出力が1となり、DC5Vの電圧が出力されます。これによって、LED1が点灯します。
wait();
次に、時間稼ぎ関数が終了するまでの間、なにもしないでボーっとしています。この間、LED1は点灯したままです。
*p5dr = 0x02;
先ず、ポート5のDRに0x02 (0000 0010)を書き込みます。すると2bit目の出力が1となり、DC5Vの電圧が出力されます。これによって、LED2が点灯します。このとき、1bit目は0なので電圧が出力されなくなり、LED1は消灯します。
wait();
再び、時間稼ぎ関数が終了するまでの間、なにもしないでボーっとしています。この間、LED2は点灯したままです。
と、以上の処理を永久に繰り返すので、LED1とLED2が交互に点滅を繰り返す動作となります。メイン関数は以上で終了です。
■時間稼ぎ関数では、ただ単純に0x0000から0xffff(0〜65535)まで数を数えて時間をつぶしています。
先ずはじめに、数えた数を覚えておくための変数 i をint型で宣言しています。int型では2byte(16bit)の整数が扱えます。つまり、65535まで数えられます。
int i;
そして、次のfor文で、i を 0 から 1ずつ (i++) 増やしていき、0xffffより小さい間、数え続けます。
for (i=0;i<0xffff;i++){
/*なにもしない*/
}
0xffffまで数え終わったらfor文を抜け、return; でメイン関数の呼ばれた元の場所に戻り、メイン関数内の次の処理を実行します。
■実際に動作させて見た方はお分かりかと思いますが、LED1とLED2の点滅は、結構早い周期で行なわれます。パカパカといった感じです。これをもっとゆっくりにさせたい場合は、時間稼ぎ関数の0xffffの値をもっと大きくします。ただし、int i;で宣言した変数 i は、最大で0xffffまでしか数えられないため、単純に0xfffff (f が5個)などとしても、ちゃんと動いてくれません。
この場合は、long i; と宣言します。long型は32bitのデータを扱うことが出来るため、0xffffffff (4,294,967,295)まで数えることができるようになります。
long型にして試してみる場合は、0xfffff(f が5個)くらいまでにしておかないと、その効果を確認するまでに眠くなる恐れがありますので、注意して下さい。
101−3.PIO出力のプログラム例 その2
次にご紹介するプログラムも、さっきご紹介したプログラム例その1と全く同じものです。でも、見比べてみるとちょっと書き方が違います。ここをクリックするとダウンロードできます。(ledtest2.c) なにが違うのでしょうか?
| /* C TEST PROGRAM BY RIKIYA 2001.02.25 */ /* for AKI-H8/3048F CPU BOARD */ /* PROGRAM NAME LEDTEST2.C */ /***************************************/ #include <3048f.h> /* 3048f.h ヘッダーファイルの読み込み */ /*メインプログラム**********************/ main(){ P5.DDR = 0xff; /* port5を全て出力に設定 */ P5.PCR.BYTE = 0x00; /* port5のプルアップ抵抗なし */ while(1){ P5.DR.BYTE = 0x01; wait(); P5.DR.BYTE = 0x02; wait(); } } /*時間稼ぎ関数*************************/ wait(){ int i; for (i=0;i<0xffff;i++){ /*なにもしない*/ } return; } |
メインプログラム中で、P5.DDRとP5.PCR.BYTEというものがいきなり出てきて、早速設定値を書き込んでいます。
P5.DDR = 0xff; /* port5を全て出力に設定
*/
P5.PCR.BYTE = 0x00; /* port5のプルアップ抵抗なし */
また、P5.DR.BYTEというのも出てきて、早速LEDを点灯させるための作業を行なっています。
while(1){
P5.DR.BYTE = 0x01;
wait();
P5.DR.BYTE = 0x02;
wait();
}
これらの変数の宣言はしなくてもいいのでしょうか?一体どこから出てきたのでしょう。ということで、プログラムの一番初めの #include <3048f.h> に注目して下さい。
これは、コンパイルするときに3048f.hというファイルを読み込んで下さいという意味です。実は、この3048f.hは、他のプログラムでも共通して使える変数の宣言や関数などを集めたヘッダーファイルと呼ばれるものの中のひとつで、特にH8-3048F CPUのインターフェイスに関係する変数の宣言を集めたものです。
P5.DDRやP5.PCR,、それにP5.DR.BYTEというのは、この3048f.hで宣言されていて、アドレスの割り当ても済んでいるため、プログラムがスマートに記述できるのです。3048f.hファイルはコンパイラと同じファオルダにあります。一度メモ帳などでのぞいてみてください。
ちなみに、上のwhile(1){ }の中身は、以下のように直接bit単位で操作する記述も可能です。
while(1){
P5.DR.BIT.B0 = 1;
P5.DR.BIT.B1 = 0;
wait();
P5.DR.BIT.B0 = 0;
P5.DR.BIT.B1 = 1;
wait();
}
この辺の細かい取り扱い説明書はありませんので、必要に応じて3048f.hの中身を見て、どういう使い方ができるのかを、自分で判断することになります。
TekuRobo工作室では、これから3048f.hを使って簡単にプログラムを作っていこうかと思います。