内容
R8C/M12Aの内蔵周辺機能のひとつであるタイマRJ2を使って、圧電サウンダーから音を鳴らします。圧電サウンダーに、特定の周波数のパルスを加えることにより音が鳴ります。パルス幅やタイミングをマイコンで制御しています。
今回の「タイマRBJ」の「2」は、Ver.2という意味です。型式の違うR8CマイコンにはタイマRJがありますが、タイマRJ2の方が機能がアップしています!
ワークスペース
「開発環境を整える」ページからダウンロードしてください。
回路
回路を下図に示します。
ブレッドボード実装図
ブレッドボードの実装を下図に示します。
実習中のブレッドボード
プログラムを開く
ワークスペース「r8cm12a_breadboard」のプロジェクト「04sounder」をアクティブ(有効)にします。「04sounder」が太字になっていない場合は、右画面のように、「アクティブプロジェクトに設定」してください。
「ビルド→ビルド」して、MOTファイルを作成、「ツール→R8C Writer」でプログラムを書き込んで、実行してください。 |
|
プロジェクト「04sounder」を有効にする |
実行中の動画
※映像は動きません。音だけ鳴ります。音量は小さめにして、少しずつ上げていってください。
プログラムの説明
タイマRJ2の設定
タイマRJ2の概要(パルス出力モード)を、下図に示します。
タイマRJ2を使って、パルスを出力します。タイマRJ2を使ったパルス出力は、ON幅とOFF幅の比率を変えることは出来ず、常にON幅:OFF幅=50%:50%になります。今回のようにON幅とOFF幅を同じでパルス出力する場合は、持ってこいのタイマとなります。
これからタイマRJ2のパルス出力モードについて、説明します。
■TRJO端子の選択
TRJO端子(タイマRJ2を使ったパルス出力モードで、パルスを出力することのできる端子)は、P3_7端子とP1_6端子の2つあります。どちらの端子を使うかは、プログラムで設定します。
P3_7端子からパルスを出力したい場合、ポートP3_7機能選択ビット(P37SEL1,P37SEL0)を下記のように設定します。
p37sel1 = 1; /* P3_7をTRJO端子にする */
p37sel0 = 0; /* 〃 */
P1_6端子からパルスを出力したい場合、ポートP1_6機能選択ビット(P16SEL1,P16SEL0)を下記のように設定します。
p16sel1 = 1; /* P1_6をTRJO端子にする */
p16sel0 = 0; /* 〃 */
今回は、P3_7をタイマRJ2 パルス出力モードの出力端子にしています。
■タイマRJモードレジスタ(TRJMR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
0 |
タイマRJカウントソース 選択ビット 000:f1(20MHz) 001:f8(2.5MHz) 010:fHOCO(20MHz) 011:f2(10MHz)
|
0 |
タイマRJ動作モード 選択ビット 000:タイマモード 001:パルス出力モード 010:イベントカウンタモード 011:パルス幅測定モード 100:パルス周期測定モード |
設定値 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
1 |
|
タイマRJカウントソース選択ビットは、f2(10MHz)を選びます。これは、タイマRJカウンタの値が、100nsごとにカウントダウンしていくことになります。
タイマRJ動作モード選択ビットは、今回は「パルス出力モード」を選びます。
■タイマRJ制御レジスタ(TRJCR)の設定
bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
設定 内容 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
タイマRJカウント 開始ビット 0:カウント停止 1:カウント開始 |
設定値 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
x |
ビットの 名称 |
|
|
|
|
|
|
|
TSTART_TRJCR |
|
タイマRJカウント開始ビットを"1"にすると、タイマRJカウンタレジスタ(TRJ)の値がタイマRJカウントソース選択ビットで設定した時間ごとに-1していきます。値の変化は、TSTART_TRJCR(タイマRJカウント開始ビット)が"1"のときだけです。"0"だと、値は変化しません。
■タイマRJカウンタレジスタ(TRJ)
bit |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
値 |
TSTART_TRJCR="1"なら、タイマRJカウントソース選択ビットで設定した時間(今回は100ns)ごとに-1します。1の次は0、0の次が設定した値です。 TSTART_TRJCR="0"なら、値は変化しません。 |
|
TRJが「・・・→2→1→0→設定した値→・・・」と、0から設定した値に変わる瞬間に波形が反転します。TRJには、ON幅(またはOFF幅)をTRJに設定しておきます。
例えば、周期1msのパルスを出力したいときの計算方法は次のようになります。
出力したい周期/タイマRJカウントソース
=(1×10-3)/(100×10-9)= 10000
タイマRJカウンタ(TRJ)に設定する値は、ON幅です。周期の1/2なので、
10000 / 2 = 5000
最後に1引いた値が、タイマRJカウンタ(TRJ)に設定する値になります。
TRJ = 5000 - 1 = 4999
■タイマRJ2の設定プログラム
今回のinit関数内でのタイマRJ2の初期化プログラムを下記に示します。
259 : /* タイマRJ2の設定 */
260 : p37sel1 = 1; /* P3_7をTRJO端子にする */
261 : p37sel0 = 0; /* 〃 */
262 : msttrj = 0; /* タイマRJ2を有効にする */
263 : trjmr = 0x31; /* パルス出力モードに設定 */
264 : trj = 0; /* TRJ×1/20M*2の時間でON/OFFする*/
265 : //tstart_trjcr = 1; /* タイマスタート(今回はまだしない) */
※265行はコメントです。今回はタイマスタートはここでは実行しません。
他のプログラムでこの部分を使って、タイマスタートする場合は、
「//」をとってこの行のプログラムを実行してください。
「msttrj」は、タイマRJ2スタンバイビットで、タイマRJ2を有効にするか、無効にするかを選択するビットです。0で有効です。初期はタイマRJ2が無効になっているので、タイマRJ2を使う前にこのビットを0にしてください。
波形出力は、次で説明するsounder関数で行うので、ここではまだタイマRJカウンタのカウントはしません。すなわち、tstart_trjcrを1にはまだしません。
sounder関数
sounder関数を説明する前に、音階について説明します。
音階とは、「ドレミファソラシド」のことです。この音階の周波数が分かれば周期が分かりますので、デューティ比50%のPWMをブザーに出力すれば、「ドレミファソラシド」と音を鳴らすことができます。
音階は、「ド」から次の高い「ド」まで「ド、ド#、レ、レ#、ミ、ファ、ファ#、ソ、ソ#、ラ、ラ#、シ」の12段階あります。12段階を1オクターブといいます。
4オクターブ目のドの音の周波数は261.6Hzです。12段階の周波数は、次の式で求めることができます。
周波数=261.6×2(x/12) [Hz]
音階と周期についての計算を、下表に示します。
オク ターブ |
音階 |
x |
計算式 |
周波数[Hz] |
周期[ms] |
0 |
ド |
-48 |
261.6×2(-48/12) |
16.4 |
61.16 |
1 |
ド |
-36 |
261.6×2(-36/12) |
32.7 |
30.58 |
2 |
ド |
-24 |
261.6×2(-24/12) |
65.4 |
15.29 |
3 |
ド |
-12 |
261.6×2(-12/12) |
130.8 |
7.65 |
4 |
ド |
0 |
261.6×2(0/12) |
261.6 |
3.82 |
4 |
ド# |
1 |
261.6×2(1/12) |
277.2 |
3.61 |
4 |
レ |
2 |
261.6×2(2/12) |
293.6 |
3.41 |
4 |
レ# |
3 |
261.6×2(3/12) |
311.1 |
3.21 |
4 |
ミ |
4 |
261.6×2(4/12) |
329.6 |
3.03 |
4 |
ファ |
5 |
261.6×2(5/12) |
349.2 |
2.86 |
4 |
ファ# |
6 |
261.6×2(6/12) |
370.0 |
2.70 |
4 |
ソ |
7 |
261.6×2(7/12) |
392.0 |
2.55 |
4 |
ソ# |
8 |
261.6×2(8/12) |
415.3 |
2.41 |
4 |
ラ |
9 |
261.6×2(9/12) |
440.0 |
2.27 |
4 |
ラ# |
10 |
261.6×2(10/12) |
466.1 |
2.15 |
4 |
シ |
11 |
261.6×2(11/12) |
493.8 |
2.02 |
5 |
ド |
12 |
261.6×2(12/12) |
523.2 |
1.91 |
6 |
ド |
24 |
261.6×2(24/12) |
1049.4 |
0.96 |
|
これで周期が分かりました。あとはタイマRJカウンタ(TRJ)に設定する数値を計算するだけです。例として、4オクターブ目の「ド」を鳴らすときの値を計算します。
TRJ=ドの周期/タイマRJカウントソース/2−1
=(3.82×10-3)/(100×10-9)/ 2 − 1
=38200 / 2 − 1
=19099
タイマRJカウンタ(TRJ)に設定する値は、ON幅です。周期の1/2なので、
38200/2=19100
となります。答えに1引いた値である「19099」が、タイマRJカウンタ(TRJ)に設定する値です。
毎回計算するのは大変なので、プログラムではあらかじめdefine定義しています。
今回の定義部分(抜粋)を下記に示します。
※計算したときの有効数字が違うため、プログラムでは4オクターブ目のドは、19113になっています。
44 : /* 4オクターブ目の音階 */
45 : #define DO_4 19113 /* ド */
46 : #define DOU_4 18040 /* ド# */
47 : #define RE_4 17028 /* レ */
48 : #define REU_4 16072 /* レ# */
49 : #define MI_4 15170 /* ミ */
50 : #define FA_4 14319 /* ファ */
51 : #define FAU_4 13515 /* ファ# */
52 : #define SO_4 12756 /* ソ */
53 : #define SOU_4 12041 /* ソ# */
54 : #define RA_4 11365 /* ラ */
55 : #define RAU_4 10727 /* ラ# */
56 : #define SI_4 10125 /* シ */
いよいよ、sounder関数の説明をします。この関数で、圧電サウンダーにパルスを出力します。
285 : void sounder( unsigned int tone, int time )
286 : {
287 : if( tone == 0 ) {
288 : tstart_trjcr = 0; /* タイマ停止 */
289 : } else {
290 : trj = tone;
291 : tstart_trjcr = 1; /* タイマ開始 */
292 : }
293 : if( time != 0 ) {
294 : timer( 15000L * time / tempo );
295 : }
296 : }
引数の1つ目には、音階を設定します。2つ目には、長さを指定します。
音階が0なら、288行でタイマRJ2を停止させてパルス出力を停止します。
音階が0以外なら、タイマRJカウンタ(TRJ)に音階データをセット、タイマを開始します。
長さは、4分音符=4として、2分音符なら4分音符の2倍の長さなので8、8分音符なら4分音符の1/2倍の長さなので2を設定します。休符も同様です。音符名、休符名と値の関係を下表に示します。
音符、休符 |
説明 |
拍 |
四分音符を4としたときの長さ |
テンポが60のときの時間[秒] |
全音符 |
4分音符の4倍に当たる長さの音を表現する音符。 |
4 |
16 |
4 |
2分音符 |
4分音符の2倍に当たる長さの音を表現する音符。 |
2 |
8 |
2 |
4分音符 |
基準となる長さの音。便宜上、この音の長さを1拍とする。 |
1 |
4 |
1 |
8分音符 |
4分音符の1/2に当たる長さの音を表現する音符。 |
1/2 |
2 |
0.5 |
16分音符 |
4分音符の1/4に当たる長さの音を表現する音符。 |
1/4 |
1 |
0.25 |
32分音符 |
4分音符の1/8に当たる長さの音を表現する音符。 |
1/8 |
0.5 |
0.125 |
|
main関数
volume.cのmain関数のプログラムを、下記に示します。
82 : int tempo = 60; /* テンポ */
中略
87 : void main( void )
88 : {
89 : init(); /* 初期化 */
90 :
91 : /*
92 : 長さは、四分音符を4として、
二分音符は8、八分音符は2となります。
93 : 休符も同様に、四分休符を4として、
二部休符は8、八分休符は2となります。
94 : */
95 : /* 音階, 長さ */
96 : sounder( DO_4, 4 );
97 : sounder( RE_4, 4 );
98 : sounder( MI_4, 4 );
99 : sounder( FA_4, 4 );
100 : sounder( SO_4, 4 );
101 : sounder( RA_4, 4 );
102 : sounder( SI_4, 4 );
103 : sounder( DO_5, 4 );
104 : sounder( 0, 0 );
105 : while( 1 );
82行で、テンポを指定します。四分音符を1分間に何回演奏するかの指定です。今回は60なので、4分音符を1分間に60回鳴らす早さです。
96〜103行で、「ドレミファソラシド」を鳴らします。
104行で、音を止めます。
課題
1.「大きな古時計」を演奏するよう、プログラムを改造しなさい。
2.チャルメラの音楽(ドレミ〜レド、ドレミレドレ〜〜)を演奏しなさい。
3.R8C/M12Aマイコンと圧電サウンダーの接続をP1_6端子にして、音楽が鳴るようプログラムを改造しなさい。
※P1_6端子につながっているLEDは外してよい。
※圧電サウンダーが繋がっていると書き込みができない場合があります。その時は、書き込み時のみ圧電サウンダーを外して書き込みをしてください。
課題の回答例
1.の回答例
→ sounder_answer_1.c
2.の回答例
→ sounder_answer_2.c
3.の回答例
→ sounder_answer_3.c
|