目次
前
次
タイマー割込み処理
タイマーがどのような構成になっているのかは
ブロック図で説明されています。
システムクロックを分周したクロックをカウンタに入れるか
T1ピンからのトリガーを入れるかを選択できます。
どちらのクロックを選択するのかは、命令で指定できます。
システムクロックの分周クロック -> STRT T
T1ピンからのトリガー -> STRT CNT
停止するときには、「STOP TCNT」を利用。
「STRT T」を利用すると、接続は次のようになります。
クロックを6MHzとすると、タイマー用カウンタには
12.5kHzのクロックが与えられます。
「STRT CNT」を利用すると、接続は次のようになります。
タイマーかイベントの割込みは、イベントフラグとして
セットされて通知されます。イベントフラグのセットは
$FFから$00に変化するときで、オーバーフローでセット
というカラクリです。
指定値でのオーバーフローを発生させるためには
タイマー用カウンタに初期値を設定します。
250カウントでオーバーフローさせるためには
タイマー用カウンタに、初期値として6を設定。
この初期化には、2通りのコードを用意できます。
初期値は、256-250=6なので、そのままカウンタTに
設定するときは、以下。
stop tcnt
mov a,#6
mov t,a
strt t
2の補数を求めて設定する方法もあります。
stop tcnt
mov a,#250
cpl a
inc a
mov t,a
strt t
ポートに接続したLEDを、タイマー割込みを使って
点滅させるプログラムを書いてみます。
タイマー割込みで、周期的にフラグをセットします。
そのフラグをイベント通知フラグとして利用。
イベント通知フラグを監視し、セットされたなら
LEDを点灯か消灯かを決定していきます。
メインとなる処理は、次のように構成。
MAIN:
; get flag
mov a,@r0
; judge
anl a,#1
jz MAINL
; clear flag
mov @r0,#0
; impress
xch a,@r1
anl a,#1
outl P1,a
; update
inc @r1
;
MAINL:
;
jmp MAIN
イベント通知フラグがセットされているかを
常に見ています。
イベント通知フラグがセットされているなら
カウンタ値をリードして、LSBの値をLEDへ
転送。
イベント通知フラグがセットされていたなら
クリアします。また、LEDに情報を転送後に
カウンタを+1しておきます。
イベント通知フラグがセットされていることを
アキュムレータの内容がゼロか否かに置換して
判定。
イベント通知フラグ、カウンタはメモリ上の
1バイトに格納。メモリ上の値をアクセスに
汎用レジスタr0、r1をポインタとして使います。
最上位の動作を定義したので、I/Oの初期化
タイマー初期化等のサブルーチンを作成して
いきます。
I/O初期化
サブルーチン内では、次の項目を設定。
- 外部割込み禁止
- タイマー割込み禁止
- ポート1、2の初期化
- 2つのポインタ設定
- イベント通知フラグをクリア
- カウンタをクリア
リストにそって、1命令ずつアセンブリ
言語コードに置換していきます。
INIT:
; disable external interrupt
dis i
; disable timer interrupt
dis tcnti
; initialize I/O
mov a,#0
outl p1,a
outl p2,a
; set pointer
mov r0,#TFLAG
mov r1,#MCNT
; clear flag
mov @r0,#0
; clear counter
mov @r1,#0
;
ret
ポインタが参照するアドレスは、擬似命令を
利用して定義しておきます。
TFLAG equ 18h
MCNT equ 19h
$00から$1Fは、汎用レジスタとスタックに割付け
されているので$20から$3Fの間にあるアドレスを
使います。
タイマー初期化
与えるクロックを止めて、カウンタに
初期値を設定後、クロック供給を再開
していきます。
言葉で表現すると、複雑に思えますが
アセンブリ言語コードは単純。
INIT_TIM:
; stop counter
stop tcnt
; initialize
mov a,#TZERO
mov t,a
; start timer
strt t
;
ret
タイマー割込みハンドラ
ハンドラは、特定事象が発生したときに
動かすプログラムという意味で使います。
割込みが発生したときの処理は、極力
少なくしておかないと、他の処理へと
影響するので、2つの動作だけに限定
しました。
イベント通知フラグ設定
タイマーカウンタ初期化
タイマーカウンタ初期化は、他のサブルーチンが
担当していますが、スタックサイズが8バイトと
いうので、割込みハンドラからサブルーチンコール
をしないで済ませます。
定義した割込みハンドラは、以下。
E_TIMX:
; clear flag
jtf E_TIMX0
; exit
jmp E_TIMXE
E_TIMX0:
; stop counter
stop tcnt
; set flag
mov @r0,#1
; initialize
mov a,#TZERO
mov t,a
; start timer
strt t
E_TIMXE:
;
retr
割込みハンドラでは、リターン命令に
retrを使うことに注意します。
割込みは、ハードウエアで実現するサブ
ルーチンと考えれば、ソフトウエアとは
異なるリターン命令を採用するのは当然
と思えます。
割込み利用には、割込みの許可をしないと
いけないので、メインループに入る前には
発行しておきます。
まとめると、以下。
;
; TEST program for 8048 ( PROASM-II )
; Copyright (C) 2017 Kensuke Ooyu
;
INCLUDE 8048.LIB
;*******************
; value and address
;*******************
TZERO equ 6
TFLAG equ 18h
MCNT equ 19h
;****************
; define symbols
;****************
ENTRY equ 0h
E_INT equ 3h
E_TIM equ 7h
;*******************
; interrupt vectors
;*******************
org ENTRY
jmp START
; external interrupt
org E_INT
retr
; timer interrupt
org E_TIM
jmp E_TIMX
org 10h
;**************
; sub routines
;**************
INIT:
; disable external interrupt
dis i
; disable timer interrupt
dis tcnti
; initialize I/O
mov a,#0
outl p1,a
outl p2,a
; set pointer
mov r0,#TFLAG
mov r1,#MCNT
; clear flag
mov @r0,#0
; clear counter
mov @r1,#0
;
ret
INIT_TIM:
; stop counter
stop tcnt
; initialize
mov a,#TZERO
mov t,a
; start timer
strt t
;
ret
E_TIMX:
; clear flag
jtf E_TIMX0
; exit
jmp E_TIMXE
E_TIMX0:
; stop counter
stop tcnt
; set flag
mov @r0,#1
; initialize
mov a,#TZERO
mov t,a
; start timer
strt t
E_TIMXE:
;
retr
;**************
; main routine
;**************
org 100h
START:
call INIT
call INIT_TIM
; enable
en TCNTI
MAIN:
; get flag
mov a,@r0
; judge
anl a,#1
jz MAINL
; clear flag
mov @r0,#0
; impress
xch a,@r1
anl a,#1
outl P1,a
; update
inc @r1
;
MAINL:
;
jmp MAIN
end
アセンブリ言語コードが、どんな機械語に
変換されているのかを見てみます。
0000 ;
0000 ; TEST program for 8048 ( PROASM-II )
0000 ; Copyright (C) 2017 Kensuke Ooyu
0000 ;
0000 INCLUDE 8048.LIB
0000 list
0000
0000 ;*******************
0000 ; value and address
0000 ;*******************
0006 TZERO equ 6
0018 TFLAG equ 18h
0019 MCNT equ 19h
0000
0000 ;****************
0000 ; define symbols
0000 ;****************
0000 ENTRY equ 0h
0003 E_INT equ 3h
0007 E_TIM equ 7h
0000
0000 ;*******************
0000 ; interrupt vectors
0000 ;*******************
0000 org ENTRY
0000 2400 + jmp START
0002
0002 ; external interrupt
0002 org E_INT
0003 93 + retr
0004
0004 ; timer interrupt
0004 org E_TIM
0007 0425 + jmp E_TIMX
0009
0009 org 10h
0010 ;**************
0010 ; sub routines
0010 ;**************
0010 INIT:
0010 ; disable external interrupt
0010 15 + dis i
0011 ; disable timer interrupt
0011 35 + dis tcnti
0012 ; initialize I/O
0012 2300 + mov a,#0
0014 39 + outl p1,a
0015 3A + outl p2,a
0016 ; set pointer
0016 B818 + mov r0,#TFLAG
0018 B919 + mov r1,#MCNT
001A ; clear flag
001A B000 + mov @r0,#0
001C ; clear counter
001C B100 + mov @r1,#0
001E ;
001E 83 + ret
001F
001F INIT_TIM:
001F ; stop counter
001F 65 + stop tcnt
0020 ; initialize
0020 2306 + mov a,#TZERO
0022 62 + mov t,a
0023 ; start timer
0023 55 + strt t
0024 ;
0024 83 + ret
0025
0025 E_TIMX:
0025 ; clear flag
0025 1629 + jtf E_TIMX0
0027 ; exit
0027 0430 + jmp E_TIMXE
0029 E_TIMX0:
0029 ; stop counter
0029 65 + stop tcnt
002A ; set flag
002A B001 + mov @r0,#1
002C ; initialize
002C 2306 + mov a,#TZERO
002E 62 + mov t,a
002F ; start timer
002F 55 + strt t
0030 E_TIMXE:
0030 ;
0030 93 + retr
0031
0031 ;**************
0031 ; main routine
0031 ;**************
0031 org 100h
0100 START:
0100 1410 + call INIT
0102 141F + call INIT_TIM
0104 ; enable
0104 25 + en TCNTI
0105 MAIN:
0105 ; get flag
0105 F0 + mov a,@r0
0106 ; judge
0106 5301 + anl a,#1
0108 C611 + jz MAINL
010A ; clear flag
010A B000 + mov @r0,#0
010C ; impress
010C 21 + xch a,@r1
010D 5301 + anl a,#1
010F 39 + outl P1,a
0110 ; update
0110 11 + inc @r1
0111 ;
0111 MAINL:
0111 ;
0111 2405 + jmp MAIN
0113
0113 end
割込みハンドラであっても、通常のサブルーチンと
同じように1バイト、2バイトの命令に変換されて
いるのがわかります。また、リターン命令が異なる
のが見て取れます。
HEXファイルの内容は、以下。
:020000002400DA
:010003009369
:020007000425CE
:1000100015352300393AB818B919B000B100836515
:1000200023066255831629043065B0012306625504
:01003000933C
:100100001410141F25F05301C611B00021530139FA
:03011000112405B2
:00000001FF
改良の余地がないのかを、考えてみました。
アキュムレータの該当ビットが1になっていれば
分岐できるjbx(jb0,jb1,..jb7)命令を利用すると
判定処理の前のマスク処理を減らせます。
MAINの中は、次のように書換えできます。
MAIN:
; get flag
mov a,@r0
; judge
jb0 MAIN1
; exit
jmp MAINE
MAIN1:
; clear flag
mov @r0,#0
; impress
xch a,@r1
anl a,#1
outl P1,a
; update
inc @r1
;
MAINE:
jmp MAIN
目次
前
次