前回はPWMによるLEDの調光のしくみからH8/36064マイコンに内蔵されているタイマZモジュールの構造やレジスタの機能について解説しました.今回はタイマZモジュール機能を使ったLEDの明るさを変化させる簡単なC言語プログラムを作ってみましょう.H8初心者にとっては,実際にH8マイコンを使ってLEDの明るさを変化させてみることで,前回説明したモジュールを制御するレジスタなどの理解が深まると思います.
■タイマZによるPWMモードの動作
タイマZによるPWMモードの動作例を図1に示します.LED2(橙) はFTIOB1端子に接続されています.端子の制御にはチャネル1用のタイマ・カウンタ(TCNT_1)を使用します.
(1) リセットした直後の最初のコンペアマッチが起こるまでのタイマ出力(FTIOB1端子出力)は'1'("H")です.TSTRレジスタのSTR1ビットを'1'に設定するとTCNT_1は0x0000からカウントアップを開始します.
(2) TCNT_1がGRB_1の設定値と一致(コンペアマッチB)のとき,FTIOB1端子出力が'0'("L")になります.
(3) TCNT_1がGRA_1の設定値と一致(コンペアマッチA)のとき,FTIOB1端子出力が'1'("H")になります.
(4) また,コンペアマッチAのときTCNT_1がクリアされ,再び0x0000からカウントアップを開始して(2)~(4)を繰り返します.図1に示すように,パルス幅WはGRB_1の設定値,パルス周期TはGRA_1の設定値で決まるPWM波形がFTIOB1端子から出力されます.
<図1>タイマZによるPWMモードの動作例
ここで,PWM波形の周期TとGRA_1レジスタの関係,およびパルス幅WとGRB_1レジスタの関係は次式のようになります.
T = GRA_1 / PSS・・・(1)
W = GRB_1 / PSS・・・(2)
ただし,PSSはプリスケーラの設定(φ,φ/2,φ/4,φ/8)です.φはH8マイコン・ボードの水晶発振器のクロック周波数(14.7456MHz)です.なお,デューティ比DとGRA_1,GRB_1との関係は次式のようになります.
D = W / T = GRB_1 / GRA_1・・・(3)
(計算例)波形の周期T=10ms,パルス幅W=2.5ms(デューティ比D=25%)のPWM波形を出力させる場合のGRA_1,GRB_1の値を求めてみます.ここでは,プリスケーラはPSS=φ/4に設定するものとします.式(1)より,
GRA_1 = 10ms × 14.7456MHz/4 = 36864 (=0x9000)
式(2)より,
GRB_1 = 2.5ms × 14.7456MHz/4 = 9216 (=0x2400)
となります.
■各種レジスタ設定
表1に各種レジスタと設定した値を示します.TCNT_1レジスタの初期値は0x0000になっているため,設定は省略できます.
<表1>各種レジスタと設定値
(注1)赤字のレジスタおよびビットを設定する.それ以外は初期値のままで設定は省略可.
■タイマZによるPWMモードでLEDの明るさを変えるC言語プログラムを作成する
LEDの明るさをPWMモードで変えるプログラムを作成するということで,ワークスペース名には「led_pwm」という名前をつけたいと思います.リスト1にC言語プログラムのソース・リストを示します.
<リスト1>タイマZによるPWMモードでLEDの明るさを変えるプログラム(led_pwm.c)のソース・リスト
#include "iodefine.h" // (1) I/Oレジスタ定義ファイル
void main(void)
{
TZ1.TCR.BIT.TPSC = 2; // (2) 内部クロックφ/4 でカウント
TZ1.TCR.BIT.CCLR = 1; // (3) コンペアマッチAでTCNT_1をクリア
TZ.TPMR.BIT.PWMB1 = 1; // (4)FTIOB1端子はPWMモード
TZ1.GRA = 0x9000; // (5) 周期の設定(T=10ms)
TZ1.GRB = 0x2400; // (6) パルス幅の設定(W=2.5ms)
TZ.TOER.BIT.EB1 = 0; // (7)FTIOB1端子の出力許可
TZ.TSTR.BIT.STR1 = 1; // (8) TCNT_1カウント開始
}
●プログラムの概要
リスト1に示したコメント (1) ~ (8) の順にプログラムの流れを説明していきます.
(1) I/Oレジスタ定義ファイル・・・main関数の前にI/Oレジスタ定義ファイルを取り込みます.これでタイマZモジュールに関するレジスタやビット名が定義され,アドレスを記述する作業などを省略することができます.I/Oレジスタ定義ファイルについては基礎編の第23回に解説があります.
(2) 内部クロックφ/4 でカウント…周期T=10msに設定する場合,式(1)よりPSS=φ/4,もしくはφ/8,どちらかの内部クロックを選択することになります.φ/4を選択するとタイマ設定の分解能を高くすることができます.
(3) コンペアマッチAでTCNT_1をクリア…PWMモードの動作説明にあるように,TCNT_1がGRA_1の設定値と一致(コンペアマッチA)のときクリアされる設定とします.
(4) FTIOB1端子はPWMモード…FTIOB1端子をPWMモードに設定してLEDの調光を行います.
(5) 周期の設定(T=10ms)…式(1)より求めたGRA_1の値により周期が設定されます.
(6) パルス幅の設定(W=2.5ms)…式(2)より求めたGRB_1の値によりHighレベル幅が設定されます.
(7) FTIOB1端子の出力許可…TOERレジスタのEB1ビットでFTIOB1端子のタイマ出力を許可します.
(8) TCNT_1カウント開始…TSTRレジスタのSTR1ビットを1にセットすると,TCNT_1カウンタが動作します.
■リスト1のC言語プログラムを実行してLEDを光らせてみよう!
●Htermによるプログラムの実行
それでは,リスト1に示したC言語プログラムをHtermで実行してみましょう.図2に示すように,Htermのコンソールから次のように入力してみましょう.F890はプログラムの先頭アドレスです.
G F890[リターンキー]
これでLED2(橙)が点灯すればプログラムが正常に動作しています.LEDの点灯を確認したらH8マイコン・ボードのプッシュ・スイッチを押してHtermへ戻りましょう.
<図2>Htermのコンソール画面例
●周辺機能のレジスタ表示と変更
次にGRBレジスタの値を変更してみます.[表示]メニューから[Peripheral]を選択すると,周辺機能を選択するウィンドウ(図3)が開きます.ここでは[TZ1]を選択して[OK]ボタンをクリックしてみましょう.

