CCPモジュールとTMR1による秒信号発生
コンペアモード
PIC16F877A にはキャプチャ、コンペア、パルス幅変調などのモードが使えるCCPモジュールがあります。
コンペアモードとタイマ1(TMR1)を使って1秒ごとに LED を点滅させるプログラムを作ってみました。

TIMER 1 モジュール
このタイマは3ビットのプリスケーラと16ビットカウンタがあります。
カウントする信号入力はクロック用の信号(Fosc = 10MHz)を使いました。

スペシャル・イベント・トリガ
CCPモジュールのレジスタ(CCPR1H, CCPR1L)に16bit以内の所望の値を書込んでおきタイマを走らせると、その値に到達したときPIR1レジスタのCCP1IFがセットされるので、それを単位信号として使います。
このとき TMR1 は自動的にリセットされ0から「設定されたある値」までのカウントを連続繰り返します。

この操作は CCPのスペシャル・イベント・トリガを設定することにより行なえます。

PIC16F877A には CCP1 と CCP2 の2個のモジュールがありますが上記の使い方をするにはCCP1 のモジュールを選択します。 カウント終了時にセットされた CCP1IF はプログラムの中でリセットしなければいけません。

プログラムの概要
PORTB のbit0 に接続した LED を1秒間隔で点滅されるプログラムを作って、動かしてみました。点灯 500mSec、消灯 500mSec としました。 
クロック用発振子の発振周波数が 10MHz で、 CCP1の 16bit レジスタでは直接 500mSecを取り出すことはできません。 ここでは 100mSecを取り出すようにしました。

設定値
 クロック周波数 Fosc :10MHz
 命令サイクルタイム: 4/Fosc = 0.4μSec
 プリスケーラ:4
 CCPP1H/L の16ビットカウンタ設定値:62,500(H'F424')

得られる時間 T は
 T = 0.4μSec x 4 x 62,500 = 100,000μSec = 100mSec となります。

この値をプログラムの中で5倍してLED を点滅させます。
100mSec を5倍したり、LED を点滅させたりしていても TMR1は走りつづけますから、プログラム上では何の誤差も出ません。100mSec間隔で信号が来ますが、その間 25万回の命令が行えるわけで、取得時間を 7seg-LED時計などに使う場合、割込み方式でなくても問題なくプログラムは進められます。

プリスケーラを8に設定すると 200mSec信号が取り出せます。

下は主要部分のプログラムです。
テストに使用したプログラムの全文(4KB)はここから見られます。
拡張子は .txt になっています。

2007.3.23
   
BCF STATUS,RP0 ;BANK 0
CLRF PIR1 ;周辺割込みフラグを下ろしておく
MOVLW B'00100000'
MOVWF T1CON ;TMR1の設定 内部クロックを使用
CLRF TMR1H ;TMR1 レジスタクリヤ
CLRF TMR1L
   
MOVLW B'00001011 ;コンペアモード
MOVWF CCP1CON ;スペシャル・イベント・トリガ使用
  
MOVLW H'24' ;62,500 カウント(H'F424'設定)
MOVWF CCPR1L
MOVLW H'F4'
MOVWF CCPR1H
BSF LED_SW,0 ;LED_SW は 1 に設定
MOVLW 5 ;5倍カウントの設定
MOVWF CNT
  
BSF T1CON,TMR1ON ;TMR1 スタートさせる
  
MAIN BTFSS PIR1,CCP1IF ;CCP1IF フラグはセットされたか
GOTO MAIN ;まだなら MAIN へ セットされたなら次へ
BCF PIR1,CCP1IF ;CCP1IF フラグをクリヤ
DECFSZ CNT,F ;5カウントしたらシフト
GOTO MAIN ;5カウントするまで繰返す
  
BTFSC LED_SW,0 ;LED_SW レジスタのbit0=0ならシフト
GOTO LED0_ON ;bit0=1なら LED_ON へ
LED_OFF BCF PORTB,0 ;LED 消灯
BSF LED_SW,0
MOVLW 5 ;5倍カウントの設定
MOVWF CNT
GOTO MAIN
  
LED_ON BSF PORTB,0 ;LED 点灯
BCF LED_SW,0
MOVLW 5 ;5倍カウントの設定
MOVWF LED_SW,0
GOTO MAIN
  
END