ソフトウェア処理概要
今回のソフトウェアはベースレベル処理、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 の各ビットをチェックし、外部装置の制御が行われます。
フラッグと外部装置駆動状態の関係は以下の表のようになります。
| flag | o1 | o2 | 外部装置駆動状態 |
| 0 | 0 | 0 | 駆動しない |
| 1 | 0 -> 1 | 0 | 外部装置1を駆動 |
| 1 | 1 | 0 -> 1 | 外部装置1および2を駆動 |
| 1 | 1 | 1 | そのまま外部装置を駆動 |
| 0 | 1 | 1 -> 0 | 外部装置2を停止 |
| 0 | 1 -> 0 | 0 | 外部装置1を停止 |
| X | 0 | 1 | この状態は発生しない |
|