目次PIC回路集カウントダウン・タイマー


カウントダウン・タイマー ソフト処理説明




タイトル

;********************************************************
;
;             The Count-down timer processing
;
;                                 Author : Seiichi Inoue
;********************************************************

    コメント(;)を使用してプログラムのタイトルを書きました。



LIST および INCLUDE疑似命令

        list            p=pic16f84a
        include         p16f84a.inc
    PICの種類を指定するためにLISTコマンド(疑似命令)を使用します。
    PIC16F84Aの標準ラベル定義をINCLUDEコマンドで組み込みます。
    includeファイルの変更については「サインボード ソフト処理説明」を参照して下さい。
    または、ERRORLEVELコマンドで警告メッセージを表示しないようにすることができます。



コンフィギュレーションワード

    CONFIG疑似命令を使用してコンフィギュレーションワードの指定を行っています。

        __config _hs_osc & _wdt_off & _pwrte_on & _cp_off
    コンフィギュレーション・ワードはライターでプログラムを書き込む際にも指定できますが、CONFIG疑似命令を使用すると自動的に設定することができます。
    オペランドの内容については「サインボード ソフト処理説明」を参照して下さい。

    項目設定内容フィールド名称ビット
    コードプロテクションOFFCP1111111111
    パワーアップタイマーONPWRTE(inv)0
    ウォッチドッグタイマーOFFWDTE0
    クロック発振器指定HSFOSC1およびFOSC010






ラベル定義

;****************  Label Definition  ********************

    処理で使用するラベル常数の定義を行います。PIC16F84Aの標準ラベルはINCLUDEで組み込まれます。

    7セグメントLEDのパターン定義もEQUで行っています。

    パターンは次のようになっています。


'0'が点灯、'1'が消灯です。

正面図
abcdefg
00000001
11001111
20010010
30000110
41001100
50100100
60100000
70001111
80000000
90000100




デバッグモード指定

;**************  Debugging mode setting  ****************
;For debugging mode, ";" of next line should be removed.
;#define  _debug
    ソフトウェアをデバッグするときに処理ステップの一部を変更した方が良い場合があります。
    今回の場合には、カウンター値の初期値、タイマーの設定値、ストップスイッチの状態などを擬似的に設定する方法で行っています。その都度、ソースプログラムの内容を変更しても良いのですが、今回は'_debug'のラベルが定義されているかいないかでアッセンブルする内容が変わるようにしました。
    詳細は「ソフトデバック説明」のページを参照して下さい。



プログラム開始

;****************  Program Start  ***********************

    電源投入/リセット時はプログラムメモリアドレスは h'0000' からスタートします。また、割り込み処理のスタート番地は h'0004' です。
    goto命令で各処理にジャンプするようにしています。 h'0000' は初期化処理、h'0004' はタイマー割込処理にジャンプします。



初期化処理

;****************  Initial Process  *********************
    電源投入後の初期化処理として以下の処理を行います。
    ポートAのモードを設定
    ポートAの0番から3番の4本を出力ポート、4番を入力ポートに設定
    4番ポートはストップキーの入力ポートに使用
    ポートBのプルアップ機能を有効(RPBU=0)に設定

    プルアップ機能については「Bポート( RB0-RB3 ) の仕様」を参照して下さい。
    タイマー起動の条件設定

    内部クロックを使用、TMR0にプリスケーラを使用、プリスケーラ値は256
    ポートAの3番ポートの出力を'1'に設定

    リレーをOFF状態に設定
    7セグメントの点灯パターンをRAMメモリに書き込む

    7セグメントの点滅処理には間接アドレス方式を使用したので、RAMメモリにパターンを設定
    秒カウンターに0を設定
    タイムアウト表示(フラッグ)に非タイムアウト状態を設定





タイマー待機処理

;*************  Timer stand-by Process  *****************

    タイマーのカウントダウンがスタートしていない状態では以下の処理を繰り返し実行しています。

    BCDスイッチの状態を取り込み、カウンター値に設定

    カウンターの内容をLEDに出力

    ポートBの6番ポートを入力モードに設定

    スタートスイッチの状態を取り込む



タイマースタート処理
;**************  Timer start Process  *******************
    タイマー待機処理でスタートスイッチがONになったことを検出すると以下の処理が実行されます。

    リレーをONにする
    割り込みタイマーの初期化を実行
     出来るだけ正確に1秒毎の割り込みを行わせる必要があります。
     タイマーの割り込み時間を決めるには以下の要素があります。
発振器周波数:10MHzの発振を使用
プリスケーラの設定値: 256に設定
割り込み回数を少なくするために最大値を設定しています。
ハードタイマーのカウント値: 誤差が最小になるように設定しています。(213カウント)
設定値は256-213=43です。
ソフトカウンターの設定値:誤差が最小になるように設定しています。(46カウント)

    割り込み可能状態を設定

    以降の処理はタイムアウトするまで繰り返し実行されます。
    カウンターの内容をLEDに出力
    タイムアウトしたかどうかをチェック
    タイムアウト時には初期化処理に戻る

割り込み時間は以下の式で計算できます。
割り込み時間= (4/発振周波数) x プリスケーラ値 x ハードタイマーカウント値 x ソフトタイマーカウント値

= 0.4 x 10-6 x 256 x 217 x 45

= 0.999936 秒

