内容
R8C/M12Aの内蔵周辺機能のひとつであるタイマRCを使って、PWM波形を3チャネル分、出力します。PWMとは、「パルス幅変調:pulse width modulation」のことで、端子を高速で"0"、"1"することです。例えば、LEDをつないでPWM波形を出力するとLEDの明るさを変えることができます。モータをつなぐとモータの回転速度を変えることができます。
回路、ブレッドボード実装図は、ボリューム(0〜5Vの電圧)の入力(A/D変換器)と同じです。
ワークスペース
r8cm12a_trc_pwm_3ch_100.zip
ファイルを解凍し、フォルダを「c:\worksapce」に入れてください。
プログラムの説明
タイマRCの設定
タイマRCの概要(PWMモード)を、下図に示します。
概略といっても複雑で分かりづらいので、細かい部分は省略した概略を、下図に示します。
タイマRCを使って、PWM波形を3チャネル出力します。タイマRCのレジスタに、パルスの周期、ON幅を一度設定すれば、PWM波形の出力をタイマRCが行うので、プログラムはPWM波形出力処理のことは一切気にせずに別な作業を行うことができます。
※タイマRCを使わなければ、プログラムで波形出力処理("1"にしたり"0"にしたり)をしながら、別なプログラムを実行することになります。プログラムが非常に大変になるか、もしくは処理が間に合わずに波形が止まってしまうかもしれません。
これからタイマRCのPWMモードについて、説明します。
■TRCIOB端子の選択
TRCIOB端子(タイマRCを使ったPWMモードで、パルスを出力することのできる端子)は、P1_2端子、P1_4端子、P1_6端子の3つあります。どの端子を使うかは、プログラムで設定します。
P1_2端子からパルスを出力したい場合、ポートP1_2機能選択ビット(P12SEL1,P12SEL0)を下記のように設定します。
p12sel1 = 0; /* TRCIOB端子の選択 */
p12sel0 = 1; /* P1_2をTRCIOB端子にする */
P1_4端子からパルスを出力したい場合、ポートP1_4機能選択ビット(P14SEL2,P14SEL1,P14SEL0)を下記のように設定します。
p14sel2 = 1; /* TRCIOB端子の選択 */
p14sel1 = 0; /* P1_4をTRCIOB端子にする */
p14sel0 = 0;
P1_6端子からパルスを出力したい場合、ポートP1_6機能選択ビット(P16SEL1,P16SEL0)を下記のように設定します。
p16sel1 = 1; /* TRCIOB端子の選択 */
p16sel0 = 1; /* P1_6をTRCIOB端子にする */
今回は、P1_2をTRCIOB端子にしています。
■TRCIOC端子の選択
TRCIOC端子(タイマRCを使ったPWMモードで、パルスを出力することのできる端子)は、P1_3端子、P3_4端子の2つあります。どの端子を使うかは、プログラムで設定します。
P1_3端子からパルスを出力したい場合、ポートP1_3機能選択ビット(P13SEL1,P13SEL0)を下記のように設定します。
p13sel1 = 0; /* TRCIOC端子の選択 */
p13sel0 = 1; /* P1_3をTRCIOC端子にする */
P3_4端子からパルスを出力したい場合、ポートP3_4機能選択ビット(P34SEL1,P34SEL0)を下記のように設定します。
p34sel1 = 0; /* TRCIOC端子の選択 */
p34sel1 = 1; /* P3_4をTRCIOC端子にする */
今回は、P1_3をTRCIOC端子にしています。
■TRCIOD端子の選択
TRCIOD端子(タイマRCを使ったPWMモードで、パルスを出力することのできる端子)は、P1_0端子、P3_5端子、P3_7端子の3つあります。どの端子を使うかは、プログラムで設定します。
P1_0端子からパルスを出力したい場合、ポートP1_0機能選択ビット(P10SEL1,P10SEL0)を下記のように設定します。
p10sel1 = 0; /* TRCIOD端子の選択 */
p10sel0 = 1; /* P1_0をTRCIOD端子にする */
P3_5端子からパルスを出力したい場合、ポートP3_5機能選択ビット(P35SEL1,P35SEL0)を下記のように設定します。
p35sel1 = 0; /* TRCIOD端子の選択 */
p35sel0 = 1; /* P3_5をTRCIOD端子にする */
P3_7端子からパルスを出力したい場合、ポートP3_7機能選択ビット(P37SEL1,P37SEL0)を下記のように設定します。
p37sel1 = 1; /* TRCIOD端子の選択 */
p37sel0 = 1; /* P3_7をTRCIOD端子にする */
今回は、P1_0をTRCIOD端子にしています。
■タイマRCモードレジスタ(TRBMR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
TRCCNT カウント 開始ビット 0:カウント停止 1:カウント開始 |
|
|
|
PWM2 モード 選択ビット 0:PWM2モード 1:タイマモードまたはPWMモード |
TRCIOD PWMモード 選択ビット 0:タイマモード 1:PWMモード |
TRCIOC PWMモード 選択ビット 0:タイマモード 1:PWMモード |
TRCIOB PWMモード 選択ビット 0:タイマモード 1:PWMモード |
設定値 |
|
|
|
|
1 |
1 |
1 |
1 |
ビットの 名称 |
CTS_ TRCMR |
|
|
|
PWM2_ TRCMR |
PWMD_ TRCMR |
PWMC_ TRCMR |
PWMB_ TRCMR |
|
PWM2モード選択ビットを"1"にするとPWMモードになります。TRCIOD PWMモード選択ビットで、TRCIOD端子からPWM波形を出力するかどうか選択します。今回はPWMモードにします。TRCIOC PWMモード選択ビット、TRCIOB PWMモード選択ビットも同様です。今回は、3端子ともPWMモードにします。
CTS_TRCMRは、後述します。
■タイマRC制御レジスタ1(TRCCR1)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
TRCCNTカウンタ クリア選択ビット 0:フリーランニングカウンタ 1:インプットキャプチャ/コンペア一致AでTRCCNTカウンタクリア |
カウントソース 選択ビット 000:f1(20MHz) 001:f2(10MHz) 010:f4(5MHz) 011:f8(2.5MHz) 100:f32(0.625MHz) 110:fHOCO(20MHz) |
0 |
0 |
0 |
0 |
設定値 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
|
TRCCNTカウンタクリア選択ビットを"1"にして、「インプットキャプチャ/コンペア一致AでTRCCNTカウンタクリア」を選びます。これは、「TRCCNT=TRCGRA+1」になったら、TRCCNTを0にするという意味です。
カウントソース選択ビットは、f1(20MHz=50nsの周期)を選びます。これは、TRCCNTが50nsごとに+1する設定です。
■タイマRCジェネラルレジスタA(TRCGRA)の設定
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
PWM波形の周期1msなら19999を設定 |
|
TRCIOB、TRCIOC、TRCIODの各端子から出力するPWM波形の周期を設定します。3つの波形の周期は共通です。残念ながら端子ごとに周期を変えることはできません。タイマRCジェネラルレジスタA(TRCGRA)の計算方法を下記に示します。
TRCGRA=設定したいPWM周期÷カウントソース選択ビットで設定したクロック
今回、PWM周期は1msにすることにします。よって、
TRCGRA=1ms÷50ns
=20000
値の設定は、1引いた値を設定します。したがって、プログラムでは、TRCGRA=19999を設定します。これは、「TRCCNT=TRCGRA+1」になったときに、波形を"1"にする、というタイマRCの仕様のためです。「+1」があるので、TRCGRAに設定する値は、1引いた値にします。
■タイマRCジェネラルレジスタB(TRCGRB)の設定
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
TRCIOB端子から出力するON幅を設定 |
|
TRCIOB端子から出力するPWM波形のON幅を設定します。タイマRCジェネラルレジスタB(TRCGRB)の計算方法を下記に示します。
TRCGRB=設定したいTRCIOB端子のON幅÷カウントソース選択ビットで設定したクロック
■タイマRCジェネラルレジスタC(TRCGRC)の設定
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
TRCIOC端子から出力するON幅を設定 |
|
|
TRCIOC端子から出力するPWM波形のON幅を設定します。タイマRCジェネラルレジスタC(TRCGRC)の計算方法を下記に示します。
TRCGRC=設定したいTRCIOC端子のON幅÷カウントソース選択ビットで設定したクロック
■タイマRCジェネラルレジスタD(TRCGRD)の設定
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
TRCIOD端子から出力するON幅を設定 |
|
■タイマRCカウンタ(TRCCNT)の設定
※プログラム内では、TRCCNTの設定はしませんが、動作の理解に必要なので説明しておきます。
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
0→1→・・・→19998→19999→0、とカウントアップしていきます。 |
|
カウントソース選択ビットで設定したクロックでカウントアップします。今回は、50nsごとに+1します。値は、「TRCCNT=TRCGRA+1」になった瞬間に0になります。今回は、TRCGRAは19999に設定しているので、TRCCNTの値は、
0→1→・・・→19999→0(20000になった瞬間に0になる)→1→・・・
となります。19999から0に変わる瞬間にTRCIOB、TRCIOC、TRCIODの各端子の波形が"1"になります。
■タイマRC出力許可レジスタ(TRCOER)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
|
|
|
|
TRCIOD出力 禁止ビット 0:出力許可 1:出力禁止 |
TRCIOC出力 禁止ビット 0:出力許可 1:出力禁止 |
TRCIOB出力 禁止ビット 0:出力許可 1:出力禁止 |
|
設定値 |
|
|
|
|
0 |
0 |
0 |
|
ビットの 名称 |
|
|
|
|
ED_TRCOER |
EC_TRCOER |
EB_TRCOER |
|
|
TRCIOB端子、TRCIOC端子、TRCIOD端子からPWM波形を出力することを許可するか、禁止するかを設定します。今回は出力するので、3つの端子を許可します。
■タイマRCモードレジスタ(TRBMR)の設定
TRCCNTカウント開始ビット(CTS_TRCMR)を"1"にして、タイマRCカウンタ(TRCCNT)のカウントを開始します。
タイマRCの設定は、init関数内で行います。プログラムを下記に示します。
/* タイマRCによるPWM出力(3ch出力) */
msttrc = 0; /* タイマRCを有効にする */
p12sel1 = 0; /* TRCIOB端子の選択 */
p12sel0 = 1; /* P1_2をTRCIOB端子にする */
p13sel1 = 0; /* TRCIOC端子の選択 */
p13sel0 = 1; /* P1_3をTRCIOC端子にする */
p10sel1 = 0; /* TRCIOD端子の選択 */
p10sel0 = 1; /* P1_0をTRCIOD端子にする */
pwm2_trcmr = 1; /* PWMモード */
pwmd_trcmr = 1; /* TRCIOD出力 PWM出力する */
pwmc_trcmr = 1; /* TRCIOC出力 PWM出力する */
pwmb_trcmr = 1; /* TRCIOB出力 PWM出力する */
trccr1 = 0x80; /* カウントソース = f1 */
trcgra = 20000-1; /* PWM周期の設定 1/20M*20000=1ms*/
trcgrb = 0; /* TRCIOB端子のON幅の設定 */
trcgrc = 0; /* TRCIOC端子のON幅の設定 */
trcgrd = 0; /* TRCIOD端子のON幅の設定 */
ed_trcoer = 0; /* TRCIODの出力 出力許可 */
ec_trcoer = 0; /* TRCIOCの出力 出力許可 */
eb_trcoer = 0; /* TRCIOBの出力 出力許可 */
cts_trcmr = 1; /* TRCCNT カウント開始 */
「msttrc」は、タイマRCスタンバイビットで、タイマRCを有効にするか、無効にするかを選択するビットです。0で有効です。初期状態ではタイマRCは無効になっているので、タイマRCを使う前にこのビットを0にしてください。
波形出力
■0%以外、100%以外の設定
タイマRCカウンタ(TRCCNT)、タイマRCジェネラルレジスタA(TRCGRA)、タイマRCジェネラルレジスタB(TRCGRB)の値と、TRCIOB端子の波形の様子を下図に示します。
タイマRCジェネラルレジスタB(TRCGRB)の値を、TRCCNT=TRCGRB+1になる前に、タイマRCカウンタ(TRCCNT)より小さい値に変更したときの様子を下図に示します。
「TRCCNT=TRCGRB+1」が起こらないタイミングが1周期分でてしまい、1周期PWM出力が100%になってしまいます。もしモータをつないでいたならば、一瞬ですがモータがフル回転してしまいます。そこで、ON幅を変更するときは、下図のようにタイミングを見て変更するようにします。
青色の範囲のとき(TRCCNT=TRCGRB+1になる前)に、TRCGRBの値をTRCCNTより小さい値に変えると、波形が"0"にならなくなります。よって、下記のプログラムで、波形が"1"なら(TRCCNTの値がTRCGRBより小さいなら)、この行を繰り返し続けて待ちます。波形が"0"になったら(TRCCNTがTRCGRBより大きくなったら)、TRCGRBを新しい値に変えます。
while( trccnt <= trcgrb ); //ここで待つ
trcgrb = 新しい値;
※このプログラムは、まだ完成ではありません。
完成版は、後述します。
■0%のときの設定
PWM波形を0%にしようと、TRCGRBの値を0にしても、「TRCCNT=TRCGRB+1」で波形が"0"になるので、「TRCCNT=TRCGRB+1=0+1=1」と、1クロック分(f1=50nsなら、50ns)"0"になってしまいます。タイマRCは、ルネサス エレクトロニクスの「R8C/M11A グループ、R8C/M12A グループ ユーザーズマニュアル ハードウェア編」には、「周期レジスタとデューティレジスタのコンペア、一致が同時に発生すると、出力は変化しません」とあります。これは、波形が"0"のときに「TRCGRB=TRCGRA」にすればよいことになります(下図)。
そこで、0%,100%以外の設定で説明した、波形が"0"になるまで待つプログラムを実行してから、「TRCGRB=TRCGRA」を実行します。
while( trccnt <= trcgrb ); //ここで待つ
trcgrb = trcgra;
※このプログラムは、まだ完成ではありません。
完成版は、後述します。
■100%のときの設定
こちらは簡単で、"0"になるきっかけを作らなければ良いのです。"0"になるきっかけは「TRCCNT=TRCGRB+1」なので、TRCGRBの値をTRCCNTより大きい値にします。ここでは、1大きい値にしておきます(下図)。
プログラムを、下記に示します。
■100%出力から、それ以外の出力に変えるとき
0%にするとき、または0%と100%以外のとき、先に説明した次のプログラムを実行します。
// 0%にするプログラム
while( trccnt <= trcgrb ); //ここで待つ
trcgrb = trcgra;
// 0%と100%以外のときのプログラム
while( trccnt <= trcgrb ); //ここで待つ
trcgrb = 新しい値;
※このプログラムは、まだ完成ではありません。
完成版は、後述します。
while文で、TRCGRBの値がTRCCNTより小さいか等しければ、この行を繰り返し実行してそれ以外の条件になるまで待ちます。
もし、現在のPWMが100%なら、TRCGRBの値は20000です。これからそれ以外のPWM値にを設定しようと思います。「0%にするとき」、「0%,100%以外に設定するとき」共に、while文で「TRCCNT <= TRCGRB」なら、while文を繰り返し、それ以外の条件になったら次の行に進みます。しかし、TRCCNTの値は「・・・19998→19999→0→1・・・」と20000以上にはなりません。TRCCNTの値が最大でも、while文の条件は「19999 <= 20000」となり、いつまで経ってもwhile文を抜ける条件になりません。要はここでプログラムが止まってしまいます。
よって、「0%にするとき」、「0%,100%以外に設定するとき」は、TRCGRBの値がTRCGRAより小さいときだけ、while文を実行するようにします。プログラムを下記に示します。
// 0%出力に設定するとき
if( trcgrb < trcgra ) while( trccnt <= trcgrb );
trcgrb = trcgra;
// 0%,100%以外
if( trcgrb < trcgra ) while( trccnt <= trcgrb );
trcgrb = 新しい値;
■0%,100%,それ以外を条件分けして関数化する
今までの説明をまとめ関数化して、すぐに使えるようにします。TRCIOB端子へPWM波形を出力する関数なので「set_trciob」と命名し、引数は0〜19999(TRCGRAと同じ値)が0〜100%になるようにします。関数を下記に示します。
void set_trciob( int out )
{
if( out == 0 ) {
// 0%出力
if( trcgrb < trcgra ) while( trcgrb >= trccnt );
trcgrb = trcgra;
} else if( out == trcgra ) {
// 100%出力
trcgrb = trcgra + 1;
} else {
// 0%,100%以外
if( trcgrb < trcgra ) while( trcgrb >= trccnt );
trcgrb = out;
}
}
TRCIOC端子、TRCIOD端子も同様の考え方なので、関数化してみましょう!
main関数
main関数を下記に示します。
void main( void )
{
int pwm;
init(); /* 初期化 */
while( 1 ) {
pwm = (long)19999 * get_ad7() / 1023;
set_trciob( pwm );
}
}
get_ad7関数で、P1_7端子に繋がっているボリュームからの0〜5V信号を0〜1023の値に変換します。さらに、PWM=19999×AD値(0〜1023)÷1023の計算をして、0〜19999の値に変換します。
この値をset_trciob関数にセットすると、P1_2端子からPWM波形が出力されます。ボリュームを回すと、P1_2端子に繋がっているLEDの明るさが変わりますので、試してみてください。
|