目次PIC回路集室温調節装置


室温調節装置 ソフトウェア処理説明

ソフトウェア処理概要
今回のソフトウェアはベースレベル処理、TMR0割り込み処理、TMR1割り込み処理の3つのブロックで構成されています。

ベースレベルでは6つの7セグメントLEDの表示制御、3つのBCDスイッチの読み込み、およびUP/DOWN切替スイッチの読み込み処理を行っています。
当初はLED表示のデバイスの切り替えに時間が必要なため、割り込み処理を使うつもりでしたが、厳密な時間は必要ないのでNOP処理を繰り返すサブルーチンによりデバイスの切り替え時間を制御しています。処理の途中でTMR0およびTMR1の割り込み処理により中断されて時間は伸びますが、動作に影響はありません。

TMR0割り込み処理は温度の変化を2秒間隔で表示するために使用しています。温度表示がめまぐるしく変わるのを避けるためです。
TMR0による割り込み時間はあまり長くできません。4MHzクロックの場合、プリスケーラを256にしても最大65.5ミリ秒です。今回はTMR0の割り込み時間を10ミリ秒にし、ソフトウェアで2秒間隔を作っています。2秒間隔で温度検出をし、表示も2秒間隔にしています。
この処理では温度センサーの読み込み、表示データの設定以外にTESTモードの読み込み、温度比較処理を行っています。TESTモードの読み込み、および温度センサーの読み込みにはA/Dコンバータを使用しています。
TESTモードはベースレベルで処理しても良いのですが、A/Dコンバータ用の25μ秒タイマーサブルーチンを共用するためにTMR0割り込み処理で行っています。
外部装置の制御をするための温度比較条件は以下のようにしています。UP/DOWNの名称は室温が期待温度より高い場合はUP、期待温度より低い場合はDOWNとしています。少し分かりづらいです。
UPモードON条件:( 室内温度 > 設定温度 ) かつ ( 室内温度 > 屋外温度 )

OFF条件:( 室内温度 ≦ 設定温度 ) または ( 室内温度 ≦ 屋外温度 )

DOWNモードON条件:室内温度 < 設定温度

OFF条件:室内温度 ≧ 設定温度

TMR1割り込み処理は外部装置を制御する比較的長い時間を得るために使用しています。外部装置が頻繁にON/OFFすることを避けるためです。
TMR0の温度比較結果により外部装置をONにしたあと、2秒後に検出温度が変化してOFFにする条件になることもあります。そうすると外部装置が頻繁にON/OFFを繰り返すことになり、装置を傷める可能性もあります。そのため、外部装置を1度ONにしたら、数分間動作し続けるようにしています。この時間はインターバル設定スイッチで1分から10分まで変化させることができます。
外部装置は2つまで制御することができます。外部装置制御のON条件になるとNo.1の外部装置を動作させます。インターバル時間が経過したあとでもON条件が継続していた場合にはNo.2の外部装置を動作させます。OFF条件になった場合にはNo.2が動作していればNo.2を止め、インターバル時間後にNo.1を止めます。詳細は「TMR1割り込み処理」をご覧ください。

メモリの用途
以下に汎用メモリの使用用途を説明します。
out10:屋外温度10位BCDデータseg_ha:7セグメントデータテーブル先頭番地
out1:屋外温度1位BCDデータ
seg0:"0"表示パターン
in10:室内温度10位BCDデータ
seg1:"1"表示パターン
in1:室内温度1位BCDデータ
seg2:"2"表示パターン
preset10:設定温度10位BCDデータ
seg3:"3"表示パターン
preset1:設定温度1位BCDデータ
seg4:"4"表示パターン
out_temp1:屋外温度バイナリデータ ( 0.25℃単位 )
seg5:"5"表示パターン
in_temp1:室内温度バイナリデータ ( 0.25℃単位 )
seg6:"6"表示パターン
out_temp2:屋外温度バイナリデータ ( ℃単位 )
seg7:"7"表示パターン
in_temp2 :室内温度バイナリデータ ( ℃単位 )
seg8:"8"表示パターン
preset2:設定温度バイナリデータ ( ℃単位 )
seg9:"9"表示パターン
interval:インターバルタイマー値
sega:表示OFFパターン
mode:UP/DOWNモード ( 1:up/0:down )
w_save:Wレジスタセーブエリア
test_mode:TESTモード ( 2:OFF/1:IN/0:OUT )
s_save:STATUSレジスタセーブエリア
scan_cont:デバイス・スキャン・カウンター
temp_check:2秒カウンタ
rc_cont: led_onサブルーチンへの入力パラメータ
RCポート制御データ

