本内容は、神戸市立科学技術高等学校 電気情報工学科・登 弘聡先生が作成したプログラムを参考にさせていただきました。ありがとうございました。
内容
送信機からの信号を受信機で受信し、サーボを動かし、ラジコンやヘリコプターを動かします(下図)。
サーボを、R8C/M12Aマイコンに変えます。受信機からは、周期16ms、ON幅0.7〜2.3msのパルスが出力されているので、その幅をマイコンで測定します。今回は、測定したパルス幅に応じてLED 8個を点灯させます(下図)。
ワークスペース
r8cm12a_pulse_width_100.zip
ファイルを解凍し、フォルダを「c:\worksapce」に入れてください。
回路
回路を下図に示します。
プログラムの説明
タイマRJ2の設定
タイマRJ2の概要(パルス幅測定モード)を、下図に示します。
タイマRJ2を使って、入力端子(P1_5、P1_7、P4_6のどれか一つだけ選択)の"1"の時間(パルス幅)を測定します。測定時間は、f1を選んだときは3.2768msまで、f2を選んだときは6.5536ms、f8を選んだときは26.2144msになります。それ以上は、オーバーフローとなり測定できません(プログラムを工夫すればできます)。
これからタイマRJ2のパルス幅測定モードについて、説明します。
■TRJIO端子の選択
TRJIO端子(タイマRJ2を使ったパルス幅測定モードで、信号を入力することのできる端子)は、P1_5端子、P1_7端子、P4_6端子の3つあります。どの端子を使うかを、プログラムで設定します。
P1_5端子を入力端子にしたい場合、ポートP1_5機能選択ビット(P15SEL2,P15SEL1,P15SEL0)を下記のように設定します。忘れずに、P1_5端子の入出力設定も入力にしておきましょう(pd1を設定)。
p15sel2 = 0; /* P1_5をTRJIO端子にする */
p15sel1 = 1;
p15sel0 = 0;
P1_7端子を入力端子にしたい場合、ポートP1_7機能選択ビット(P17SEL1,P17SEL0)を下記のように設定します。忘れずに、P1_7端子の入出力設定も入力にしておきましょう(pd1を設定)。
p17sel1 = 1; /* P1_7をTRJIO端子にする */
p17sel0 = 0;
P4_6端子を入力端子にしたい場合、ポートP4_6機能選択ビット(P46SEL2,P46SEL1,P46SEL0)を下記のように設定します。忘れずに、P4_6端子の入出力設定も入力にしておきましょう(pd4を設定)。
p46sel2 = 1; /* P4_6をTRJIO端子にする */
p46sel1 = 0;
p46sel0 = 1;
今回は、P4_6をTRJIO端子にしています。
■タイマRJモードレジスタ(TRJMR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
タイマRJカウントソース選択ビット 000:f1(20MHz) 001:f8(2.5MHz) 011:f2(10MHz) |
|
タイマRJ動作モード選択ビット 000:タイマモード 001:パルス出力モード 010:イベントカウンタモード 011:パルス幅測定モード 100:パルス周期測定モード |
設定値 |
|
0 |
0 |
0 |
|
0 |
1 |
1 |
ビットの 名称 |
|
TCK2_ TRJMR |
TCK1_ TRJMR |
TCK0_ TRJMR |
|
TMOD2_ TRJMR
|
TMOD1_ TRJMR
|
TMOD0_ TRJMR
|
|
タイマRJカウントソース選択ビットで、ON幅を測定する精度(細かさ)を設定します。
000…f1(20MHz)を設定します。精度は、50nsになります(今回の設定)。
001…f8(2.5MHz)を設定します。精度は、400nsになります。
011…f2(10MHz)を設定します。精度は、100nsになります。
タイマRJ動作モード選択ビットは、今回はパルス幅測定モードにします。
■タイマRJ I/O制御レジスタ(TRJIOC)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
|
|
|
|
|
入出力極性切り換えビット 0:Lレベル幅("0"の幅)を測定 1:Hレベル幅("1"の幅)を測定 |
設定値 |
|
|
|
|
|
|
|
1 |
ビットの 名称 |
|
|
|
|
|
|
|
TEDGSEL_TRJIOC |
|
入出力極性切り換えビットで、"1"の幅を測るか、"0"の幅を測るか設定します。今回は"1"の幅を測ります。
■タイマRJカウンタレジスタ(TRJ)の設定
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
初期値 0xffffを設定 |
|
タイマRJカウンタレジスタ(TRJ)を設定します。このレジスタの値が、入力信号が"1"の間、50nsごとに-1していきます(ダウンカウント)。ダウンカウントなので、初期値は最大値である0xffffにしておきます。「0xffff-TRJ」の値がON幅になります。
■タイマRJ割り込み制御レジスタ(TRJIR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
タイマRJ割り込み 許可ビット 0:割り込み禁止 1:割り込み許可 |
タイマRJ割り込み 要求フラグ 0:割り込み要求なし 1:割り込み要求あり |
|
|
|
|
|
|
設定値 |
1 |
|
|
|
|
|
|
|
ビットの 名称 |
TRJIE_TRJIR |
TRJIF_TRJIR |
|
|
|
|
|
|
|
タイマRJ割り込み許可ビットを"1"にして、割り込み許可にします。入力信号が"1"になると自動的にTRJのカウントダウンが開始され、"0"になるとカウントダウンが停止します。停止したときに割り込みを発生させ、パルス幅を計算するようにします。
■割り込み優先レベルレジスタB (ILVLB)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
周期タイマの割り込み優先レベル設定ビット 00:レベル0 (割り込み禁止) 01:レベル1 10:レベル2 11:レベル2 |
|
|
タイマRJ2の割り込み優先レベル設定ビット 00:レベル0 (割り込み禁止) 01:レベル1 10:レベル2 11:レベル2 |
設定値 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
ビットの 名称 |
|
|
ILVLB5 |
ILVLB4 |
|
|
ILVLB1
|
ILVLB0
|
|
タイマRJ2の割り込み優先レベル設定ビットを設定します。これは、複数の割り込みが発生した場合に、どの割り込みを優先させるかを設定します。今回はタイマRJ2の割り込みしか使っていませんので1以上であればどの値でも構いませんが、一応いちばん大きいレベル2にしておきます。
■タイマRJ制御レジスタ(TRJCR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
|
|
|
|
|
タイマRJカウント開始ビット 0:カウント停止 1:カウント開始 |
設定値 |
|
|
|
|
|
|
|
1 |
ビットの 名称 |
|
|
|
|
|
|
|
TSTART_TRJCR |
|
タイマRJカウント開始ビットを"1"にして、TRJがカウントダウンするように設定します。
■全体の割り込みを許可する
タイマRJ割り込み制御レジスタ(TRJIR)で、タイマRJ2の割り込みを許可しましたが、初期状態ではマイコン全体の割り込みが禁止になっています。
そのため、最後にマイコン全体の割り込みを許可します。全体割り込み許可は、マイコンのCPUレジスタという、C言語では操作できない場所にあるので、アセンブラで命令を記述します(下記プログラム)。asm関数は、C言語プログラム内でアセンブラ命令を記述する命令です。
/* 全体割り込みの許可 */
asm(" fset I "); /* 全体の割り込み許可 */
タイマRJ2の設定は、init関数内で行います。プログラムを下記に示します。
/* タイマRJ2の設定 */
msttrj = 0; /* タイマRJ2を有効にする */
p46sel2 = 1; /* P4_6をTRJIO端子にする */
p46sel1 = 0;
p46sel0 = 1;
tck2_trjmr = 0; /* カウントソース = f1 */
tck1_trjmr = 0;
tck0_trjmr = 0;
tmod2_trjmr = 0; /* パルス幅測定モード */
tmod1_trjmr = 1;
tmod0_trjmr = 1;
tedgsel_trjioc = 1; /* Hレベルを測定 */
trj = 0xffff; /* TRJに最大値を入れる */
trjie_trjir = 1; /* TRJ割り込み許可 */
ilvlb = 0x02; /* 割り込み優先レベル2 */
tstart_trjcr = 1; /* タイマスタート */
/* 全体割り込みの許可 */
asm(" fset I "); /* 全体の割り込み許可 */
「msttrj」は、タイマRJ2スタンバイビットで、タイマRJ2を有効にするか、無効にするかを選択するビットです。0で有効です。初期状態ではタイマRJ2は無効になっているので、タイマRJ2を使う前にこのビットを0にしてください。
割り込みプログラム(パルス幅の測定)
割り込みプログラムを下記に示します。このプログラムは、入力信号が"1"→"0"になった瞬間、またはアンダーフロー(TRJが0→65535になった瞬間)に実行されます。
#pragma interrupt intTRJ(vect=22)
void intTRJ( void )
{
if( tundf_trjcr ) { /* アンダフローあり? */
// 50ns×65536=3.2768ms以上ONなら、計測できない
tundf_trjcr = 0;
}
if( tedgf_trjcr ) { /* 立ち下がり検出 */
tedgf_trjcr = 0;
/* パルス幅セット */
pulse_width = 0xffff - trj;
/* カウンタクリア(いったん停止させてセット) */
tstart_trjcr = 0; /* TRJ停止 */
trj = 0xffff;
tstart_trjcr = 1; /* TRJ再開 */
}
}
intTRJ関数が、タイマRJ2割り込みが発生したときに実行される関数です。この関数がタイマRJ2割り込みの実行先ということを設定するのが、「#pragma interrupt」命令です。この命令の書式を下記に示します。
#pragma interrupt 割り込み関数名(vect=割り込み番号)
void 割り込み関数名( void )
{
割り込みプログラム
}
タイマRJ2の割り込み番号は22と決まっています。どの内蔵周辺機能が何番の割り込み番号かは、ルネサス エレクトロニクスの「R8C/M11Aグループ、R8C/M12Aグループ ユーザーズマニュアル ハードウェア編」の「可変ベクタテーブル」部分を参照してください。
割り込み関数名は、自由に付けて構いません。今回はタイマRJ2割り込みなので、割り込みの「interrupt」とタイマRJ2の「Timer RJ2」を略して、「intTRJ」としました。
タイマRJカウンタレジスタ(TRJ)の値、入力波形などの関係を、下図に示します。
今回、割り込みプログラムが実行されるきっかけは次の2つあります。
@タイマRJカウンタレジスタ(TRJ)がアンダーフローした(0→65535になった瞬間の)とき
A入力端子が"1"から"0"になった瞬間
@で割り込みが発生した場合、tundf_trjcrが1になります。tundf_trjcrをチェックして1なら、tundf_trjcrを0にして、何もせずに終了します。
Aで割り込みが発生した場合、tedgf_trjcrが1になります。tedgf_trjcrをチェックして1なら、tedgf_trjcrを0にして、パルス幅をpulse_width変数に入れます。
入力波形が"1"になるとTRJが0xffffからダウンカウントしていき、入力波形が"0"になると停止します。よって、0xffffから現在の値を引くと、ONの幅が分かります。プログラムは次のようになります。
pulse_width = 0xffff - trj; //pulse_width変数にパルス幅が入る
今回の設定では、pulse_widthの値が1あたり、50nsなので、パルス幅は次の計算で求めることができます。
パルス幅[s] = 50[ns] × pulse_width
最後に、タイマRJカウンタレジスタ(TRJ)を0xffffに設定して、次のパルス幅測定に備えます。ただし、設定はTRJのカウントが停止されている状態でなければいけません(図のTSTART_TRJCR部分がOFFの状態でなければいけません)。よって、tstart_trjcrを0にしてから、TRJに0xffffを代入、再度、tstart_trjcrを1にします。
これで、パルス幅が分かりました。受信機からは、送信機のジョイスティックの操作量に応じてON幅0.7〜2.3msのパルスが出力されますので、pulse_width変数でパルス幅を測定、パルス幅に応じてLEDを光らせたり(今回のプログラム)、モータを動かす(「モータドライブ基板Ver.4をつないでモータ制御」を参照してください)など、プログラム次第で様々な応用が可能です。
|