職業訓練43日目 H8マイコン入門(アセンブラ言語による実習)
LEDの制御
LEDの点滅
LEDを点滅させるにはタイマプログラムを作る必要があり、
タイマには2つの実現方法がある。
- 繰り返し処理で時間をかせぐ
- 内蔵タイマ(ITU)を利用する
まずは1.の繰り返し処理を利用したコードから。
下記のコードを実行すると、5秒経過するたびにLEDの点灯がローテイトするはず。
.CPU 300HA .SECTION PROG4, CODE, LOCATE=H'000000 P1DR .EQU H'FFFFC2 P1DDR .EQU H'FFFFC0 .SECTION ROM, CODE, LOCATE=H'000100 MOV.L #H'FFFF00, ER7 MOV.B #H'FF, R0L MOV.B R0L, @P1DDR ; ポート1を出力に設定 MOV.B #'01111111, R0L ; LED点灯データ LOOP: MOV.B R0L, @P1DR ; ポート1へ点灯データを出力 JSR @TIM2 ; タイマサブルーチンの呼び出し ROTR.B R0L ; 右に1ビットローテイト JMP @LOOP TIM2: MOV.W #D'500, E5 ; 5秒のタイマサブルーチン L2: JSR @TIM1 DEC.W #1, E5 BNE L2 RTS TIM1: MOV.L #D'20000, ER6 ; 10msのタイマサブルーチン L1: DEC.L #1, ER6 ; ER6から1を引く NOP ; 何もしない、時間稼ぎ BNE L1 ; ER6≠0ならL1にジャンプ RTS .END
細かい計算はというと、
H8命令セットから、各処理のステート数を調べて、
どれぐらいの時間がかかっているのか算出する。
基準となる1ステート(クロック)の時間は、
CPUの動作周波数が16MHzなので、
1ステート = 0.0625μs
(1s/16000000Hz=0.0000000625s=0.0000625ms=0.0625μs)となる。
各処理のステート数は以下の通り。
ニーモニック | ステート数 |
---|---|
DEC.L | 2 |
NOP | 2 |
BNE | 4 |
つまり、サブルーチンL1の中では、
0.0625μs * 8ステート = 0.5μs かかっているので、
それを20000回繰り返すことによって、
10msのサブルーチン(TIM1)が作られている。
(0.5μs * 20000 = 10000μs = 10ms)
10msのサブルーチン(TIM1)を500回繰り返して、
5秒ずつ点滅する処理の出来上がり、というわけですね。
では、続きまして「2. 内蔵タイマ(ITU)を利用する」バージョンを。
インテグレーテッドタイマの使用
ITU(Integrated Timer Unit):5チャネル16ビットのタイマ機能
ITU内のカウンタ(TCNT)は、0000H〜FFFFHまでカウントアップした後、
0000Hに戻ってカウントを始める。
FFFFHまでカウントするのにどれくらいかかるかというと、
1クロック = 0.0625μsなので、
0.0625μs * FFFFH =
0.0625μs * 65535 = 4095μs ≒ 約4ms で数え終わる計算になります。
4msでは早過ぎる場合は、クロック周波数を低くするプリスケーラ機能(分周機能)を利用する。
この機能を使えば、周波数を1/2、1/4、1/8に分周して、カウント時間を延ばすことが可能。
1/8に分周したとすると、FFFFHまでカウントするのに、
4ms * 8 = 32ms かかることになる。
プリスケーラの設定含め、ITUの具体的な設定方法は以下を参照。
(タイトルに思いっきり3052Fと書いてありますが…)
http://homepage1.nifty.com/rikiya/program/h83052f_itu1/h83052f_itu1.html
ITUを利用してLEDを点滅させるプログラムはコチラ。
.CPU 300HA .SECTION PROG5, CODE, LOCATE=H'000000 P1DR .EQU H'FFFFC2 P1DDR .EQU H'FFFFC0 TSTR .EQU H'FFFF60 ; タイマスタートレジスタ TCR0 .EQU H'FFFF64 ; タイマコントロールレジスタ0 TSR0 .EQU H'FFFF67 ; タイマステータスレジスタ0 .SECTION ROM, CODE, LOCATE=H'000100 MOV.L #H'FFFF00, ER7 MOV.B #H'FF, R0L MOV.B R0L, @P1DDR ; ポート1を出力に設定 MOV.B #H'03, R0H ; 1/8分周データ MOV.B R0H, @TCR0 ; プリスケーラ設定 MOV.B #'11111110, R0L ; LED点灯データ BSET #0, @TSTR ; ITUカウントスタート L1: MOV.B R0L, @P1DR L2: BTST #2, @TSR0 ; オーバーフローフラグのチェック BEQ L2 ; フラグが"0"の場合、L2へジャンプ ROTL.B R0L BCLR #2, @TSR0 ; オーバーフローフラグのクリア JMP @L1 .END
カウンタのスタート後に、
タイマステータスレジスタ(TSR0)の2ビット目(オーバーフローフラグ:OVF)をチェックして、
OVFが"0"の場合、チェックを続ける(BEQ L2)。
OVFが"1"になったら、LED点灯データを左にローテートし、
オーバーフローフラグを"0"にリセットし、点灯データを出力する。
実行すると、32msごとにLEDの点灯がローテートするはず。