目次
前
次
LEDを点滅(タイマー割込み利用)
時間利用の動作制御には、タイマー割込みを使います。
マイコンを触り始めた頃だと、このページの内容を理解する
のは、難しいと思うので、一通りのことができるようになった
時点で、このページに戻った方が理解しやすいでしょう。
PICは、割込み処理はひとつだけになっているので
割込み処理コード(割込みハンドラと言います。)
の中で、どういう種類の割込みが発生したのかを
判断して、対応した処理を実行します。
データシートの中にある、割込み信号生成回路をみれば
どんな割込みができるのかを理解できます。
個別モジュールごとに割込みを使うか否かと、割込み
発生時の動作を、別途設定できる仕様です。
注意するのは、どれかひとつでも、モジュールの割込み
を使うときは、Global Interruptを許可すること。
割込み信号生成回路で、最も右にあるANDに、GIEと個別の
モジュールの割込み信号のOR出力を入力しています。
図面から、Global Interruptを許可しないと、割込みの
発生が、CPUに通知されないとわかります。
具体的な割込みの初期化コードは、以下。
/* initialize Timer 0 */
{
/* ??? */
/* enable timer0 overflow interrupt */
INTCON.T0IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
mikroCの割込みハンドラは、次のように記述します。
void interrupt(void)
{
/* timer0 overflow */
if ( INTCON.T0IF == ON ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* ??? */
}
}
割込みハンドラは、関数interruptで扱います。
Global Interruptがひとつだけと割込み信号生成
回路でわかっているので、割込みハンドラも唯一
です。
割込みの発生を通知したモジュールが、フラグを
セットするので該当モジュールのフラグがセット
したかスキャンして、複数の割込みに対応します。
割込みハンドラで使う時間は、極力短くした方がよい
ので、イベントフラグを使い、main関数に通知して
時間のかかる処理は、main関数の無限ループの中で
他の関数に仕事を依頼する方が楽です。
動作フローで示すと以下。
イベントフラグをセットするのは、割込みハンドラ
フラグのリセットは、main関数の無限ループの中で
として、構造を単純にします。
関数mainは、次のように記述。
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* process A */
if ( FLAGA == ON ) {
/* clear */
FLAGA = OFF ;
/* ??? */
}
/* process B */
if ( FLAGB == ON ) {
/* clear */
FLAGB = OFF ;
/* ??? */
}
/* process C */
if ( FLAGC == ON ) {
/* clear */
FLAGC = OFF ;
/* ??? */
}
}
}
ワンチップマイコンでは、使える内蔵メモリが
少ないので、共用体を利用して1バイトの中に
8個のフラグを用意して使えるようにします。
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGA xflags.BIT.B0
#define FLAGB xflags.BIT.B1
#define FLAGC xflags.BIT.B2
#define FLAGD xflags.BIT.B3
この場合、4フラグを利用していますが
初期化(ゼロクリア)は、1回で全部の
フラグを扱えます。
xflags.DR = 0x00 ;
フラグのセット、リセットは、変数と同様
代入だけでOK。
FLAGA = ON ;
FLAGB = OFF ;
FLAGC = OFF ;
FLAGD = ON ;
構造体、共用体は、C言語のテキストでは使い処が
見えにくいため、説明に苦労しているようですが
ワンチップマイコンのファームウエアで考えると
わかるようになります。
PIC16F627Aのタイマーは、3モジュールあり
タイマー0、タイマー1、タイマー2と命名
されてます。
タイマー0のブロック図を見てみます。
PICのタイマー0は、Watch Dog Timerと兼用で
どちらを使うかをセレクタで指定可能。
Watch Dog Timerを使う場合、WDT ENABLE BITをセットし
同時にPSAを1にします。
クロックソースを外部、システムクロックの1/4、Watch Dog Timer
のどれかにします。外部からの場合、RA4(T0CKI)ピンを使います。
クロックソースを決めたなら、プリスケーラで分周比を決めます。
タイマー0で利用するカウンタは、8ビット。
また、割込みはオーバーフローのみというのも
ブロック図をみるとわかります。
思い通りにタイマー0を使うには、関係レジスタに
値を設定しなければ駄目。
割込み関係は、INTCONレジスタのGIE、TOIEの2つ
のビットとなります。
タイマー0の初期設定は、以下。
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
all inputs are pull-up .
*/
OPTION = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.T0IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
システムクロックの利用では、1/4になるので
プリスケーラ経由でカウンタのクロックを使う
ようにします。
プリスケーラは、OPTIONレジスタの中にあるので
次の分周比を設定。
- 1/2 0(0x00)
- 1/4 1(0x01)
- 1/8 2(0x02)
- 1/16 3(0x03)
- 1/32 4(0x04)
- 1/64 5(0x05)
- 1/128 6(0x06)
- 1/256 7(0x07)
OPTIONレジスタのPSAは、Watch Dog Timerを使う場合
1を設定します。
クロックソースを、RA4ピンの入力とするなら、T0CSを1に設定。
T0SEは、反転して入力するのか、そのままかを指定。
割込みを使う場合オーバーフローにするので、カウンタ
の値が、255から0に戻るとき、割込みが発生。
この変化をINTCONのT0IFビットに反映させます。
カラクリがわかれば、割込みハンドラ関数interrupt
では、どの割込みが発生しているのかをスキャンし
フラグのセットで通知する方式が妥当だと理解できる
でしょう。
カラクリがわかれば、関数interruptは次のように
記述することになります。
void interrupt(void)
{
/* timer0 overflow interrupt */
if ( INTCON.T0IF == ON ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* set flag */
FLAGA = ON ;
}
}
ここまでの内容を踏まえて、LEDをひとつ点滅する
処理に、割込みを使ったコードは以下。
#define OFF 0
#define ON OFF+1
#define STARTV 6
#define STIMMAX 625
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGA xflags.BIT.B0
volatile UBYTE state ;
volatile UWORD stim ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
/* timer0 overflow interrupt */
if ( INTCON.T0IF == ON ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = STARTV ;
/* update counter */
stim++ ;
/* judge */
if ( stim == STIMMAX ) {
/* clear */
stim = 0 ;
/* set flag */
FLAGA = ON ;
}
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer0 interrupt */
if ( FLAGA == ON ) {
/* clear flag */
FLAGA = OFF ;
/* impress */
PORTB = state & ON ;
/* update state */
state++ ;
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* set sub counter */
stim = 0 ;
/* initialize Timer 0 */
{
/*
10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16
156250Hz / 250 = 625 Hz
*/
OPTION = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = STARTV ;
/* enable timer0 overflow interrupt */
INTCON.T0IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
割込みを利用すると、コードは増えていきますが
無駄時間をカウントで扱うことから解放されます。
割込みを使うと、ひとつのマイコンで複数の仕事を
扱えるようになります。
ひとつの仕事のみとなれば、割込みを使わないで
済みますが、1人の従業員に多くの作業をさせる
のが、マイコンを使う側の論理です。
タイマー1のブロック図を見ていきます。
ブロック図から読み取れることをリスト。
- カウンタは16ビット
- オーバーフローで割込みを生成
- RB6、RB7に振動子接続して発振させられる
- 外部発振とシステムクロックの1/4のいずれかをクロックソースにできる
- プリスケーラを使える
- プリスケーラの分周比は、1/1、1/2、1/4、1/8のいずれか
- クロックと同期、非同期でカウンタを更新できる
これらの情報を利用して、意図した動作をさせるために
レジスタへの設定値を考えます。それには関係レジスタ
の内容を理解します。
関係レジスタの内容は、以下。
T1CONレジスタのビット構成をみると、タイマー1は
利用するか否かを指定できるよう。
T1CONレジスタのTMR1ONビットで、モジュールに電源を
与えるかカットするかを決めていると考えます。
電源を与えなければ、そのモジュールは動作しないので
その分だけ消費電力が減ります。
TK1CKPS1、TK1CKPS1の組み合わせで、プリスケーラの
分周比を決めることができます。2のベキ乗利用での
設定になるので、シフト演算子で指定がよいでしょう。
タイマー1を利用して、プリスケーラを1/2にするなら
次のコードとなります。
T1CON = (1 << 4) | 1 ;
割込みは、PIE1(Peripheral Interrupt Enable)レジスタ
のTMR1IEビットをセットし、カウンタのオーバーフロー
で発生するようにします。
Global Interruptを指定を忘れないよう、注意します。
関数interruptの記述は、以下。
void interrupt(void)
{
/* timer1 overflow interrupt */
if ( PIR1.TMR1IF == ON ) {
/* clear flag */
PIR1.TMR1IF = OFF ;
/* initialize */
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* set flag */
FLAGB = ON ;
}
}
タイマー1の初期化は次のようにします。
/* initialize Timer 1 */
{
/*
10MHz/4 = 2.5MHz -> 2.5MHz/8 = 312.5kHz prescaler = 1:8
*/
T1CON = (3 << 4) | 1 ;
/*
65536 - 62500
*/
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
タイマー0で実現した内容を、タイマー1で
置き換えてみます。
#define OFF 0
#define ON OFF+1
#define STARTV 3036
typedef unsigned char UBYTE ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGB xflags.BIT.B1
volatile UBYTE state ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
/* timer1 overflow interrupt */
if ( PIR1.TMR1IF == ON ) {
/* clear flag */
PIR1.TMR1IF = OFF ;
/* initialize */
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* set flag */
FLAGB = ON ;
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer1 interrupt */
if ( FLAGB == ON ) {
/* clear flag */
FLAGB = OFF ;
/* impress */
PORTB = state & ON ;
/* update state */
state++ ;
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* initialize Timer 1 */
{
/*
10MHz/4 = 2.5MHz -> 2.5MHz/8 = 312.5kHz prescaler = 1:8
*/
T1CON = (3 << 4) ;
/*
65536 - 62500
*/
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
/* enable */
T1CON |= 1 ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
カウンタが16ビットになったので、8ビットレジスタの
再設定には、2ステートメントが必要となりました。
計算そのものは単純です。
タイマー2のブロック図を見ていきます。
ブロック図から読み取れることをリスト。
- カウンタは8ビット、参照レジスタも8ビット
- カウンタと参照レジスタの値を比較、一致時に比較器の出力を1とする
- カウンタと参照レジスタの値が一致するとカウンタはゼロクリアされる
- システムクロックの1/4のみをカウンタのクロックにできる
- カウンタのクロックは、プリスケーラで分周する
- プリスケーラの分周比は、1/1、1/4、1/16のみ
- 比較器の出力をポストスケーラに伝達
- ポストスケーラの分周比は、4ビット指定の1から16で指定可能
これらの情報を利用して、意図した動作をさせるために
レジスタへの設定値を考えます。それには関係レジスタ
の内容を理解します。
関係レジスタの内容は、以下。
T2CONレジスタのビット構成から、タイマー2は利用するか
しないを指定できると読めます。
T2CONレジスタのTMR2ONビットで、モジュールに電源を
与えるかカットするかを決めていると考えます。
T2CONレジスタでプリスケーラ、ポストスケーラの分周比を
一度に指定できるようになっています。
プリスケーラは、1/1、1/4、1/16の分周比ですが、ビット
の組み合わせは、00、01、10、11の4通り。この中で10と
11が1/16の分周比とできます。
ポストスケーラは、4ビットなので(分周比の値-1)を
指定します。
タイマー2の割込みを利用する場合、関数interruptは
次のように定義すればよいでしょう。
void interrupt(void)
{
/* timer2 compare match interrupt */
if ( PIR1.TMR2IF == ON ) {
/* clear flag */
PIR1.TMR2IF = OFF ;
/* ??? */
/* set flag */
FLAGC = ON ;
}
}
タイマー2の初期化は次のようにします。
/* initialize Timer 2 */
{
/*
prescalar
10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16
postscalar 1:5
*/
T2CON = (4 << 3) | (1 << 2) | 3 ;
/* clear counter */
TMR2 = 0 ;
/* set reference value 250 */
PR2 = STARTV ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
タイマー0と同じ内容をタイマー2で実現すると、以下。
#define OFF 0
#define ON OFF+1
#define STARTV 250
#define SCNTMAX 125
typedef unsigned char UBYTE ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGC xflags.BIT.B2
volatile UBYTE state ;
volatile UBYTE scnt ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
/* timer2 compare match interrupt */
if ( PIR1.TMR2IF == ON ) {
/* clear flag */
PIR1.TMR2IF = OFF ;
/* update counter */
scnt++ ;
/* judge */
if ( scnt == SCNTMAX ) {
/* clear */
scnt = 0 ;
/* set flag */
FLAGC = ON ;
}
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer2 interrupt */
if ( FLAGC == ON ) {
/* clear flag */
FLAGC = OFF ;
/* impress */
PORTB = state & ON ;
/* update state */
state++ ;
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* clear sub counter */
scnt = 0 ;
/* initialize Timer 2 */
{
/*
prescalar
10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16
postscalar 1:5
*/
T2CON = (4 << 3) | 3 ;
/* clear counter */
TMR2 = 0 ;
/* set reference value 250 */
PR2 = STARTV ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
/* enable */
T2CON |= (1 << 2) ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
ここまでで、関数mainの改変は通知フラグだけで
よいと理解できると思います。
どのタイマーを利用するかで、初期化と割込みハンドラの
記述内容が変わります。関数mainの内容の一部改変だけに
なっているとわかれば、割込みを使うのは面倒ではないと
理解できるでしょう。
方向指示器をタイマー割込みを利用して、書き直します。
タイマー0による方向指示器
#define OFF 0
#define ON OFF+1
#define STARTV 6
#define STIMMAX 625
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGA xflags.BIT.B0
volatile UBYTE state ;
volatile UWORD stim ;
volatile UBYTE pat[8] ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
/* timer0 overflow interrupt */
if ( INTCON.T0IF == ON ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = STARTV ;
/* update counter */
stim++ ;
/* judge */
if ( stim == STIMMAX ) {
/* clear */
stim = 0 ;
/* set flag */
FLAGA = ON ;
}
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer0 interrupt */
if ( FLAGA == ON ) {
/* clear flag */
FLAGA = OFF ;
/* impress */
PORTB = *(pat+state) ;
/* update */
state++ ;
if ( state == 8 ) { state = 0 ; }
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* set sub counter */
stim = 0 ;
/* store bit pattern */
*(pat+0) = 0x01 ; *(pat+1) = 0x02 ;
*(pat+2) = 0x04 ; *(pat+3) = 0x08 ;
*(pat+4) = 0x10 ; *(pat+5) = 0x20 ;
*(pat+6) = 0x40 ; *(pat+7) = 0x80 ;
/* initialize Timer 0 */
{
/*
10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16
156250Hz / 250 = 625 Hz
*/
OPTION = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = STARTV ;
/* enable timer0 overflow interrupt */
INTCON.T0IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
タイマー1による方向指示器
#define OFF 0
#define ON OFF+1
#define STARTV 3036
typedef unsigned char UBYTE ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGB xflags.BIT.B1
volatile UBYTE state ;
volatile UBYTE pat[8] ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
if ( PIR1.TMR1IF == ON ) {
/* clear flag */
PIR1.TMR1IF = OFF ;
/* initialize */
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* set flag */
FLAGB = ON ;
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer1 interrupt */
if ( FLAGB == ON ) {
/* clear flag */
FLAGB = OFF ;
/* impress */
PORTB = *(pat+state) ;
/* update */
state++ ;
if ( state == 8 ) { state = 0 ; }
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* set sub counter */
stim = 0 ;
/* store bit pattern */
*(pat+0) = 0x01 ; *(pat+1) = 0x02 ;
*(pat+2) = 0x04 ; *(pat+3) = 0x08 ;
*(pat+4) = 0x10 ; *(pat+5) = 0x20 ;
*(pat+6) = 0x40 ; *(pat+7) = 0x80 ;
/* initialize Timer 1 */
{
/*
10MHz/4 = 2.5MHz -> 2.5MHz/8 = 312.5kHz prescaler = 1:8
*/
T1CON = (3 << 4) ;
/*
65536 - 62500
*/
TMR1L = STARTV % 256 ;
TMR1H = STARTV / 256 ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
/* enable */
T1CON |= 1 ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
タイマー2による方向指示器
#define OFF 0
#define ON OFF+1
#define STARTV 250
#define SCNTMAX 125
typedef unsigned char UBYTE ;
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define FLAGC xflags.BIT.B2
volatile UBYTE state ;
volatile UBYTE scnt ;
volatile UBYTE pat[8] ;
/* prototype */
void usr_init(void);
void interrupt(void)
{
/* timer2 compare match interrupt */
if ( PIR1.TMR2IF == ON ) {
/* clear flag */
PIR1.TMR2IF = OFF ;
/* update */
scnt++ ;
/* judge */
if ( scnt == SCNTMAX ) {
/* clear */
scnt = 0 ;
/* set flag */
FLAGC = ON ;
}
}
}
void main(void)
{
/* initialize PORT */
usr_init();
/* endless loop */
while (ON) {
/* timer2 interrupt */
if ( FLAGC == ON ) {
/* clear flag */
FLAGC = OFF ;
/* impress */
PORTB = *(pat+state) ;
/* update */
state++ ;
if ( state == 8 ) { state = 0 ; }
}
}
}
void usr_init(void)
{
/* initial value */
PORTB = OFF ;
/* direction */
TRISB = 0x00 ;
/* clear flag */
xflags.DR = 0x00 ;
/* clear state counter */
state = 0 ;
/* set sub counter */
scnt = 0 ;
/* store bit pattern */
*(pat+0) = 0x01 ; *(pat+1) = 0x02 ;
*(pat+2) = 0x04 ; *(pat+3) = 0x08 ;
*(pat+4) = 0x10 ; *(pat+5) = 0x20 ;
*(pat+6) = 0x40 ; *(pat+7) = 0x80 ;
/* initialize Timer 2 */
{
/*
prescalar
10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16
postscalar 1:5
*/
T2CON = (4 << 3) | 3 ;
/* clear counter */
TMR2 = 0 ;
/* set reference value 250 */
PR2 = STARTV ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
/* enable */
T2CON |= (1 << 2) ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
}
目次
前
次