presetb: 設定温度用
バイナリ変換カウンタ
rb_data: led_onサブルーチンへの入力パラメータ
RBポートデータ

presetw: 設定温度用
バイナリ変換データ
t25us_cnt:25μ秒サブルーチン用カウンタ
cont_flag:外部装置制御フラッグ
t200us_cnt:200μ秒サブルーチン用カウンタ
repeat:読取確認用カウンタ
t1ms_cnt:1ミリ秒サブルーチン用カウンタ
presetlk:設定温度ラストルック




interval_h:インターバルカウンタ ( 上位 )




interval_l:インターバルカウンタ ( 下位 )

初期化処理
初期化処理では以下の処理を行います。
ポート初期化:ポートA, B, C の入出力モードを設定

TMR0初期化:プリスケーラーを64とし、10ms割り込みに設定

TMR1初期化:プリスケーラーを8とし、500ms割り込みに設定

A/D初期化:ポートのA/Dモードを設定

LEDパターン設定: 7セグメントLEDの表示パターンを設定
LED制御ではRB7には常に'1'を設定

ワークエリア初期化:各種ワークメモリの値を初期化

割り込み設定:TMR0割込、周辺割込(TMR1)、グローバル割込を設定

LEDおよびスイッチスキャン処理
この処理はベースレベルの処理で、割り込み処理が行われていないときに常に実行されている処理です。LED点灯処理、スイッチ読み取り処理を順番に行います。
処理
実行内容
処理時間
1 屋外温度10位LEDの点灯制御を行います。
LEDのデバイス指定を rc_cont に格納し、表示データを rb_data に格納してLED点灯制御サブルーチン led_on を呼び出します。
1.22ms
2屋外温度1位LEDの点灯制御を行います。1.22ms
3室内温度10位LEDの点灯制御を行います。1.22ms
4室内温度1位LEDの点灯制御を行います。1.22ms
5設定温度10位LEDの点灯制御を行います。1.22ms
6設定温度1位LEDの点灯制御を行います。1.22ms
7 設定温度10位スイッチの読み取りを行います。
最初にLEDをOFFにしているのはデバイスの切り替えを行った時にLED制御のPORTBデータによる誤動作を防ぐためです。必要ないかもしれません。
RB0-6を入力モードに切り替えます。
デバイスの切り替え待ち時間は200ミリ秒にしています。もっと短くても問題ないと思います。
読み取ったBCDデータは回路の都合で0と1が逆になっているので、xorlw で反転させます。下位4ビット(BCD値)を格納します。
0.21ms
8 設定温度1位スイッチの読み取りを行います。
デバイスを切り替え、200ミリ秒後にデータを読み込みます。処理7で読み込んだ10位の値を使用してバイナリー(2進)データに変換します。
変換した値は presetlk に仮保存します。設定温度の値は3回続けて同じ値の場合に有効とし、preset2 に保存します。
これは動作試験で読み取り値に異常が発生したためです。「トラブルシュート」参照。
0.33ms
9 インターバルスイッチの読み取り、およびUP/DOWNスイッチの読み取りを行います。
デバイスの切り替えを行いますが、インターバルスイッチだけRB7を'0'に設定します。200ミリ秒後にデータを読み込みます。タイマー値は1以上なので、データが '0'の場合には10に変換しています。次の周期で行う処理はLED制御なので、RB0-6を出力モードに切り替えます。
最後にUP/DOWNスイッチを読み込み、スイッチの状態により mode にデータを設定します。( 1:up/0:down )
0.22ms

