PIC12F629においてTIMER1はSLEEPからの復帰が可能なタイマーです。
TIMER0は8ビットでTIMER1は16ビットということもあり、タイマー割り込みはほとんどタイマー1を使います。
省電力化しようとするとTimer1について、しょっちゅうマニュアルを見るので日本語でまとめておきます。主にデータシート、Developer Helpとやって確認したことのまとめです。
TIMER1モジュールとゲートコントロール
PIC12F629/675は16ビットのタイマーをもってます。
以下がブロックダイアグラムです。(後閑大先生の本の引用)
いろんなサイトを見ても、ほとんど言及されていませんが32.768KHzのLPクリスタルを接続した時、TImer1はこのクリスタルを入力ソースにできます。
この時、本体は内部クロックINTOSCで動かすことになります。(だってクリスタルを別につなぐ場所がないから)
それぞれの発振は同期しないので、T1CONで非同期を指定します。
タイマー1の割り込みで本体にやりたいことをさせてすぐにSLEEPさせるのです。
Lチカくらいなら割り込みルーチン内でやればいいので、main.cでは
while(1){ SLEEP(); NOP(); }
でよくなります。
これがPICで作る、もっとも省電力なデバイスの制作方法だと思います。
Timer1には以下の機能があります。
- 16ビットカウンター(TMR1H:TMR1L)
- 読み書き可能
- プリスケーラー
- 内部クロックか外部クロックか選べる
- 専用の32KHzオシレーター用回路
- 同期か非同期で動作
- 0xFFFF(65535)から0x0000に変わった時に割り込みが発生
- SLEEPからの復帰はオーバーフロー時(非同期モードで)
- 外部からのインプットでも可能
- LPオシレーターでも可能
タイマー1コントロールレジスター(T1CON)でタイマー1をコントロールします
Timer1モジュールの動作
タイマー1は以下の3つのモードのどれかで動作します。
- プリスケーラー付き16ビットタイマー
- 16ビット同期カウンター
- 16ビット非同期カウンター
タイマーの時はインストラクションサイクルごとに増えます。(クロックの1/4ということですね)
カウンターの時はタイマー1はT1CKIの外部クロック入力の立ち上がりエッジの時に増えます。
さらにカウンターモードのクロックはマイクロコントローラーのシステムクロックと同期することもできるし、非同期にすることもできます。
カウンターモードでもタイマーモードでもカウンター/タイマークロックはnT1Gインプットを選択できます。
もし外部クロックオシレーターが必要な場合(かつ、マイクロコントローラーがCLKOUTなしのINTOSCを使っている場合)タイマー1はLPオシレーターをクロックのソースとして使うことができます。
NOTE: カウンターモードでは立ち下がりエッジが、最初の立ち上がりエッジより先に、カウンターにより検知されます。
タイマー1のクロックソース
- タイマー1のクロックソースとは、タイマー1カウンターを増加する入力信号のことです。
クロックのソースはT1CON内のTMR1CSビットで選びます。
四つのソースがあります。 - Fosc/4命令クロック
- Foscシステムクロック
- 外部クロック
- 四番目(機種による)のクロック(LF内部オシレーターなど)
PIC12F629のような古いタイプはTMR1CS相当はT!CONの中のT1OSCENの1ビットです。
Fosc/4命令クロックソース(00)
命令クロック(Fosc/4)はTMR1CS<1:0> = 00)を選ぶと、Timer1は命令サイクルと同じオシレーターによりTMR1H:TMR1Lは立ち上がりエッジでインクリメントします。
Foscシステムクロックソース(01)
FoscのシステムオシレーターがTimer1のクロックソースとして使われます。(TMR1CS)
もし、TMR1H:TMR1Lの値を読むことがあるなら、Fosc/4のサイクルで読み取られるということです。
Fosc内部クロックが選ばれた場合、値は命令サイクルで更新されます。このため最下位の2ビットは精度がエラーである場合があります。
外部クロックソース(10)
外部クロックソースが選ばれた時(TMR1CS=10)タイマー1オシレーター可能ビット(T1OSCEN)が外部ソースとして選ばれます。タイマー1モジュールはI/Oピンか、外部の32KHzクロックオシレーターをm入力ソースとして使います。
T1CKI I/Oピン
カウンターを使いたい時T1OSCENビットでT1CKI入力をタイマー1のオシレーターとして使えます。
タイマー1はT1CK1入力の立ち上がりエッジでインクリメントされます。
これはマイクロコントローラーシステムクロックと同期することもできるし、非同期で動かすこともできます。
外部32KHzクロックオシレーター
タイマーをクロックオシレーターと別にしたい場合、T1OSCENビットはクリスタルオシレーターモードとします。このモードが選ばれるとTimer1は32.768KHzオシレーター回路(I/OピンのSOSCIとSOSCSO)を動かします。この内部サーキットには32.768KHzクロッククリスタルを接続します。タイマー1はリアルタイムクロックとして動作します。
タイマー1割り込み
タイマー1のレジスターペア(TMR1H:TMR1L)は0xFFFFを超えたら0x0000に戻ります。タイマー1が戻った時にタイマー1は割り込みフラグビット(PIR1<0>)をセットします。
割り込みを検知可能とするためには以下の3つのビットをセットします。
- タイマー1割り込み可能ビット(PIE1<0>)
- PEIEビット(INTCON<6>)
- GIEビット(INTCON<7>)
割り込みサービスルーチンの中でTMR1IFはクリアーしてから次の割り込みを受け付けてください。
タイマー1 プリスケーラー
タイマー1は4つのプリスケーラー(その数で割る)1/1,1/2,1/4,1/8でクロック入力を分周することができます。T1CKPSビット(T1CON<5:4>)で設定します。プリスケーラーカウンター自身を読み書きすることはできません。しかしTMR1HかTMR1Lに書き込みを行うとクリアされます。
T1CONレジスター
ビット6: TMR1GE: ゲート使用ビット 使わないなら0
ビット5-4: T1CKPS:T1CKPS0 プリスケーラー設定ビット
11 = 1/8プリスケーラー
10 = 1/4プリスケーラー
01 = 1/2プリスケーラー
00 = 1/1プリスケーラー
ビット3: T1OSCEN: LPオシレーター入力ビット
もしCLKOUTなしのINTOSCをアクティブにしているならば、1ではTimer1クロックとする、0ではオシレーターオフ(TMR1CSと関係する)
もしINTOSCでないならば関係ない
ビット2:nT1SYNC: タイマー1外部クロック入力と同期とるか 1=とらない 0=とる
ビット1: TMR1CS:タイマー1クロックのソース選択ビット 1:外部クロック 0:通常のFoSC/4
ビット0: タイマー1オン 1=オン、0=ストップ
非同期カウンターモードのタイマー1
外部クロックモードnT1SYNC(T1CON<2>)を1にすると同期は取られません。0にするとFosc/4と同期されます。タイマーはインターナルフェーズクロックとは同期せずにインクリメントされます。
非同期のタイマーはSLEEP中であっても動作し続け、オーバーフロー割り込みを発生します。それはプロセッサーを復帰させます。しかしタイマーの読み書きには注意が必要です。
タイマーが外部非同期のクロックで動いている時に、TMR1HやTMR1Lを読むと正しい読み方を意識しないといけません。ユーザーは16ビットタイマーが2つの8ビット値からなり、読んでいる最中にオーバーフローすると問題が起きます。
書き込み時にはユーザーは単純にタイマーを止めてのぞみの値を書き込むべきです。タイマーが値を増加している時には整合性が取れないことがあります。
タイマー1のオシレーター
OSC1, OSC2端子にはクリスタルオシレーター回路が設定されていて、T1OSCEN(T1CON<3>)をセットすれば使用可能となります。オシレーターは37KHz程度の弱いパワーのオシレーターが想定されています。表9-2にはタイマー1オシレーターの適切なコンデンサーが示されています。(まったく動きません。37KHzクリスタルの場合、15PF程度でないと動作しません!)
タイマー1オシレーターはシステムのLPオシレーターを共用することができます。内部オシレーターをシステムクロックとしている場合です。システムのLPオシレーターと共用する場合、ユーザーはオシレーターがきちんとスタートアップするまでソフトウェアで時間を与える必要があります。(数秒かかります。作るものによっては無反応としたほうがいいでしょう。)
TRISIO4とTRISIO5をえらんでいる場合、GP4とGP5がセットされるため、読み取っても0で、TRISIO4,TRISIO5は1(入力)となります。
SLEEP中のタイマー1
非同期カウンターモードにセットした時、TIMER1はSLEEP中でも動作します。このモードの時、外部クリスタルかクロックはカウンターのソースとして使われます。タイマーにより復帰させるには
- タイマー1はオン(T1CON<0>)をセット
- TTMR1IEビット(PIE1<0>)をセット
- PEIEビット(INTCON<6>)をセット
オーバーフローが起きるとデバイスは復帰します。GIEビット(INTCON<7>)がセットされていたらデバイスは動作し始め。オーバーフローした時に割り込みサービスルーチンへジャンプします。
関連レジスタ
サンプルコード
// PIC12F629 Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-Up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = ON // Code Protection bit (Program Memory code protection is enabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include
#define _XTAL_FREQ 4000000
// __delay_ms()
#define SW R3 // pin 4
#define GRN_LED GP2 // pin5
#define RED_LED GP1 // pin6
#define HIVALUE 0x00
#define LOWVALUE 0x01
static void setup(void){
CMCON = 0x07; // do not use comparator
TRISIO = 0b00010000; // all output except GP3 always in
T1CON = 0b00111000; // 7th. bit timer on/off TMR1ON
INTCONbits.PEIE = 1; // timer 1 intterupt
INTCONbits.GIE = 1;
PIE1bits.TMR1IE = 1;
PIR1bits.TMR1IF = 0; // reset interruption flag
GPIO = 0; // once reset
TMR1H = HIVALUE; // 5 sec
TMR1L = LOWVALUE;
}
void __interrupt() ISR(void){
if (PIR1bits.TMR1IF){
T1CONbits.TMR1ON = 0; // stop timer
PIR1bits.TMR1IF = 0;
//
GRN_LED = ~GRN_LED;
TMR1H = HIVALUE; // 5 sec
TMR1L = LOWVALUE;
T1CONbits.TMR1ON = 1; // start timer
}
}
void main(void){
setup();
T1CONbits.TMR1ON =1;
while(1){
}
}