職業訓練46日目 H8マイコン入門(アセンブラ言語による実習)
割込み制御
割込み
実行中の処理を一時停止して、他の処理を行った後に最下位する機能。
●割込み動作の流れ
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端子の例とやってることは一緒ですね。