<図3>周辺機能の選択画面(ここではTZ1を選択する)
すると,図4に示すようにTZ1に関連するレジスタが表示されます.画面の左から,REG(レジスタ名),ADDR(アドレス),CODE(データ),7~0(各ビット名)となっています
<図4>TZ1に関連するレジスタが表示
さて,Peripheralウィンドウ内でGRBレジスタが表示されている部分をダブルクリックすると,図5のようにCODEの値が変更できます.設定値は16進数で入力して[OK]をクリックしてください.

<図5>レジスタ内容の変更
●LEDの発光のようす
写真1および写真2に示すように,GRBレジスタの値を変更することでLEDの明るさが変わることがわかります.数値を大きくすると暗くなり,逆に数値を小さくすると明るくなります.ただし,GRAレジスタの設定値は0x9000ですのでこれ以上の数値は使用できません.
<写真1>GRBを0x2400に設定した時のLEDの発光のようす
(デューティ比D=25%)
(デューティ比D=25%)
<写真2>GRBを0x6C00に設定した時のLEDの発光のようす
(デューティ比D=75%)
(デューティ比D=75%)
●出力波形のようす
オシロスコープで観測したFTIOB1端子の出力波形を写真3および写真4に示します.
<写真4>GRBを0x6C00に設定した時のFTIOB1端子の出力電圧波形(デューティ比D=75%)
■LEDを「ホタルの光」のように変化させるC言語プログラムを作成する
それでは先ほどのプログラムをちょっと応用してみましょう.LEDを「ホタルの光」のように連続的に変化させながら点灯/消灯させるプログラムを作ってみましょう.リスト2にC言語プログラムのソース・リストを示します.
<リスト2>LEDを「ホタルの光」のように変化させるプログラム(led_hotaru.c)のソース・リスト
#include "iodefine.h" // (1) I/Oレジスタ定義ファイル
void main(void)
{
volatile unsigned int i, j;
TZ1.TCR.BIT.TPSC = 2; // (2) 内部クロックφ/4 でカウント
TZ1.TCR.BIT.CCLR = 1; // (3) コンペアマッチAでTCNT_1をクリア
TZ.TPMR.BIT.PWMB1 = 1; // (4) FTIOB1端子はPWMモード
TZ1.GRA = 0x9000; // (5) 周期の設定(T=10ms)
TZ1.GRB = 0x2400; // (6) パルス幅の設定(W=2.5ms)
TZ.TOER.BIT.EB1 = 0; // (7) FTIOB1端子の出力許可
TZ.TSTR.BIT.STR1 = 1; // (8) TCNT_1カウント開始
while(1) { // (9) ループの繰り返し
for ( i = 1; i < 0x8FFF; i++) { // (10) 明→暗へのループ
TZ1.GRB = i; // (11) Highレベル幅の設定(0ms→10ms)
for ( j = 0; j < 20; j++); // (12) ウエイト
}
for ( i = 0x8FFF; i > 1; i--) { // (13) 暗→明へのループ
TZ1.GRB = i; // (14) Highレベル幅の設定(10ms→0ms)
for ( j = 0; j < 20; j++); // (15) ウエイト
}
}
}
●プログラムの概要
リスト2は(9) ~ (15) のプログラムをリスト1に追加しています.(1) から (8) までのプログラムの内容は前項の解説を参照してください.
(9) ループの繰り返し…明→暗,暗→明のループを繰り返し実行します.
(10) 明→暗へのループ…Highレベル幅の設定値を 0→0x8FFFまで変えます.
(11) パルス幅の設定(0ms→10ms)…GRB_1に設定値を代入してHighレベル幅を設定します.
(12) ウエイト…明→暗のループを繰り返す時間を設定します.
(13) 暗→明へのループ…Highレベル幅の設定値を 0x8FFF→1まで変えます.
(14) パルス幅の設定(10ms→0ms)…GRB_1に設定値を代入してHighレベル幅を設定します.
(15) ウエイト…暗→明のループを繰り返す時間を設定します.
それでは,プログラム・リスト2を実行してみましょう.「ホタルの光」のように連続的に明るさが変化しながら点灯/消灯しましたか.
今回はタイマZモジュール機能を使ってLEDの明るさを変化させる簡単なC言語プログラムを作ってみましたが,いかがだったでしょうか.次回はH8マイコン・ボードのプッシュスイッチを押すとLEDが点灯/消灯するプログラムを作ってみましょう.お楽しみに!
< Yoshihito Shimada >


コメントする