led_onサブルーチン
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
;--------------------------------------------------------
;                  LED ON subroutine
;--------------------------------------------------------
led_on
        movlw   b'11111111'
        movwf   portb           ;LED OFF
        movfw   rc_cont         ;Read RC control data
        movwf   portc           ;Set PORTC
        call    t200us          ;Wait 200 microseconds
        movfw   rb_data         ;Read disp digit
        addwf   seg_ha,w        ;HA + Digit
        movwf   fsr             ;Set address
        movfw   indf            ;Read 7seg data
        movwf   portb           ;Set PORTB
        call    t1ms            ;Wait 1 millisecond
        return

最初にLEDをOFFにしています。これはデバイスを切り替えたとき、前のデータが次のLEDに表示されるのを防ぐためです。
rc_cont のデータによりデバイス切り替えを行い200ミリ秒後に表示データの設定を行います。
LED表示パターンはワークエリアに格納してあるパターンテーブルから取り出します。テーブルの先頭番地に表示数字のバイナリデータを加算し、その番地にあるパターンデータを読み出すという間接アドレス形式を使用しています。パターンデータをPORTBに出力したあと、1ミリ秒の待ち合わせを行い1つのLEDの連続点灯時間を確保しています。スイッチの読み取り時間に比べLED連続点灯時間を長くすることにより、表示のちらつきを防止するためです。もっと短くても問題ないかもしれません。時間を変えたときの表示状態は確認していません。

上記の処理時間は参考値です。読み取りデータの値によりBCD変換処理ステップが変わるので、処理時間は多少変化します。シミュレータでは1周期の時間は約 8.33ms でした。処理1の先頭にブレークポイントを設定して計測した値です。

割り込み処理
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
;********************************************************
;                 Interruption Process
;********************************************************
int
        movwf   w_save          ;Save W register
        movfw   status          ;Read STATUS reg
        movwf   s_save          ;Save STATUS reg
        bcf     status,rp0      ;Change to Bank0
        btfsc   intcon,t0if     ;Check TMR0
        goto    temp_detect     ;TMR0 time-out
        btfsc   pir1,tmr1if     ;Check TMR1IF
        goto    out_control     ;TMR1 time-out

;********************************************************
;              END of Interruption Process
;********************************************************
int_end
        movfw   s_save          ;Read saved STATUS reg
        movwf   status          ;Recover STATUS reg
        swapf   w_save,f        ;Read saved W register
        swapf   w_save,w        ;Recover W register
        retfie

TMR0またはTMR1がタイムアウトすると割り込みが発生します。割り込み処理はベースレベルの処理のどの時点で発生するか分かりません。ベースレベルで使用しているレジスタの内容を割り込み処理で書き換えてしまうと、ベースレベルの処理が続行できなくなります。ですから、割り込み処理を始める前に共用するレジスタの内容を待避し、割り込み処理が終了した時点で元の内容に戻します。今回の処理ではWレジスタとSTATUSレジスタの内容を待避しています。ベースレベルで何も処理しない場合には必要ありませんが、初期化処理以外で何らかの処理をしている場合にはこの2つのレジスタの待避が必要になります。
待避処理で大切なことはSTATUSレジスタの内容を変えないことです。STATUSレジスタには処理結果の各種フラッグが格納されています。例えば、あるメモリを読み出してその内容が"0"かどうかで処理ステップを変える処理があったとします。この場合"0"の判断はBTFSSまたはBTFSC命令を使ってSTATUSレジスタのZフラッグを見ます。
ベースレベル処理
割り込み処理
     説明
 movfw   xyz
;処理判断のためにxyzを読出
割り込み発生
;0004番地から実行

        goto    int
         :
int
        movwf   w_save
        movfw   status
        movwf   s_save
         :
         :
         :

int_end
        movfw   s_save
        movwf   status
        swapf   w_save,f
        swapf   w_save,w   
        retfie