上記のハードタイマーカウント値およびソフトタイマーカウント値はいろいろ組み合わせた結果、もっとも誤差が少なく、割り込み時間が少ない値でした。
発振器として4.19MHzを使った場合、ハードタイマーカウント値 =186、ソフトタイマーカウント値 = 22 の時の精度が最も良く、1.000049642秒でした。
実際の回路では発振器の周波数精度および割り込み後のソフト処理の関係で計算通りにはなりません。作成後に調整します。

私が作成した装置で99分カウントダウンした場合の誤差は−20秒(タイマーの方が速い)でした。
これを1秒の誤差に換算すると0.003367秒になります。そこで、ハードタイマーカウント値=213、ソフトタイマーカウント値=46にしました。この場合の割り込み時間は以下のようになります。値を調整した結果、99分で1秒以下の誤差になりました。
割り込み時間= (4/発振周波数) x プリスケーラ値 x ハードタイマーカウント値 x ソフトタイマーカウント値

= 0.4 x 10-6 x 256 x 213 x 46

= 1.0033152 秒

ハードタイマー(TMR0)の設定値は256から希望するカウント値を引いた値になります。256-213=43(2Bh)




LED点灯制御サブルーチン

;**************  LED Control Subroutine  ****************

    分の10位、分の1位、秒の10位、秒の1位の順にカウンターの内容をLEDに出力します。




BCDコードから7セグメントデータへの変換

;*******  Change BCD to 7segment data Subroutine  *******

    BCDコードのデータから7セグメントのデータへの変換を行い、ポートBに出力します。




1ミリ秒タイマーサブルーチン

;*************  1msec Timer Subroutine  *****************
    ポートBはBCDスイッチ、スタートスイッチ、LEDなどの制御を行っています。各デバイスを指定してもトランジスタがONになるのに少し時間がかかります。この時間は数μ秒と非常に短いのですが、PICの動作は10MHzクロックを使用した場合には0.4μ秒とそれより短いです。ですから、BCDスイッチなどのデバイスを指定した後、1ミリ秒の待ち処理を入れています。1ミリ秒である必要はないです。もう少し短くても問題はないと思います。これはトランジスタの特性によります。待ち時間が長すぎると表示がちらついてしまいます。

    BCDスイッチ、スタートスイッチなどのように入力モードで使用する場合にはデバイスを指定した後、デバイスの状態を読み込む前に1ミリ秒の待ちをします。7セグメントLEDのように出力モードで使用する場合にはLEDの点灯情報を出した後、1ミリ秒待った後次のデバイスの処理をします。

    待ち時間が必要なことはMLPABでのシミュレーションでは分かりません。私は実際の回路で動作させてみて分かりました。ハードウェアの動作時間も考慮する必要があります。

    このサブルーチンは「LEDフラッシャー」で作成した処理を流用しています。




割り込み処理

;************  Begin Interruption Process  **************

    WレジスタのセーブとSTATUSレジスタのセーブを行い、タイマー割り込みの確認を行います。
    ここで注意すべき点は割り込み時のバンク状態です。割り込まれた処理でバンクを1に切り替えた直後に割り込みが発生すると割り込み処理で違うSFRを設定してしまうことがあります。ですから、STATUSレジスタのセーブが終了した後、バンクを0に切り替える処理を実行しています。



割り込み終了処理
;************  END of Interruption Process **************
    STATUSレジスタおよびWレジスタの戻しを行い、割り込み終了命令(RETFIE)で割り込み処理を終了すると同時に次の割り込みを可能な状態にします。
    Wレジスタを戻すのにはSTATUSレジスタの内容が変わらないようにSWAPF命令を使用しています。


タイムアウト割り込み処理
;***********  Time-out interruption Process  ************
    ハードウェアのタイマーTMR0がタイムアウトするとこの処理が実行されます。
    1秒毎にカウントダウン処理をさせるためには、ハードウェアタイマーだけでは短いです。(10MHzクロックで最大26_秒)
    ですから、ハードタイマーの割り込みをソフトウェアでカウントし、1秒毎にカウントダウン処理を実行させるようにしています。
    カウントダウンの誤差を最小にするようにハードタイマーの設定値とソフトでのカウント値設定を決めています。


カウントダウン処理
;*************  Timer count-down Process  ***************
    1秒毎に処理が実行されます。
    最初に秒の1位カウンターを減算して0になるかどうかをチェックしています。0になった場合にはタイムアウト状況の可能性があるので、全てのカウンターが0かどうかのチェックをしています。
    カウンターが0であるかどうかはmovf命令でカウンター内容を読み出し、STATUSレジスタのZビットをチェックして判断します。Zビットが'1'の場合にはカウンターの内容が0であることを示しています。
    いずれかのカウンターが0でない場合にはタイムアウト状態ではないので、カウントダウン処理に移ります。
    カウントダウン処理では各カウンタの内容をチェックし、0の場合には最大値の設定を行います。秒の10位の最大値は5で他の桁は9が最大値です。カウンターの内容が0でない場合にはその桁だけ1つ減算します。

    割り込み処理ではタイムアウトチェックとカウントダウン処理のみを行います。タイムアウトした場合の処理(タイマー停止、リレーOFF)およびカウンターをLEDに表示する処理はタイマースタート処理で行っています。


コーディングの終了
;********************************************************
;          END of signboard control processing
;********************************************************
        end
    コーディングの最後は end命令 で終了します。endが無いとアッセンブラはコーディングの最後を検出できず。エラーになります。