今までご紹介してきたプログラムの中では、for (i=0;i<0x0004FFFF;i++) {}といった無意味なループ処理をすることで時間かせぎをしていました。これはこれで使えたのですが、もう少しきちんとした時間を計測することによって、ある程度正確な時間かせぎができると便利です。今回はITU(16ビットインテグレーテッドタイマーユニット)を使って、1mS(1/1000秒)単位で待ち時間が設定できる時間かせぎのプログラムをご紹介します。ITUは何も時間かせぎをするためだけの機能ではなく、色々な機能を持ったタイマーユニットです。先ずは時間かせぎのプログラムを通して、タイマーの基本的な動きを見てみることにしましょう。 1.H8/3052FのITU H8/3052Fマイコンには、ITU(16ビットインテグレーテッドタイマー)という機能が5チャンネル搭載されています。ITUはタイマーを利用した色々な機能が扱えますが、今回はその中でも最も簡単なタイマー機能を使ってみることにします。先ずはタイマー機能の動作について簡単に確認してみましょう。![]() 先ず、タイマー動作をスタートさせると、16ビットのTCNT(タイマーカウンタ)がカウントを開始します。16ビットなので0x0000〜0xFFFF(1〜65535)までカウントできます。このカウンタは、ある基準となるクロック信号に合わせて1つずつカウント値を増やして行きます。つまり、クロック信号の周期(時間)が分かっていれば、カウント値によってカウント開始から何秒経過したかが分かります。ここで、GRA(ゼネラルレジスタA)に、0x0000から0xFFFFの間の任意の値を設定しておくと、TCNTのカウント値がGRAと一致(コンペアマッチ)したときにTSR(タイマーステータスレジスタ)のIMFAというビットが1となり、TCNTが任意の値に達したことを検出することができます。なので、GRAに書き込む値によって、好きなタイマー期間を設定することができるということになります。 今回のプログラムで利用するITU関連のレジスタを以下に整理しましょう。 ■TCR(タイマーコントロールレジスタ) TCRは各ITUの基本的な動作を決定するためのレジスタです。
TPSC2,1,0 では、TCNTの基準となるクロックを選びます。外部から入力するクロックも選べますが、システムクロックを分周(プリスケーラで遅く)して使用する部分だけを抜粋すると、以下のような設定となります。
CKEG1,0では、クロックの立ち上がり、立ち下りの、どのエッジを使ってカウントするかを選びます。
CCLR1,0では、TCNTをクリアするための要因を選びます。
■GRA(ゼネラルレジスタA) GRAは16ビットのレジスタで、今回の使い方では、あらかじめ任意の値を設定しておくことによって、TCNTのカウント値がその設定値と同じになった場合にコンペアマッチとなります。 ■TSTR(タイマースタートレジスタ) TSTRではTCNTのカウントを止めておくか、スタートさせるかを操作します。TSTRは以下のような8ビットのレジスタで、ITU0〜5それぞれに相当するTCNT0〜5のビットを書き換えることによって操作します。ビットを0にするとカウントは停止し、1にするとカウントが開始されます。
■TSR(タイマーステータスレジスタ) TSRは各ITUの状態を返します。
OVF TCNTがカウントアップ動作の時に0xFFFFを超えてオーバーフローするか、カウントダウン動作の時に0x0000以下になりアンダーフロー状態になると、1になります。 IMFB TCNTがGRB(ゼネラルレジスタB)と同じ値になると1になります。 IMFA TCNTがGRA(ゼネラルレジスタA)と同じ値になると1になります。 2.ITU0チャンネルによる時間かせぎ それでは、ITUのタイマー機能を使って正確な時間かせぎを行うプログラムの事例を見てみましょう。今回はITUの0チャンネルを使って機能を実装します。このプログラムはHEW4の環境でビルドできます。なお、今回作成した関数は汎用的に利用するため、myfunc.hというヘッダファイルに収めました。プロジェクトのフォルダにコピーして、HEW4のメニューバーから「プロジェクト」→「ファイルの追加」でプロジェクトに追加してください。 【ダウンロード】 timer_test.c 右クリックで「対象をファイルに保存」 【ダウンロード】 myfunc.h 右クリックで「対象をファイルに保存」
それでは、プログラムの中身について見てみましょう。 実は上記のtimer_test.cは、「H8/3052F PIO出力」のページでご紹介したプログラムpio_test1.cと一部を除いて全く同じです。どこが違うかというと、青文字の部分が変更または追加されているところです。できれば両者を見比べてみてください。ここでは、青文字の部分だけを簡単にご説明しましょう。 #include "myfunc.h" では、myfunc.hというヘッダファイルを読み込んでいます。myfunc.hはTekuRoboで作っていく関数のうち、他のプログラムでも汎用的に使えるものを集めて収めていこうと思うヘッダファイルです。汎用的に使える関数については特定動作のプログラムではなく、ヘッダファイルという形にまとめておくことによって他のプログラムでも使いやすくなります。また、ヘッダファイルの中に様々な汎用的な機能の関数が増えていくと、それは今後の財産となります。今後少しずつですが、育てて行ければ良いですね。 itu0_wait_init(); は、時間かせぎを行うためのITU0チャンネルの初期化を行う関数です。この関数は、この後ご紹介するヘッダファイルmyfunc.hに記述してあります。 itu0_wait(1000); は、実際に時間かせぎを行うための関数で、これもヘッダファイルmyfunc.hに記述してあります。引数として渡している「1000」は時間かせぎを行いたい待機時間をmS(1/1000秒)単位で指定するもので、今回は1000mS(1秒)の時間かせぎをさせるように設定しているということになります。
次に、ヘッダファイルmyfunc.hの中身について見てみましょう。 ■itu0_wait_init( )関数 timer_test.cで使用している時間かせぎのitu0_wait( )関数を実行する前に、この関数を一度実行させてITU0チャンネルを初期化させます。ここでは3つのレジスタについて操作しています。 先ず、TCR(タイマーコントロールレジスタ)です。ここでは内部クロックをφ/8、クロックのエッジの立ち上がりでカウント、TCNT(タイマーカウンタ)のクリア要因をGRA値のコンペアマッチ、と設定します。したがって、TCRの値は以下の通り0x23とします。
次にGRA(ゼネラルレジスタA)です。ここでは、TCNT(タイマーカウンタ)がカウントを開始して、ちょうど1mS経過した時の値を指定します。今回のシステムクロックは25MHzで、カウンタ用のクロックはφ/8に設定したので、25MHz/8 = 3.125MHzがカウンタ用のクロック周波数になります。この周波数の周期は1/3.125MHz = 0.32uS なので、1mSの間に必要なカウント数は 1mS/0.32uS = 3125回になります。 これを16進数で表記すると 0x0C35 になります。 最後にTSTR(タイマースタートレジスタ)です。今回はITUの0チャンネルを利用するので、TSTRのITU0チャンネルに相当するビットだけを操作します。今回は初期化によって明示的にカウントを停止させるため、ITU.TSTR.BIT.STR0 = 0; としています。 ■itu0_wait( )関数 これが実際に時間かせぎを行う関数で、引数として int msec を受け取ります。先ず、ITU.TSTR.BIT.STR0 = 1; によってTCNTのカウントを開始させます。次にfor(i=0;i<msec;i++){ } によって、{ } の中の処理を引数で受け取ったmsec回だけ実行します。{ } の中では do{ }while(ITU0.TSR.BIT.IMFA == 0); によって、GRAのコンペアマッチが検出されるまで待ちます。先ほどTCNTのカウントを開始したばかりだったので、GRAのコンペアマッチが検出されるまでにはちょうど1mSが経過しているはずです。コンペアマッチが検出されたら ITU0.TSR.BIT.IMFA = 0; により、コンペアマッチを検出したというフラグをクリアします。以上の処理を、msec回だけ繰り返して、必要な期間だけ時間かせぎを行うという仕組みです。時間かせぎが終わったら、最後に ITU.TSTR.BIT.STR0 = 0; によってTCNTのカウントを停止させて、時間かせぎ処理を終了します。 3.timer_test.C の実行
今回は、H8/3052Fのタイマー機能を使って、時間かせぎ関数を作ってみました。時間かせぎ関数は色々なプログラムで役に立つと思いますが、マイコンでのタイマーの動きを理解するのにも絶好の教材になるかと思います。ITU機能としては、更に色々な機能がありますので、追々ご紹介致します。また、今回のポイントとしては、ヘッダファイルに汎用的な関数をまとめるという手法もありました。関数を作る上では、なくべく汎用的に使えるように引数や戻り値などを考えてあげる必要があります。一度作った関数を今後作るプログラムに役立てることによって、開発がより楽になっていきます。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||