;
;
;
;
;movfw実行前のSTATUSレジスタ内容
;ベースレベルでのSTATUSレジスタ内容
;
;WおよびSTATUSレジスタが自由に使える
;
;
;
;
;ベースレベルでのSTATUSレジスタ内容
;swapf命令でSTATUSレジスタを変えない
;
;
割り込み終了
;割り込む前の番地から実行
 btfss   status,z
;STATUSレジスタは movfw xyz による内容

STATUSレジスタの待避を行う時に movfw ( movfの擬似命令 )命令を使っています。この命令を使うとSTATUSレジスタのフラッグが変化します。しかし、フラッグが変化するタイミングは命令を実行した後なので、Wレジスタには movfw を実行する前の内容、すなわち、ベースレベルでの内容が格納されます。
Wレジスタを復元するときに swapf 命令を使っています。待避エリアから movf 命令でWレジスタの内容を復元するとSTATUSレジスタのフラッグが変わってしまいます。そのため、フラッグに影響を与えない swapf 命令でWレジスタを復元しています。

今回の割り込み処理ではレジスタの待避が終了したあと、割り込み種別の判断をしています。TMR0割り込みかTMR1割り込みかの判断です。割り込み種別によりそれぞれの処理にジャンプします。

TMR0割り込み処理
419
420
421
422
423
424
425
426
427
428
429
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;         Temperature detection Process (10ms)
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
temp_detect
        bcf     intcon,t0if     ;Clear T0IF
        movlw   100             ;Set Time value
        movwf   tmr0            ;Write TMR0 register
        decfsz  temp_check,f    ;count - 1
        goto    int_end
        movlw   200
        movwf   temp_check      ;Set 2 seconds
まず最初に intcon レジスタの t0if 割り込みフラッグをクリアしています。このフラッグをクリアしないと、割り込み状態が継続し、割り込み処理を終了した時点で retfie 命令を実行するとタイムアウト状態でもないのにTMR0割り込みが発生してしまいます。
次にTMR0値の設定を行っています。TMR0は値をカウントアップし、カウンター( TMR0 )がオーバーフローしたときに割り込みが発生します。ですから、割り込みが発生した時点では TMR0 の値は"0"になっています。次の割り込みを指定時間後に発生させるために TMR0 の値を再度設定し直します。
今回 TMR0 の割り込みは10ミリ秒にしています。TMR0 割り込みで行いたい処理は2秒ごとなので、ソフトウェアのカウンター ( temp_check )で10ミリ秒を200回カウントし、2秒の時間を作り出しています。実際には temp_check に200を設定し、減算する方法を採っています。これは decfsz 命令を使うと減算と同時にカウントアウト判断をすることができ、処理を簡単にすることができるためです。2秒以下の割り込みではカウンターを減算するだけで、割り込み処理を終了します。2秒経過すると本来の割り込み処理が実行されます。

TESTモードチェック処理
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
;------------------ TEST mode check ---------------------
mode1
        movlw   b'01011001'     ;ADCS=01 CHS=AN3 ADON=ON
        movwf   adcon0          ;Set ADCON0 register
        call    t25us           ;Wait 25 microseconds
        bsf     adcon0,2        ;Start A/D conversion
mode2
        btfsc   adcon0,2        ;Conversion end ?
        goto    mode2           ;No.
        movlw   168             ;Set 3.3V
        subwf   adresh,w        ;AN3 - 3.3V
        btfss   status,c        ;AN3 >= 3.3V
        goto    mode3           ;No.
        movlw   2               ;Yes.
        movwf   test_mode       ;Set TEST OFF
        goto    temp0
mode3
        movlw   87              ;Set 1.7V
        subwf   adresh,w        ;AN3 - 1.7V
        btfss   status,c        ;AN3 >= 1.7V
        goto    mode4           ;No.
        movlw   1               ;Yes.
        movwf   test_mode       ;Set IN TEST
        goto    temp0
mode4
        clrf    test_mode       ;Set OUT TEST

