内容
R8C/M12Aには、外部からの信号が"0"から"1"になった瞬間(立ち上がりエッジといいます)、または"1"から"0"になった瞬間(立ち下がりエッジといいます)、またはその両方(両エッジといいます)になったときに割り込みを発生させることができます。これをINT割り込みといいます。R8C/M12Aには、INT0〜INT3の4つあるので最大で同時に4つの外部入力割り込みを発生させることができます。今回は、LEDを一定パターンで点灯させている状態で、INT3割り込みが発生したときにLEDを点滅させるようにします。
ワークスペース
r8cm12a_int3_100.zip
ファイルを解凍し、フォルダを「c:\worksapce」に入れてください。
回路
ブレッドボードの回路を下図に示します(「スイッチの入力(I/Oポートの入力)」と同じ回路です)。
ブレッドボード実装図
ブレッドボードの実装を下図に示します(「スイッチの入力(I/Oポートの入力)」と同じ実装です)。
P3_3に繋がっているディップスイッチを"1"(上図の左側)から"0"(右側)にするとLEDが点滅します。
プログラムの説明
INT3の設定
INT0〜INT3の概要を、下図に示します。
今回は、INT3割り込みを使用します。入力エッジは立ち下がりエッジにします。
これからINT3割り込みについて、説明します。
■INT0入力端子の選択
INT0入力端子を選択します。今回は使いませんが、使う場合は下記のように設定してください。
// P1_4端子を使う場合
p14sel2 = 0; /* P1_4をINT0端子にする */
p14sel1 = 1;
p14sel0 = 1;
// P4_5端子を使う場合
p45sel1 = 0; /* P4_5をINT0端子にする */
p45sel0 = 1;
■INT1入力端子の選択
INT1入力端子を選択します。今回は使いませんが、使う場合は下記のように設定してください。
// P1_5端子を使う場合
p15sel2 = 0; /* P1_5をINT1端子にする */
p15sel1 = 1;
p15sel0 = 1;
// P1_7端子を使う場合
p17sel1 = 0; /* P1_7をINT1端子にする */
p17sel0 = 1;
// P4_6端子を使う場合
p46sel2 = 0; /* P4_6をINT1端子にする */
p46sel1 = 1;
p46sel0 = 1;
■INT2入力端子の選択
INT2入力端子を選択します。今回は使いませんが、使う場合は下記のように設定してください。
// P3_4端子を使う場合
p34sel1 = 1; /* P3_4をINT2端子にする */
p34sel0 = 0;
// P4_7端子を使う場合
p47sel1 = 0; /* P4_7をINT2端子にする */
p47sel0 = 1;
■INT3入力端子の選択
INT3入力端子を選択します。INT3は、P3_3しか選択できないので、必ず今回の設定になります。
p33sel1 = 1; /* P3_3をINT3端子にする */
p33sel0 = 0;
■外部入力許可レジスタ(INTEN)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
|
|
INT3入力 許可ビット 0:禁止 1:許可 |
INT2入力 許可ビット 0:禁止 1:許可 |
INT1入力 許可ビット 0:禁止 1:許可 |
INT0入力 許可ビット 0:禁止 1:許可 |
設定値 |
|
|
|
|
1 |
|
|
|
ビットの 名称 |
|
|
|
|
INT3EN |
INT2EN |
INT1EN |
INT0EN |
|
INT3入力を許可します。この設定でINT3入力端子(今回はP3_3端子)がINT3入力になります。INT3を使う場合は、必ずこのビットを許可にしてください。
プログラムを下記に示します。
int3en = 1; /* INT3入力許可ビット:許可 */
■INT入力フィルタ選択レジスタ0(INTF0)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
INT3入力フィルタ 選択ビット 00:フィルタなし 01:フィルタあり、 f1でサンプリング 10:フィルタあり、 f8でサンプリング 11:フィルタあり、 f32でサンプリング |
INT2入力フィルタ 選択ビット 00:フィルタなし 01:フィルタあり、 f1でサンプリング 10:フィルタあり、 f8でサンプリング 11:フィルタあり、 f32でサンプリング |
INT1入力フィルタ 選択ビット 00:フィルタなし 01:フィルタあり、 f1でサンプリング 10:フィルタあり、 f8でサンプリング 11:フィルタあり、 f32でサンプリング |
INT0入力フィルタ 選択ビット 00:フィルタなし 01:フィルタあり、 f1でサンプリング 10:フィルタあり、 f8でサンプリング 11:フィルタあり、 f32でサンプリング |
設定値 |
1 |
1 |
|
|
|
|
|
|
ビットの 名称 |
INT3F1 |
INT3F0 |
INT2F1 |
INT2F0 |
INT1F1 |
INT1F0 |
INT0F1 |
INT0F0 |
|
入力フィルタとは、入力端子の状態を一定時間ごとにチェックして、3回連続して同じ状態なら変化したと見なす機能です。チャタリングなどで、信号にノイズが含まれている場合などに有効です。期間は、f1(20MHz=50nsごとにチェック)、f8(2.5MHz=400nsごとにチェック)、f32(0.625MHz=1600nsごとにチェック)の3つから選ぶことができます。今回はスイッチなのでf32を選択します。3回連続で同じ状態ということなので、1600ns×3=4.8μs以上同じ状態なら変化したと見なします。
プログラムを下記に示します。
int3f1 = 1; /* INT3入力フィルタ選択ビット */
int3f0 = 1; /* 11=f32でサンプリング */
■ INT入力エッジ選択レジスタ0(ISCR0)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
INT3入力エッジ 選択ビット 00:立ち下がりエッジで割り込み要求を発生 01:立ち上がりエッジで割り込み要求を発生 11:立ち下がり、立ち上がりの両エッジで割り込み要求を発生 |
INT2入力エッジ 選択ビット 00:立ち下がりエッジで割り込み要求を発生 01:立ち上がりエッジで割り込み要求を発生 11:立ち下がり、立ち上がりの両エッジで割り込み要求を発生 |
INT1入力エッジ 選択ビット 00:立ち下がりエッジで割り込み要求を発生 01:立ち上がりエッジで割り込み要求を発生 11:立ち下がり、立ち上がりの両エッジで割り込み要求を発生 |
INT0入力エッジ 選択ビット 00:立ち下がりエッジで割り込み要求を発生 01:立ち上がりエッジで割り込み要求を発生 11:立ち下がり、立ち上がりの両エッジで割り込み要求を発生 |
設定値 |
0 |
0 |
|
|
|
|
|
|
ビットの 名称 |
INT3SB |
INT3AB |
INT2SB |
INT2AB |
INT1SB |
INT1AB |
INT0SB |
INT0AB |
|
「立ち下がりエッジで割り込み要求を発生」は、信号が"1"から"0"になった瞬間に割り込みを発生させます。「立ち上がりエッジで割り込み要求を発生」は、信号が"0"から"1"になった瞬間に割り込みを発生させます。「立ち下がり、立ち上がりの両エッジで割り込み要求を発生」は、両方で割り込みを発生させます。ただし、入力フィルタを設定している場合は、一定時間毎にチェックして3回連続で同じ状態のときに割り込みが発生します。今回は立ち下がりエッジで割り込みを発生させる設定にします。
プログラムを下記に示します。
int3sb = 0; /* INT3入力エッジ選択ビット */
int3sa = 0; /* 00=立ち下がりエッジで割込発生 */
■割り込み優先レベルレジスタA(ILVLA)
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
INT2の割り込み優先 レベル設定ビット 00:レベル0 (割り込み禁止) 01レベル1 10:レベル2 |
|
|
|
|
設定値 |
|
|
|
|
|
|
|
|
ビットの 名称 |
|
|
ILVLA5 |
ILVLA4 |
|
|
|
|
|
割り込み優先レベルは、複数の割り込みが同時に発生したとき、どの割り込みを優先させるか設定するものです。レベル2とレベル1を設定することができ、レベル2に設定した割り込みが優先されます。レベルが同じ時は、ハードウェアマニュアルの表に従って優先順位が決まります。詳しくは、R8C/M12Aのハードウェアマニュアルを参照してください。
割り込み優先レベルレジスタA(ILVLA)は、INT2の割り込み優先レベルを設定します。今回はINT2は使いませんので、このレジスタの設定はしません。
■割り込み優先レベルレジスタC(ILVLC)
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
INT1の割り込み優先 レベル設定ビット 00:レベル0 (割り込み禁止) 01レベル1 10:レベル2 |
|
|
|
|
設定値 |
|
|
|
|
|
|
|
|
ビットの 名称 |
|
|
ILVLC5 |
ILVLC4 |
|
|
|
|
|
割り込み優先レベルレジスタC(ILVLC)は、INT1の割り込み優先レベルを設定します。今回はINT1は使いませんので、このレジスタの設定はしません。
■割り込み優先レベルレジスタD(ILVLD)
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
|
|
|
|
INT3の割り込み優先 レベル設定ビット 00:レベル0 (割り込み禁止) 01レベル1 10:レベル2 |
設定値 |
|
|
|
|
|
|
1 |
0 |
ビットの 名称 |
|
|
|
|
|
|
ILVLD1 |
ILVLD0 |
|
割り込み優先レベルレジスタD(ILVLD)は、INT3の割り込み優先レベルを設定します。今回はINT3以外の割り込みを使いませんのでレベル1でもレベル2でもどちらでも構いませんが、一応レベルの高い、レベル2を設定しておきます。
プログラムを下記に示します。
ilvld1 = 1; /* 割り込み優先レベル設定ビット */
ilvld0 = 0; /* INT3はD1とD0に設定 10=レベル2*/
■割り込み優先レベルレジスタE(ILVLE)
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
INT0の割り込み優先 レベル設定ビット 00:レベル0 (割り込み禁止) 01レベル1 10:レベル2 |
|
|
|
|
設定値 |
|
|
|
|
|
|
|
|
ビットの 名称 |
|
|
ILVLE5 |
ILVLE4 |
|
|
|
|
|
割り込み優先レベルレジスタE(ILVLE)は、INT0の割り込み優先レベルを設定します。今回はINT0は使いませんので、このレジスタの設定はしません。
■全体の割り込みを許可する
外部入力許可レジスタ(INTEN)で、INT3入力による割り込みを許可しましたが、初期状態ではマイコン全体の割り込みが禁止になっています。
そのため、最後にマイコン全体の割り込みを許可します。全体割り込み許可は、マイコンのCPUレジスタという、C言語では操作できない場所にあるので、下記の様にアセンブラで命令を記述します。asm関数は、C言語プログラム内でアセンブラ命令を記述する命令です。
/* 全体割り込みの許可 */
asm(" fset I "); /* 全体の割り込み許可 */
今まで説明したINT3の設定は、init関数内で行います。最終プログラムを下記に示します。
/* INT3割り込み設定 */
p33sel1 = 1; /* P3_3をINT3端子にする */
p33sel0 = 0;
int3en = 1; /* INT3入力許可ビット:許可 */
int3f1 = 1; /* INT3入力フィルタ選択ビット */
int3f0 = 1; /* 11=f32でサンプリング */
int3sb = 0; /* INT3入力エッジ選択ビット */
int3sa = 0; /* 00=立ち下がりエッジで割込発生 */
ilvld1 = 1; /* 割り込み優先レベル設定ビット */
ilvld0 = 0; /* INT3はD1とD0に設定 10=レベル2*/
/* 全体割り込みの許可 */
asm(" fset I "); /* 全体の割り込み許可 */
割り込みプログラム
割り込みプログラムを下記に示します。今回はP3_3端子に立ち下がりエッジの信号("1"→"0"になった瞬間)が入力されたとき、このプログラムが実行されます。
#pragma interrupt intINT3(vect=26)
void intINT3( void )
{
flag_int3 = 1;
}
intINT3関数が、INT3入力割り込みが発生したときに実行される関数です。この関数がINT3入力割り込みの実行先ということを設定するのが、「#pragma interrupt」命令です。この命令の書式を下記に示します。
#pragma interrupt 割り込み関数名(vect=割り込み番号)
void 割り込み関数名( void )
{
割り込みプログラム
}
INT3の割り込み番号は26と決まっています。どの内蔵周辺機能が何番の割り込み番号かは、ルネサス エレクトロニクスの「R8C/M11Aグループ、R8C/M12Aグループ ユーザーズマニュアル ハードウェア編」の「可変ベクタテーブル」部分を参照してください。
INT0〜INT3の割り込み番号を下表に示します。
INT番号 |
割り込み番号 |
INT0 |
29 |
INT1 |
25 |
INT2 |
21 |
INT3 |
26 |
|
割り込み関数名は、自由に付けて構いません。今回はINT3割り込みなので、割り込みの「interrupt」とINT3の「INT3」を略して、「intINT3」としました。
今回のプログラムではflag_int3という変数に1を代入します。LEDの点滅動作は、main関数内で行っています。
main関数
main関数を下記に示します。
void main( void )
{
int i;
init(); /* 初期化 */
while( 1 ) {
p1 = 0b00001111;
timer( 1000 );
p1 = 0b11110000;
timer( 1000 );
p1 = 0b00000000;
timer( 1000 );
if( flag_int3 == 1 ) {
// INT3割り込みが発生したなら
flag_int3 = 0;
// 10回、LEDを交互に点滅させる
for( i=0; i<10; i++ ) {
p1 = 0b10101010;
timer( 200 );
p1 = 0b01010101;
timer( 200 );
}
}
}
}
if文でflag_int3変数が1かどうかチェックして、1なら、LEDを"1010 1010"と"0101 0101"を0.2秒ごとに10回点灯させ、INT3割り込みが発生したことをLEDで知らせます。
チャタリングについて
今回、スイッチはディップスイッチを使っています。INT3割り込みは立ち下がりエッジの設定なので、ディップスイッチを"1"→"0"にするとLEDが点滅します。しかし、たまに"0"→"1"(立ち上がりエッジ)にしたときもLEDが点滅することがあります。ディップスイッチが変化したときの電圧をオシロスコープで見たときの波形を下図に示します。
スイッチを"0"→"1"にしたつもりでも、短い時間の間で何度も"0"になったり"1"になったりします。これを「チャタリング」といいます。R8C/M12Aは20MHzで動作しているので、50ns(1/20MHz)より時間が長い信号は検出してしまいます。今回のINT3入力フィルタは、「f32でサンプリング」に設定していますが、それでも4.8μsより長い間、チャタリングが発生した場合は誤検出してしまいます。今回の波形は"1"→"0"に1回しかしていないつもりでも、波形自体は2回以上(もしかしたらオシロスコープで検出できないチャタリングがあるかもしれない)変化しました。
解決方法は、回路側で対処するか、プログラム側で対処します。例えば、回路側での対応は、チャタリングの発生しない回路を入れます。プログラム側での対応は、割り込みが発生したら、0.1秒間は割り込みが発生しても無視するようにする、などします。ここでは解決例は記載しませんので、自分なりに考えたり、「チャタリング防止回路」で検索して調べたりして、対処してみてください。
|