職業訓練46日目 H8マイコン入門(アセンブラ言語による実習)

割込み制御

割込み

実行中の処理を一時停止して、他の処理を行った後に最下位する機能。

●割込み動作の流れ

  1. PCとCCRをスタックに待避(必要であれば、汎用レジスタのデータもスタックに待避)
  2. CCRの割込みマスクビットに"1"をセット(他の割込みを禁止する)
  3. メモリの割込みベクタアドレスから、割込みプログラムの開始アドレスをPCに読み込む
  4. 割込みプログラムを実行
  5. RTE命令で割込みプログラムから復帰する
  6. 待避していたPCとCCRを復元して、元の処理を再開する
IRQ端子を使った割込み

IRQ0〜5端子に"0"を入力することで、割込みが発生する。
→使用するピンによって6種類の割込みプログラムを選択できる。

IRQネーブルレジスタ(IER):端子別に許可/禁止の設定
IRQセンスコントロールレジスタ(ISCR):割込み信号の有効な動作タイミングを設定

実際に製作した回路は、
プッシュSWからシュミットトリガゲート(74LS19)を介して、
IRQ0端子に信号を入力する。

	.CPU 300HA
	.SECTION PROG13, CODE, LOCATE=H'000000

	.DATA.L	MAIN			; メイン処理は、000000番地から
	.ORG	H'000030		; IRQ0の割込みベクタアドレス
	.DATA.L	IRQ0			; 割込みプログラムの開始アドレス

IER	.EQU	H'FFFFF5		; IRQイネーブルレジスタ
ISCR	.EQU	H'FFFFF4		; IRQセンスコントロールレジスタ
P1DR	.EQU	H'FFFFC2
P1DDR	.EQU	H'FFFFC0
P5DR	.EQU	H'FFFFC8
P5DDR	.EQU	H'FFFFCA

	.SECTION ROM, CODE, LOCATE=H'000100

MAIN:	MOV.L	#H'FFF00, ER7

	MOV.B	#H'FF, R0L
	MOV.B	R0L, @P1DDR
	MOV.B	R0L, @P5DDR

	BSET	#0, @IER		; IRQ0の割込みを許可
	BSET	#0, @ISCR		; 割込みパルスの立下がりエッジで割込みを行う
	LDC	#0, CCR			; 割込み許可

	MOV.B	#B'01111111, R0L	; LED点灯データ(ポート1)
LOOP:	MOV.B	R0L, @P1DR
	JSR	@TIM2
	ROTR.B	R0L
	JMP	@LOOP

;----- 割込み処理 -----
IRQ0:	PUSH.W	R0			; レジスタの待避
	PUSH.L	ER5
	PUSH.L	ER6
	MOV.B	#D'3, R0H		; LED点灯回数データ
YET:	MOV.B	#H'FF, R0L		; LED点灯データ(ポート5)
	JSR	@TIM2
	MOV.B	#H'00, R0L
	MOV.B	R0L, @P5DR
	JSR	@TIM2
	DEC.B	R0H			; 点灯回数 - 1
	BNE	YET			; 点灯回数が0でなければ、YETへ
	POP.L	ER6			; レジスタの回復
	POP.L	ER5
	POP.W	R0
	RTE				; 割込みから復旧
;----------------------

TIM2:	MOV.W	#D'50, E5		; 0.5秒のタイマサブルーチン
L2:	JSR	@TIM1
	DEC.W	#1, E5
	BNE	L2
	RTS

TIM1:	MOV.L	#D'20000, ER6		; 10msのタイマサブルーチン
L1:	DEC.L	#1, ER6
	NOP
	BNE	L1
	RTS

	.END

上記のプログラムを実行すると、
0.5秒ごとにポート1の点灯するLEDが1個ずつ移動していき、
プッシュSWが押されると、ポート1のLEDが停止し、ポート5のLEDが3回点滅、
その後、またポート1のLEDが移動し始めるはず。

NMI端子を使った割込み

NMIとは、マスク(禁止)できない「ノンマスカブル割込み」のこと。
CCRの割込みマスクビットを"0"にしても禁止できない、優先度の高い割込み。
NMI端子の入力エッジは、システムコントロールレジスタ(SYSCR)で設定。

製作した回路は、上記のIRQ端子を使った回路と一緒で、
割込み信号を入力する端子がNMI端子になっただけ。

	.CPU 300HA
	.SECTION PROG14, CODE, LOCATE=H'000000

	.DATA.L	MAIN			; メイン処理は、000000番地から
	.ORG	H'00001C		; NMIの割込みベクタアドレス
	.DATA.L	IRQ0			; 割込みプログラムの開始アドレス

SYSCR	.EQU	H'FFFFF2		; システムコントロールレジスタ
P1DR	.EQU	H'FFFFC2
P1DDR	.EQU	H'FFFFC0
P5DR	.EQU	H'FFFFC8
P5DDR	.EQU	H'FFFFCA

	.SECTION ROM, CODE, LOCATE=H'000100

MAIN:	MOV.L	#H'FFF00, ER7

	MOV.B	#H'FF, R0L
	MOV.B	R0L, @P1DDR
	MOV.B	R0L, @P5DDR

	BCLR	#2, @SYSCR		; 割込みパルスの立下がりエッジで割込みを行う

	MOV.B	#B'11111110, R0L	; LED点灯データ(ポート1)
LOOP:	MOV.B	R0L, @P1DR
	JSR	@TIM2
	ROTL.B	R0L			; IRQ端子のプログラムとは逆の向き
	JMP	@LOOP

;----- 割込み処理 -----
IRQ0:	PUSH.W	R0			; レジスタの待避
	PUSH.L	ER5
	PUSH.L	ER6
	MOV.B	#D'3, R0H		; LED点灯回数データ
YET:	MOV.B	#H'FF, R0L		; LED点灯データ(ポート5)
	JSR	@TIM2
	MOV.B	#H'00, R0L
	MOV.B	R0L, @P5DR
	JSR	@TIM2
	DEC.B	R0H			; 点灯回数 - 1
	BNE	YET			; 点灯回数が0でなければ、YETへ
	POP.L	ER6			; レジスタの回復
	POP.L	ER5
	POP.W	R0
	RTE				; 割込みから復旧
;----------------------

TIM2:	MOV.W	#D'50, E5		; 0.5秒のタイマサブルーチン
L2:	JSR	@TIM1
	DEC.W	#1, E5
	BNE	L2
	RTS

TIM1:	MOV.L	#D'20000, ER6		; 10msのタイマサブルーチン
L1:	DEC.L	#1, ER6
	NOP
	BNE	L1
	RTS

	.END

IRQ端子の例とやってることは一緒ですね。