温度センサーの出力はOPアンプにより増幅され、A/Dコンバータでデジタル変換されます。通常、温度表示は℃単位で行っています。でも、OPアンプの増幅度を調整するためにはもう少し詳細に温度を表示させたほうが正確になります。A/Dコンバータは10ビットのデジタル出力が得られます。今回の装置ではそのうちの上位6ビットを℃に対応させています。ですから、残りの下位4ビットを使えば1/16℃( 0.0625℃単位 )の情報を得ることができます。設定温度表示まで使えば小数点以下4桁の表示も可能ですが、今回は4ビットの内の上位2ビットを使い 0.25℃単位を表示させています。
TESTモードの情報はA/Dコンバーターにより取り込みます。TEST OFF では+5V、IN TEST では+2.5V、OUT TEST では0Vが入力されます。
モードの判定は5Vを3等分し、0V〜+1.7VをOUT TEST、+1.7V〜+3.3VをIN TEST、+3.3V以上をTEST OFFと判断しています。
A/Dコンバータを使ってTESTモード、屋外温度センサー、そして室内温度センサーの情報を順番にデジタル変換します。入力ポートを切り替えた後、アナログ情報をPICに取り込むまでの時間を確保する必要があります。1ビットの変換に必要は時間は4MHzクロックの場合 (1/4)*8 = 2μ秒 です。PIC16F873の場合、出力は10ビットですが、前後に1ビットづつ前処理時間、後処理時間がかかるので、12ビット分の時間を設けます。ですから、ポートを切り替えて、A/Dコンバータを起動するまで 12b×2us/b=24μ秒 の待ち時間を設ける必要があります。今回のサブルーチンでの待ち時間は25μ秒にしています。25μ秒過ぎてからA/Dコンバータを起動します。起動後、A/D変換の完了は adcon0 レジスタの GO/DONE ビットが"0"になることを監視して確認します。
A/Dコンバータの出力の上位8ビットを使うと5Vを255分割することになるので、1分割あたり約 0.0196V になります。TESTモードの場合、+1.7Vは出力の値で見ると 1.7/0.0196 = 87、+3.3Vは 3.3/0.0196 = 168 になります。

温度データ読取処理
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
;------------ OUT-SIDE temperature detection ------------
temp0
        movlw   b'01001001'     ;ADCS=01 CHS=AN1 ADON=ON
        movwf   adcon0          ;Set ADCON0 register
        call    t25us           ;Wait 25 microseconds
        bsf     adcon0,2        ;Start A/D conversion
temp1
        btfsc   adcon0,2        ;Conversion end ?
        goto    temp1           ;No.
        movfw   adresh          ;Read result
        addlw   8               ;Add 2deg-c
        movwf   out_temp1       ;Save (unit:0.25deg-c)
        movwf   out_temp2       ;Set data
        rrf     out_temp2,f     ;Rotate Right
        rrf     out_temp2,f     ;Rotate Right
        movlw   b'00111111'     ;Set mask
        andwf   out_temp2,f     ;Save (unit:1deg-c)

屋外温度と室内温度もA/Dコンバータを使ってデジタル変換しています。読み取った値の上位8ビットを使用しています。この場合、温度の値としては1ビットを0.25℃に対応させています。さらにその内の上位6ビットを抜き出すと1ビットが1℃に対応する値になります。
温度センサーの出力は2℃で0Vなので、2℃を加える必要があります。8ビットのデータは1ビットが0.25℃単位なので2℃を加えるのには8を加算します。

温度表示処理
TESTモードを切り替えると3種類の表示になります。通常はTEST OFFの状態で屋外温度、室内温度を1℃単位で表示します。

TEST OFF

IN TEST

OUT TEST
室内温度が25.50℃、屋外温度が24.75℃の場合、TESTモードの切り替えにより表示は上図のようになります。
A/Dコンバータで得られるデータはバイナリー(2進)形式なので、10位と1位を分離する必要があります。元のバイナリーデータから10を引き、引いた回数が10位、余りが1位の値です。変換の終了は減算結果が負になったことで判断しています。ですから、負になった場合には10を加えて正常な余りの値にしています。
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
temp43
        btfss   in_temp1,1      ;1X ?
        goto    temp45          ;No. 0X
        btfss   in_temp1,0      ;11 ?
        goto    temp44          ;No. 10
        movlw   7               ;Set .75 deg
        movwf   in10
        movlw   5
        movwf   in1
        goto    comp0           ;Jump to comparison
