Timer0を使う
PIC16F18313のTimer0は従来の8bitから16bitに拡張された。また8bitモードでも使えて、コンペアで割り込みできるようになった。
割り込み周期
1Hz周期でLEDを点滅させるなら、2Hz周期で割り込めば良い。Fosc/4が250kHzだとすると、プリスケーラで1/8(→31250Hz)、ポストスケーラで1/5(→6250Hz)、TMR0H=125でコンペアすると50Hz割り込みになり、割り込みルーチンの中で25カウントすると2HzでLEDのアクセスができる。
この割り込みルーチンは以下のようになる。
unsigned char flg=0;
unsigned char cnt=0;
void __interrupt() isr(void) {
if(TMR0IF) {
TMR0IF=0;
cnt++;
if(cnt>25) {
cnt=0;
if(flg) {
LATAbits.LATA2=1;
LATAbits.LATA5=0;
} else {
LATAbits.LATA2=0;
LATAbits.LATA5=1;
}
flg=1-flg;
}
}
}
mainルーチン
mainルーチンは以下のようになる。LEDピンの出力設定、TMR0の設定、割り込み許可を順に設定してあとはループするだけだ。
#include <xc.h>
#include "pragma_config.h"
void main(void) {
TRISAbits.TRISA2=0;
TRISAbits.TRISA5=0;
T0CON1bits.T0CS=0b010; // Fosc/4
T0CON1bits.T0CKPS=0b0011; // Prescaler 1/8
TMR0H=125;
T0CON0bits.T0OUTPS=0b0100; // Postscaler 1/5
T0CON0bits.T0EN=1;
PIR0bits.TMR0IF=0;
PIE0bits.TMR0IE=1;
INTCONbits.PEIE=1;
INTCONbits.GIE=1;
while(1) ;
}
不安定割り込み
このようにTMR0のコンペア割り込み機能を使ったが、割り込みルーチンの呼び出し周期が安定しない。SimulatorのStopwatch機能を用いてサイクル数を確認してみると5039と5041サイクルを交互に繰り返している。つまり5000サイクル(20ms)で正確に割り込めていない。同じようにLEDのON周期を調べても262079と262081サイクルを繰り返し、本来の250000サイクルとは差異がある。
素直にdelay関数で調整した方が正確だ。
もしかしてnop
サイクル数が1サイクルずれるのはアセンブラではジャンプ命令が原因の場合が多いので、「while(1) {}」のところを「while(1) {__nop()}」としたところ、Simulatorでも安定して割り込みルーチンが呼ばれるようになった。ただしLEDのONサイクル数は262080であり、12080サイクルだけ遅いままだ。割り込みサイクルも5040サイクルであり、ここを解消する必要がある… 結局、TMR0H(コンペアレジスタ)をひとつ減らしてみたら(125→124)あっさりと本来の250000サイクルとなった!
投稿者の人気記事
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
(メッセージ: 初版)
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
-
akira.kei
さんが
2025/01/26
に
編集
をしました。
ログインしてコメントを投稿する