IOポートに関する補足
Copyright(C)12Nov2005
coskx
1.IOポートへの出力
IOポート(入出力ポート)は,メモリと同じアドレス空間にある。(メモリマップトIO)IOポートはメモリの一部のように見え,8ビットデータを書き込んだり読み出したりすることができる。
ある出力ポートに8ビットデータを書き込むと,そのポートにつながる端子から1と0のビットパターンが電圧のVccまたはGNDレベルとして出力される。
ある入力ポートから8ビットデータを読み出すと,そのポートにつながる端子に与えられた電圧のVccまたはGNDレベルを1と0として読み出すことができる。
2.出力ポート5のアドレスとCPUの外側
H8/3052のマザーボードでは,ポート5の第0ビットと第1ビットがそれぞれ2つのLEDにつながれているため,ポート5の第0ビットと第1ビットに1と0のビットパターンを出力することにより,LEDの点灯消灯を実現できる。(図1,2,3参照)
![]() |
| 図1 マザーボード,CPUカード,CPUの接続 ポート5の第0ビットと第1ビットはCPUの53番ピン,54番ピンから外部に出ており,CPUカードのコネクタ3(CN3)の31,32ピンに接続されています。 マザーボード上ではCN3の31,32ピンから1.5kΩの抵抗を介してLEDにつながっています。 |
![]() |
![]() |
| 図2 CPUカード 実際のCPUカードのCN3の31,32ピン 右の図とは上下が逆なので注意 |
図3 マザーボード マザーボード上でCN3の31,32ピンから引き出されているLED |
3.ポート5の実体
AKI-H8/3052は,H8/300Hアドバンスモードのモード7で動作しているこの時のアドレスとメモリの関係は表1のようになっている。
特に,ポート5に関しては表2のようになっている。 メモリ空間は1Mバイトになる。
実際のプログラムでは,16Mバイトメモリ空間モードに対応できるような記述となるため,アドレスは16進6桁で記述している。
1Mバイトメモリ空間の場合,アドレスの上位4ビットは捨てられてコンパイルされるため,実用上は差し支えない。
表1 メモリマップ
| メモリの種類 | アドレス | 備考 |
| ROM | 0x00000-0x07FFFF (512kbyte) | 実際にはフラッシュメモリ,書き込みモードでのみ書き込むことが出来る。 電源が切れても,内容は保たれる。 割り込みベクタテーブル,プログラム,定数,変数の初期値の格納場所 |
| RAM | 0xFEF10-0xFFF0F ( 4kbyte) | 電源が切れると内容は消滅する。 変数,スタック(オート変数,戻りアドレス,レジスタ退避)の格納場所 |
| I/Oレジスタ | 0xFFF1C-0xFFFFF (228byte) | I/Oレジスタ |
表2 IOレジスタポート5
| ポート5レジスタの役割 | アドレス |
| DDR データディレクションレジスタ(8ビット幅) DR(8ビット)の各ビットを入力用に使うか出力用に使うかを定義する ビットごとに0なら入力,1なら出力の設定となる。 |
0xFFFC8 |
| DR データレジスタ(8ビット幅) IOレジスタ |
0xFFFCA |
よくある質問
Q:どうしてポート5の第0ビットと第1ビットにLEDがつながれているのですか。
A:マザーボードの設計者がLEDをつなぐ位置をポート5の第0ビットと第1ビットに決めています。
Q:他のポートの適当なビットにLEDをつなぐことができますか
A:出力に使えるポートのビットであり,他の用途に使われていないのならLEDをつなぐことができます。
ただし,ソフトウェアを対応させないとLEDを点灯することができません。
|
勘どころ |
|
ポート5レジスタのアドレスが0xFFFC8であることはCPUの設計者が決めたことなので,使用者は変更することができない。 |
4.ポート5の実体を意識したLED点灯消灯のプログラム
ポート5の下位2ビットからデータを出力するためには,次の手順となる
(1)ポート5は入出力兼用であるため,下位2ビットを出力に使うように設定する
(2)ポート5の下位2ビットに任意のデータを出力する。
(2進法で00,01,10,11の4通りしかない)
具体的な手順は図4を参考に,次の通りとなる。
(1)ポート5データディレクションレジスタ(8ビット幅)
メモリマップドIOレジスタ アドレス FFFFC8
ビットごとに0なら入力,1なら出力の設定となる。
ここでは下位2ビットを出力とし,他を入力の設定にするため3を書き込む
(2)ポート5データレジスタ(8ビット幅)
メモリマップドIOレジスタ アドレス FFFFCA
下位2ビットにデータを書き込む
![]() |
|
図4 CPUがポート5を通してLEDをON−OFFさせる様子 |
4.1 ポインタと#defineを用いて,あるアドレス(ポートP5)に直接データを書き込むプログラム
| リスト1 |
#define P5DDR *(unsigned char*)0xffffc8
#define P5DR *(unsigned char*)0xffffca
void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
int i,j;
for (i=0;i<msec;i++) {
for (j=0;j<1588;j++); /*1588は実測によって求めた値*/
}
}
main()
{
/*P5の下位2ビットを出力に設定*/
/* P5のDDRの下位2ビットに1を与えるとこの設定になる*/
/*DDRとはDataDirectionRegister(データ方向設定レジスタ)*/
P5DDR = 0x3; /*0x3 = 00000011(二進数)*/
while(1) {/*これは無限ループ*/
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
/*DRとはDataRegister(データレジスタ)*/
P5DR=1;
msecwait(1000);/*1000msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
/*LED0をOFFにする P5のDRの第0ビットを0にする*/
P5DR=2;
msecwait(1000);
}
} |
4.2 ポインタとstructを用いた表現によるプログラム
| リスト2 |
struct port5 {
unsigned char DDR;
char dummy; /*ここは使われない*/
unsigned char DR;
};
#define P5 (*(struct port5*)0xffffc8)
void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
int i,j;
for (i=0;i<msec;i++) {
for (j=0;j<1588;j++); /*1588は実測によって求めた値*/
}
}
main()
{
/* P5のDDRの下位2ビットに1を与える*/
P5.DDR = 0x3; /*0x3 = 00000011(二進数)*/
while(1) {/*これは無限ループ*/
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
P5.DR=1;
msecwait(1000);/*1000msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
P5.DR=2;
msecwait(1000);
}
} |
4.3 ビットフィールドと共用体を用いた表現によるプログラム
P5.DRをバイト単位で扱ったり,ビット単位で扱えるように工夫している
| リスト3 |
struct port5 {
unsigned char DDR;
char dummy; /*ここは使われない*/
union {
unsigned char BYTE;
struct {
unsigned char dummy6 :6; /*6ビット ここは使われない*/
unsigned char B1 :1; /*1ビット*/
unsigned char B0 :1; /*1ビット*/
} BIT;
} DR;
};
#define P5 (*(struct port5*)0xffffc8)
void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
int i,j;
for (i=0;i<msec;i++) {
for (j=0;j<1588;j++); /*1588は実測によって求めた値*/
}
}
main()
{
/*P5の下位2ビットを出力に設定*/
P5.DDR = 0x3; /*0x3 = 00000011(二進数)*/
while(1) {/*これは無限ループ*/
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
P5.DR.BYTE=1;
msecwait(1000);/*1000msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
P5.DR.BYTE=2;
msecwait(1000);
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
P5.DR.BIT.B0=1;
P5.DR.BIT.B1=0;
msecwait(250);/*250msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
P5.DR.BIT.B0=0;
P5.DR.BIT.B1=1;
msecwait(250);
}
} |
4.4 ヘッダ記載のstruct表現によるプログラム
| リスト4 |
#include <3052f.h>
void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
int i,j;
for (i=0;i<msec;i++) {
for (j=0;j<1588;j++); /*1588は実測によって求めた値*/
}
}
main()
{
/*P5の下位2ビットを出力に設定*/
P5.DDR = 0x3; /*0x3 = 00000011(二進数)*/
while(1) {/*これは無限ループ*/
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
P5.DR.BYTE=1;
msecwait(1000);/*1000msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
P5.DR.BYTE=2;
msecwait(1000);
/*LED0をONに,LED1をOFFにする
P5のDRの第0ビットを1に,第1ビットを0にする*/
P5.DR.BIT.B0=1;
P5.DR.BIT.B1=0;
msecwait(250);/*250msecの間なにもしない*/
/*LED0をOFFに,LED1をONにする
P5のDRの第0ビットを0に,第1ビットを1にする*/
P5.DR.BIT.B0=0;
P5.DR.BIT.B1=1;
msecwait(250);
}
} |