temp44
        movlw   5               ;Set .50 deg
        movwf   in10
        movlw   0
        movwf   in1
        goto    comp0           ;Jump to comparison
temp45
        btfss   in_temp1,0      ;01 ?
        goto    temp46          ;No. 00
        movlw   2               ;Set .25 deg
        movwf   in10
        movlw   5
        movwf   in1
        goto    comp0           ;Jump to comparison
temp46
        movlw   0               ;Set .00 deg
        movwf   in10
        movlw   0
        movwf   in1
        goto    comp0           ;Jump to comparison

IN TESTモードおよびOUT TESTモードでは1℃単位の値を屋外表示部に表示し、小数点以下の値を屋内表示部に表示しています。小数点以下の表示には8ビットのバイナリーデータの下位2ビットを使用します。状態は4種類です。00=0.00℃、01=0.25℃、10=0.50℃、11=0.75℃です。状態は4つだけなので、表示するデータを計算で求めるのではなく、状態を判断して該当する数値を屋内表示用のエリアに書き込んでいます。

温度比較処理
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
;---------- Temperature comparison processing -----------
comp0
        movfw   mode            ;Read mode(1:up 0:down)
        btfsc   status,z        ;Up ?
        goto    comp2           ;Jump to down mode

;***(Up mode)
        movfw   in_temp2        ;Read in-side
        subwf   preset2,w       ;preset - in-side
        btfsc   status,c        ;preset >= in-side ?
        goto    comp1           ;(>=)
        movfw   in_temp2        ;(<)Read in-side
        subwf   out_temp2,w     ;out-side - in-side
        btfsc   status,c        ;out-side >= in-side ?
        goto    comp1           ;(>=)
        bsf     cont_flag,flag  ;(<)Set control flag
        goto    int_end         ;Jump to int end
comp1
        bcf     cont_flag,flag  ;Clear control flag
        goto    int_end         ;Jump to int end

;***(Down mode)
comp2
        movfw   preset2         ;Read preset
        subwf   in_temp2,w      ;in-side - preset
        btfsc   status,c        ;in-side >= preset ?
        goto    comp1           ;(>=)
        bsf     cont_flag,flag  ;(<)Set control flag
        goto    int_end         ;Jump to int end
この装置のポイントとなる処理です。でも、処理は単純です。まず、UP/DOWNモードを判断し、それぞれの処理にジャンプします。
UP(室温が設定温度より高いときに外部装置を制御する)モードの場合、最初に室内温度と設定温度を比較します。室内温度の方が設定温度より高い場合には、外部装置を制御する条件に該当しますが、その前に室内温度と屋外温度を比較します。屋外温度が高い場合、外部装置を動作させないためです。屋外温度の方が低い場合、外部装置の制御条件になります。外部装置を制御する条件になると、cont_flag の flagビットに"1"を設定します。このビットに"1"を設定することによりTMR1の処理が外部装置を動作させます。
DOWN(室温が設定温度より低いときに外部装置を制御する)モードの場合、UPモードより単純で室内温度と設定温度だけを比較します。室内温度の方が設定温度より低い場合に外部装置の制御条件になり、cont_flag の flagビットに"1"を設定します。

TMR1割り込み処理
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;           Output control Process (500ms)
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
out_control
        bcf     pir1,tmr1if     ;Clear TMR1IF
        movlw   h'0b'           ;
        movwf   tmr1h           ;Set TMR1H register
        movlw   h'dc'           ;
        movwf   tmr1l           ;Set TMR1L register
        movfw   cont_flag       ;Read all control flags
        btfsc   status,z        ;All flags OFF ?
        goto    int_end         ;Yes. Jump to int end

        btfsc   cont_flag,o1    ;OUT1 control flag ON ?
        goto    cont1           ;Yes.
        btfsc   cont_flag,o2    ;OUT2 control flag ON ?
        goto    cont1           ;Yes.
