PIC16F84のタイマー0を使った割り込みプログラム
割り込み手続きを詳細に設定しなくてもできるよう、アセンブラの割り込み用のひな形を作成。
H8でわかりやすくまとめられている テクロボ工作室では
PICについても とてもわかりやすい解説があります。
PICタイマーの説明やそれを使った方法はテクロボ工作室での
313.タイマー0を使う
で解説されていますので、そちらを最初に参考にさせてもらいましょう。
このように使えるタイマー0ですが、ひな形とするために追加部分を付け加え、一応の設定でタイマー処理しやすいように付け加え、ひな形にしてみました。
もとは 師匠ページであるテクロボ工作室の公開プログラムを基に変更をしてみたものなので、あらかじめ本家ページを見て参考にしてください
レジスタ値の保護
おもに、割り込み処理での各レジスタ退避を付け加えました。
これ無しに割り込み処理をやると、割り込み処理によっては、処理後にレジスタ部分が書き換えられていて 復帰後の処理が正常にならないことが起こるので付け加えました。
ひな形プログラム内容
ソースファイル主要部 (tm0Test_FMTLED.asm)
;***********************************************************************
;割り込み処理
;***********************************************************************
INTR
;--割り込み中でしたい処理 記述 始-----------------------------------------------
INCF CNT1,F ;変数CNT1に+1する。
MOVF CNT1,W ;WレジスタにCNT1の値をセット
MOVLW D'100'
MOVWF DATA1 ;CNT1=100
;[ if _DATA1 = CNT1 then goto Xxx ]
movf CNT1,W
xorwf DATA1,W
btfsc STATUS,Z
GOTO EQUAL
GOTO NOT_EQUAL
EQUAL
MOVLW B'00000001' ;WレジスタにCNT1の値をセット
MOVWF PORTB ;PORTBへCNT1の値を出力
CLRF CNT1
GOTO IF_E
NOT_EQUAL
MOVLW B'00000000' ;WレジスタにCNT1の値をセット
MOVWF PORTB ;PORTBへCNT1の値を出力
IF_E
;--割り込み中でしたい処理 記述 終---------------------------------------------
BCF INTCON,T0IF ;オーバーフローフラグのクリア
BSF INTCON,T0IE ;割り込み許可フラグのセット
MOVLW 00H ;Wレジスタに00Hをセット
MOVWF TMR0 ;TMR0にカウント初期値00Hを再セット
;-------------------------------; 割り込み'後'処理-----------
;退避させたレジスタを戻す
SWAPF STATUS_TEMP,w ;STATUを戻す
MOVWF STATUS
SWAPF W_TEMP,f ;Wを戻す
SWAPF W_TEMP,w ;SWAPを使いSTATUSを変化させいないため
;--------------------------------------
RETFIE ;割り込みを許可してリターン
END
データを保存しておくべき各レジスタとして、W、STATUSレジスタを退避させ、保護します。
これらのレジスタは、割り込み処理でも使用されることが多く、書き換えられると、割り込みから復帰した後にもそのデータがレジスタに残ります。
(いろんな用途に使用されるレジスタですが、最低限このレジスタ値を保護しする必要はあるでしょう)
そして割り込み復帰直前に書き戻します。
今回は考えていませんが、退避変数の場所もバンク0,1のどちらからでもアクセスできる場所にしておく必要があります。
各レジスタ用の退避変数を作り、
割り込み直前で
レジスタ値を退避変数 W_TEMP、STATUS_TEMP に
;-----------------------------; 割り込み'前'処理-------
MOVWF W_TEMP ;W退避
SWAPF STATUS,W ;STATUS退避
CLRF STATUS ;バンク0へ MOVWF STATUS_TEMP ;STATUS退避
;-------------------------------------------------------
として退避
割り込み直後に
;-------------------------------; 割り込み'後'処理----------- ;
退避させたレジスタを戻す
SWAPF STATUS_TEMP,w ;STATUを戻す
MOVWF STATUS SWAPF W_TEMP,f ;Wを戻す
SWAPF W_TEMP,w ;SWAPを使いSTATUSを変化させいないため
;--------------------------------------
RETFIE ;割り込みを許可してリターン
このように退避変数 からレジスタへ書き戻す。
(復帰にswapf命令を使うのはZフラグが変化しないようにするため)
処理をしています。この処理を割り込み直前、直後にすることで、復帰しても割り込みがかかる前とレジスタ値が変わらず、 割り込みの影響をうけません。
割り込み復帰後にこれらレジスタの状態が変わっていたのでは、不都合が起こるので、計算などに使用されるそれらしきレジスタは 保護しておきます。
割り込みひな形を使ったサンプルプログラム
作ったひな形を使って、タイマー0の割り込みのLED点滅プログラムを実行してみます。
16F84Aのタイマー0の設定は テクロボ工作室 で説明されています。
この割り込みに関する数値を変更するだけで割り込みが設定できるので、試しに改良するとひな形としても使えるでしょう。
タイマー割り込みでLEDを点滅させるプログラムです。
RB0につないだLEDを割り込み時間でカウントして点滅させてみます。
(回路や、ポート名 RB0などは
テストプログラム作成 を参照してください )
やることは、上のタイマー0のひな形プログラム内で
;--割り込み中でしたい処理 記述 始--------------------------------------- ;
;割り込み処理記述 ;
;--割り込み中でしたい処理 記述 終-----------------------------------------
この部分に割り込みでしたい処理を記述します。
その割り込み処理で必要な
使用する変数や、ポートの初期設定を付け加える必要はあります。
サンプルプログラム
;**********************************************************************
; PORTB-#0につないだLEDを
; 割り込み100回目にLED-ON
;**********************************************************************
list p=16F84A
#include
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
;**********************************************************************
CBLOCK H'0C'
W_TEMP ;W退避変数
STATUS_TEMP ;STATUS退避変数
;
CNT1
DATA1
ENDC
;----------------
ORG 0 ;リセット時の開始アドレスセット
GOTO MAIN ;メインルーチンMAINにジャンプ
ORG 4 ;割り込みアドレスセット
;-----------------------------; 割り込み'前'処理-------
MOVWF W_TEMP ;W退避
SWAPF STATUS,W ;STATUS退避
CLRF STATUS ;バンク0へ
MOVWF STATUS_TEMP ;STATUS退避
;-------------------------------------------------------
GOTO INTR ;割り込みルーチンINTRにジャンプ
MAIN BSF STATUS,RP0 ;メモリーバンクを1にセット
MOVLW 087H ;Wレジスタに87Hをセット
MOVWF OPTION_REG ;TMR0 プリスケーラ256
CLRF TRISB ;TRISBをクリア PORT-Bを出力にセット
CLRF TRISA
BCF STATUS,RP0 ;メモリーバンクを0にセット
CLRF CNT1 ;CNT1変数を00Hにクリア
MOVLW 00H ;Wレジスタに00Hをセット
MOVWF TMR0 ;TMR0にカウンタ初期値00Hをセット
BSF INTCON,T0IE ;TMR0割り込み許可
BSF INTCON,GIE ;全体割り込みの許可
;***********************************************************************
;割り込みを待つループ
;***********************************************************************
LOOP
NOP ;何もしない
GOTO LOOP ;ラベルLOOPにジャンプ
;***********************************************************************
;割り込み処理
;***********************************************************************
INTR
;--割り込み中でしたい処理 記述 始-----------------------------------------------
INCF CNT1,F ;変数CNT1に+1する。
MOVF CNT1,W ;WレジスタにCNT1の値をセット
MOVLW D'100'
MOVWF DATA1 ;CNT1=100
;[ if _DATA1 = CNT1 then goto Xxx ]
movf CNT1,W
xorwf DATA1,W
btfsc STATUS,Z
GOTO EQUAL
GOTO NOT_EQUAL
EQUAL
MOVLW B'00000001' ;WレジスタにCNT1の値をセット
MOVWF PORTB ;PORTBへCNT1の値を出力
CLRF CNT1
GOTO IF_E
NOT_EQUAL
MOVLW B'00000000' ;WレジスタにCNT1の値をセット
MOVWF PORTB ;PORTBへCNT1の値を出力
IF_E
;--割り込み中でしたい処理 記述 終---------------------------------------------
BCF INTCON,T0IF ;オーバーフローフラグのクリア
BSF INTCON,T0IE ;割り込み許可フラグのセット
MOVLW 00H ;Wレジスタに00Hをセット
MOVWF TMR0 ;TMR0にカウント初期値00Hを再セット
;-------------------------------; 割り込み'後'処理-----------
;退避させたレジスタを戻す
SWAPF STATUS_TEMP,w ;STATUを戻す
MOVWF STATUS
SWAPF W_TEMP,f ;Wを戻す
SWAPF W_TEMP,w ;SWAPを使いSTATUSを変化させいないため
;--------------------------------------
RETFIE ;割り込みを許可してリターン
END
割り込み処理
設定時間毎に割り込み処理がされ、
割り込み間隔時間は リンクの 313.タイマー0を使う 内での設定説明の通り
オーバーフロー割り込みをしています。( カウンタがいっぱいになったとき割り込み発生)
引用) システムクロックが20MHzの場合、TMR0を使ったタイマー動作では、51.2μS x 255カウント = 13.056mS
が計測できる最長時間ということになります。
この間隔で割り込み処理が毎回実行されます。
さらに、割り込み処理内で
INCF CNT1,F ;変数CNT1に+1する。
CNT1で割り込み回数をカウントします。
CNT1が100(100回目)になると
MOVLW B'00000001' ;WレジスタにCNT1の値をセット
MOVWF PORTB ;PORTBへCNT1の値を出力
CLRF CNT1
RB0から出力し、LEDを点灯させます。
そして、100をカウントしたCNT1は0にクリアします。
(if処理はひな形を使ったので、gotoを2度使いまどろっこしい処理になっていますが IF CNT1 =? 100 のIF分岐です)
つまり、
100回の割り込みで1回だけLEDを点灯。
タイマー割り込み間隔の100倍の時間ごとに1度だけLEDを点灯させています。
実行結果
RB0につないだLEDが、周期的に一瞬、ピカッ ときれのある点滅を繰り返します。
点灯時間が短いのでキレのある点滅になっています。
この点滅時間は、タイマー0設定の設定だけでなく、PICにつなぐクロックによって変わってきます。
関連詳細メモ
割り込み直前で
W、STATUSレジスタを退避させ、保護します。
直後で
W、STATUSレジスタを書き戻し、元処理に影響がでないようにする。
(割り込み処理の内容によっては、それ以外に、FSR、、PCLATHレジスタ なども退避させる必要がでます)
- twtter
- google+
- hatena