MPLAB IDE v8.92 MPASM v5.51 PICKit3の環境で、PIC16F648Aのタイマー割り込みの使い方を勉強します。
PIC16F648Aは、8bitタイマーを2個(TMR0とTMR2)と16bitタイマー1個(TMR1)持っています。今回は、TMR2を使ってなるべく正確な1秒を発生させて、LEDを点滅させてみます。
正確性を上げるためには、外部のクリスタルオシレータからクロックを供給します。今回は20MHzのクリスタルオシレータ(SG-8002)を使い、TMR2のオーバーフロー割り込みを利用して1秒を発生させます。(正確な1秒を発生させることができれば、周波数カウンタや時計などに利用することができます。)
回路図です。
今回もICSPでテストします。クリスタルオシレータは、RA7に接続します。RB0に接続したLEDを1秒ごとに点滅させます。
外部クロックを利用する場合、__CONFIGには、_EXTCLK_OSCと記載します。他の設定は、これまでと同じです。
TMR2のブロックダイアグラムです。TMR2はPWMにも利用されますので、このような形になっています。
Prescalerは 1:16,Postscalerは1:1とします。
Fosc=20MHz=20000000Hzですので、Prescalerを通過すると20MHz/4=5MHz=5000000Hzが、5000000/16=312500Hz(周期3.2us)となり、TMR2に供給されます。
TMR2は8BITですから、さらに256分の1されます。Postscalerは、1:1ですので、312500/256=1220.703125Hz、つまり1秒間に約1220回割り込みが発生します。周期にすると3.2us×256=819.2usごとに1回の割り込みが発生します。割り込み回数をカウントするカウンタを設定して、1220回または1221回カウントすれば良いことになります。
時間の精度を上げるために更に工夫します。カウンタ初期値を1221とし、割り込みがあるたびにデクリメントします。3.2us周期の割り込みですから、カウンタが0になった時、時間経過は1221×819.2=1000243.2us=1.0002432sとなり、1秒を超えてしまいます。そこでTMR2に256から、243.2us/3.2=76を引いた値、256-76=180をセットしておくことにより、最初の割り込みの時に243.2us早く割り込みを発生させます。これでカウンタが0になった時に、正確な1秒を得ることができます。
各レジスタの設定です。
TMR21のPrescalerとPostscalerの設定は、T2CONレジスタで行います。
Prescalerの設定は、T2CKPS1とT2CKPS0で行い、1:16の場合は、1Xです。(Xは0でも1でもよい)
Postscalerの設定は、TOUTPS3~TOUTPS0で行い、1:1の場合は、0000です。
割り込み関係設定をします。PIE1レジスタのbit1 TMR2IEを1として、TMR2への割り込みを許可します。
また、全割り込み、汎用割り込みをINTCONレジスタのGIEとPEIEを1にして割り込みを有効にします。
割り込みが発生した時は、PIR1レジスタのTMR2IFが1になります。
プログラムです。
割り込みが発生した時の入り口は0X04番地です。
割り込み処理ルーチンで、最初にWレジスタとSTATUSレジスタの内容を待機させ、最後に復帰させます。割り込みフラッグTMR2IFは最初にクリアしておきます。
-----------------------------------------------
LIST P=PIC16F648A
INCLUDE P16F648A.INC
__CONFIG _EXTCLK_OSC & _CP_OFF & _CPD_OFF & _WDTE_OFF & _PWRTE_ON & _BOREN_OFF & _LVP_OFF & _MCLRE_OFF
ERRORLEVEL -302
;レジスタ
CBLOCK 020h
CNTH
CNTL
SAVE_W
SAVE_ST
ENDC
ORG 0x00 ;電源ON,RESET入口
GOTO SETUP
ORG 0x04 ;割り込み時の入口
INTR
;WレジスタとSTATUSレジスタの内容を保存
MOVWF SAVE_W
SWAPF STATUS,W
MOVWF SAVE_ST
BANKSEL PIR1
BCF PIR1,TMR2IF ;TMR2割り込みフラッグクリア
DECFSZ CNTL
GOTO INTEXIT ;COUNTERL!=0なら割り込み処理終了
MOVFW CNTH
IORLW 00h
BTFSC STATUS,Z ;ゼロでないならスキップ
GOTO LEDTOGGLE
DECF CNTH,F
GOTO INTEXIT
LEDTOGGLE
BANKSEL PORTB
BTFSS PORTB,0
GOTO LED_ON
LED_OFF
BCF PORTB,0 ;LED OFF
GOTO TOGGLE_END
LED_ON
BSF PORTB,0 ;LED ON
TOGGLE_END
;TMR2に初期値セット
BANKSEL TMR2
MOVLW 0B4h ;0B4h=180
MOVWF TMR2 ;TMR2初期値セット
;COUNTERに1221=04C5hをセット
MOVLW 04h
MOVWF CNTH
MOVLW 0C5h
MOVWF CNTL
INTEXIT
;STATUSレジスタとWレジスタの内容を復帰
SWAPF SAVE_ST,W
MOVWF STATUS
SWAPF SAVE_W,F
SWAPF SAVE_W,W
RETFIE
SETUP
;入出力設定
BANKSEL TRISA
CLRF TRISA ;PORTAは全て出力(RA5は入力に設定される)
CLRF TRISB ;PORTBは全て出力
BANKSEL CMCON
MOVLW 07h
MOVWF CMCON ;コンパレータは使わない
BANKSEL PORTB
CLRF PORTB
;TMR2設定
BANKSEL T2CON
MOVLW B'00000110' ;
MOVWF T2CON ;postscalere 1:1,prescaler 1:16,TMR2ON
BANKSEL PIE1
BSF PIE1,TMR2IE ;TIMER2割り込み許可
;割り込み設定
BANKSEL INTCON
BSF INTCON,GIE ;全割り込み許可
BSF INTCON,PEIE ;汎用割り込み許可
MAIN
GOTO MAIN
END
-----------------------------------------------
ブレッドボードです。LEDが1秒ごとに点灯、消灯を繰り返します。
クリスタルオシレータの精度やプログラムにより、数us程度の誤差がでると思います。周波数カウンタなどのタイムベースに使う場合は、更に誤差を少なくする工夫が必要になります。
※コメント投稿者のブログIDはブログ作成者のみに通知されます