;***(1st control)
        bsf     cont_flag,o1    ;Set OUT1 control flag
        bsf     porta,o1        ;OUT1 ON
        call    time_set        ;Set timer value
        goto    int_end         ;Jump to int end

cont1
        decfsz  interval_l,f    ;time -1
        goto    int_end         ;Not time-out
        movlw   1
        subwf   interval_h,f    ;Higher value check
        btfss   status,c        ;Value >= 1 ?
        goto    cont2           ;Value = 0 (Time-out)
        movlw   h'ff'
        movwf   interval_l      ;Set Lower value
        goto    int_end         ;Not time-out
cont2
        btfss   cont_flag,flag  ;Control flag ON ?
        goto    cont3           ;No.
        bsf     cont_flag,o2    ;Set output2 flag
        bsf     porta,o2        ;OUT2 ON
        call    time_set        ;Set timer value
        goto    int_end         ;Jump to int end
cont3
        btfss   cont_flag,o2    ;Output2 flag ON ?
        goto    cont4           ;No.
        bcf     cont_flag,o2    ;Clear output2 flag
        bcf     porta,o2        ;OUT2 OFF
        call    time_set        ;Set timer value
        goto    int_end         ;Jump to int end
cont4
        bcf     cont_flag,o1    ;Clear output1 flag
        bcf     porta,o1        ;OUT1 OFF
        goto    int_end         ;Jump to int end
この処理でも最初に pir1 レジスタの tmr1if 割り込みフラッグをクリアしています。TMR1は tmr1h と tmr1l の2つのカウンターを持っていて、16ビットでカウントします。プリスケーラは最大8です。ですから、4MHzのクロックでは 1us*8*65536 = 524,288us までカウントできます。今回はカウンタの初期値を 3036 とし、62,500カウント*8us=500ミリ秒で割り込みが発生するようにしています。
各500ミリ秒周期で cont_flag の flagビットをチェックしています。ですから、温度比較処理で外部装置制御要求を出すと、遅くとも500ミリ秒後にはTMR1の処理で検出することができます。外部装置の駆動状況は cont_flag の o1 および o2ビットで管理しています。管理ビットは飛び飛びになっています。o1は第2ビット目、o2は第5ビット目です。これは外部装置用の駆動ポートが回路1はRA2、回路2はRA5であり、o1、o2というラベルをPORTAのビット指定と共用しているためです。
両方のビットが"0"の場合には外部回路は駆動していない状態です。この状態で cont_flag のflagビットが立つと回路1を駆動することになり、 cont_flag の o1ビットを"1"にし、PORTAのRA2をONにします。これにより、リレー1が駆動され、外部装置1が動作し始めます。そのあと、インターバルタイマーを設定します。インターバルタイマーは外部装置が動作している時間です。設定値はインターバルスイッチの値により変わります。
500ミリ秒周期で o1 あるいは o2 が"1"であることが確認されると、インターバルタイマーの減算が行われます。インターバルタイマーのタイムアウト前に外部装置駆動条件が解除されて cont_flag の flagビットが"0"になってもインターバルタイマーがタイムアウトするまで外部装置を駆動し続けます。
インターバルタイマーがタイムアウトしたときに cont_flag をチェックします。 o1 および flagビットが"1"の場合、外部装置1を駆動しているが、まだ、温度が設定値に達していないということで、 o2ビットを"1"にし、PORTAのRA5をONにします。これにより、リレー2が駆動され、外部装置2が動作し始めます。この場合も、処理の最後でインターバルタイマーが設定されます。インターバルタイマーのタイムアウトの都度 cont_flag の flag、o1、o2 の各ビットをチェックし、外部装置の制御が行われます。

フラッグと外部装置駆動状態の関係は以下の表のようになります。
flago1o2外部装置駆動状態

000駆動しない

10 -> 10外部装置1を駆動

110 -> 1外部装置1および2を駆動

111そのまま外部装置を駆動

011 -> 0外部装置2を停止

01 -> 00外部装置1を停止

X01この状態は発生しない