目次PIC回路集デジタル時計


デジタル時計 処理説明



ラベル定義
;****************  Label Definition  ********************
        cblock  h'20'
データエリアにはCBLOCK疑似命令を使用して20hから自動割付を行っています。割付の終了にはENDCを使います。
以下に今回使用しているデータエリアの意味(使用目的)を示します。

ラベル
用  途
count:20ミリ秒(50Hz)のクロックを50回カウントして1秒(1Hz)毎に時計を更新するためのカウンタです。
disp_p: LED表示の桁指定データを格納します。
時10位:6,時1位:5、分10位:4、分1位:3、秒10位:2、秒1位:1
disp_pw:LED表示位置を算出するときに使用するワークエリアです。
disp_data:LED表示処理で表示データを一時格納するエリアです。PORTCの処理を共通化するために設けています。
disp_h10w:時10位の内容を処理するためのワークエリアです。
disp_h10:時10位のデータを格納するエリアです。
disp_h1:時1位のデータを格納するエリアです。
disp_m10:分10位のデータを格納するエリアです。
disp_m1:分1位のデータを格納するエリアです。
disp_s10:秒10位のデータを格納するエリアです。
disp_s1:秒1位のデータを格納するエリアです。
mode: 時計モード、時刻設定モードの識別データを格納するエリアです。
時計モード:1、時刻設定モード:0
rb6ll:RB6(0秒設定/時刻設定解除スイッチ)の変化を検出するために使用します。
rb7ll:RB7(時刻設定桁変更スイッチ)の変化を検出するために使用します。
rb7count:RB7(時刻設定要求スイッチ)が2秒間ONであることを検出するためのカウンタです。
digit_posi: 時刻設定桁指定データを格納します。
時10位:0、時1位:1、分10位:2、分1位:3
digit_posiw:時刻設定桁を算出するために使用するワークエリアです。
digit_save:時刻設定モードのとき、該当する桁の数字を点滅させます。表示データを一時格納するエリアです。
digit_blink:時刻設定モードで点灯/消灯時間をカウントするカウンタです。20ミリ秒を10回カウントして200ミリ秒を作ります。
blink_cont:時刻設定モードでの指定桁点滅で、点灯か消灯かのデータを格納するエリアです。
change_st:ロータリエンコーダによるアップ/ダウン検出をするための状態管理エリアです。
change_wk:ロータリエンコーダ入力(RB4,RB5)を一時格納するエリアです。
seg7_ha:7セグメントLED制御データテーブルの先頭アドレスを格納するエリアです。
seg70-7b:7セグメントLED制御データを格納するエリアです。




環境指定 他
    LIST および INCLUDE疑似命令プログラム開始については「ライト・コントローラー」を参照して下さい。

    コンフィグレーションワードとして以下を指定しています。
    発振器の種類HS
    ウォッチドッグタイマーOFF
    パワーアップタイマー使用する
    低電圧プログラミング OFF
    (これをOFFにしないとRB3を入出力ポートに使用できません)

    結果は3F72hです。





初期化処理
;****************  Initial Process  *********************
    ポート初期化
      PIC16F873のRAポートはアナログ入力/デジタル入出力が兼用されています。RAポートをデジタル入出力モードにするためにはADCON1でデジタル指定する必要があります。RA、RB、RCに必要な入出力モードを設定します。

    LED表示周期タイマの初期化
      タイマー0を1ミリ秒周期に設定します。今回はクロックとして4MHzを使用しているので、タイマーのカウントは1マイクロ秒毎に行われます。プリスケーラを1:8にしているので、実際には8マイクロ秒毎にカウントされます。125回カウントすれば1ミリ秒になります。タイマー0はカウントアップタイマーでFFhから00hになるときにタイムアウト割り込みが発生します。ですから、TMR0への設定値は256から希望するカウント値を引いた値を設定します。256−125=131が設定値になります。

    ポート初期化
      ポートの出力状態を初期化します。
      PORTCはLED制御に使用していて、"1"を出力するとLEDが消える回路にしています。

    ワークエリア初期化
      disp_pは時10位から制御するように初期値を6にしています。0を設定しても問題はありません。他のワークアリアは0を設定しています。
      モードデータは0で時刻設定モードなので、初期化した後は時刻設定モードになります。要は電源を入れた時には時刻設定モードで動作することになります。
      ワークエリア初期化では7セグメントLED用のデータもワークエリアに設定しています。

    割り込み初期化
      GIE、T0IE、INTE、RBIEを設定しています。

    割り込み待ち処理
      処理というほどではないのですが、初期化処理が終わった後は割り込みを待つだけです。同じアドレスの処理を繰り返し実行させています。




LED表示処理
;*********  LED disply Process (1msec interval) *********
    1ミリ秒周期でLEDを1桁づつ点灯します。残像が残らないように最初にLEDを消しています。disp_pの内容をチェックして制御する桁を決めます。時10位の処理は少し複雑で、AM/PMと時10位に1を設定するか消すかの制御を行っています。
    時刻設定モードで時10位に消灯データ(0Ah)が入っている場合には特に制御は行いません。先頭で消灯処理を行っているからです。



時計処理
;******  Clock count up Process (20msec interval) *******
    この処理は外部クロックにより20ミリ秒毎に起動されます。起動されると時計更新の前に以下の処理を行います。
    時刻設定モードチェック
      時刻設定モードの場合、時計処理は行わず、時刻設定処理にジャンプします。

    0秒設定チェック
      時計モードで0秒スイッチが押されていることを検出すると、秒表示を00秒にします。この処理は20ミリ秒毎に行われるので、最大20ミリ秒の誤差が生じますが、実質的には問題ないと思います。
      0秒設定スイッチはラストルック監視をしています。スイッチONを検出する前の状態がOFFの場合だけ0秒設定処理を行います。スイッチが連続的に押されていても、最初の変化以降のON状態は0秒設定に影響ないようにしています。

    時刻設定要求チェック
      時計モードで時刻設定スイッチを2秒間連続して押されている場合、時刻設定処理にジャンプします。2秒の監視はカウンタにより監視しています。
      時刻設定処理を行う前に、変更桁を時10位にし、秒を00秒にし、さらにRBポートの変化検出割り込みを可能にしています。RB変化検出はロータリーエンコーダからの入力を取り込むためです。RB7LLを1にしているのは時刻設定モードになるときに桁位置が変化しないようにするためです。

    1秒カウントチェック
      この処理は20ミリ秒毎に起動されるので、カウンタを使って1秒を監視しています。1秒経つと時計更新処理に入ります。
上記のチェックで時刻設定モードでなく、1秒が経過した時に時計の更新が行われます。各桁は最大数から0になるときに桁上げが行われます。
今回の処理では少し凝ってAM11:59からPM12:00へ、PM11:59からAM0:00にしています。



時報制御
;*** Time signal check
    時計更新で時1位が更新される都度、時報のチェックをしています。
    今回の処理では以下の8種類を時報にしています。
    AM7:00AM9:00PM6:00PM8:00
    AM8:00AM10:00PM7:00PM9:00

この時刻になると時報信号としてRB1をONにして時報回路を動作させます。RB1のOFFは1秒後に行われます。1秒の更新時にはいつも時報信号をOFFにしています。



時刻設定処理
;****** Time adjust mode Process (20msec interval) ******
    時刻設定処理は外部クロックにより20ミリ秒毎に起動されます。
    時刻設定解除
      0秒設定SWを押すと時刻設定モードが解除されます。
      時刻設定解除処理では設定対象桁を200ミリ秒周期で点滅させているので、表示が消えている可能性があります。ですから、表示エリアにデータを再設定しています。また、RBの変化割り込みをOFFにしています。

    変更桁指定
      桁指定スイッチ(RB7)を押す都度、設定対象桁を移動しています。
      設定できる桁は時/分のみで、秒の設定はしていません。時刻設定の時は常に0秒になります。
      表示の点滅処理のために対象桁のデータをセーブしています。移動前の桁の表示が消えている場合には、表示を戻してから移動後の桁のデータをセーブしています。

    表示点滅
      設定対象桁を200ミリ秒周期で点滅させています。消灯するためにはLEDの全セグメントを消せば良いのですが、点灯するためには元のデータをセーブしておく必要があります。digit_saveはそのためのエリアです。



時刻変更処理
;**************** Digit change process ******************
    時刻データの変更はロータリエンコーダで行います。
    ロータリエンコーダには2つの出力(A,B)があり、それぞれのONするタイミングが右回転の場合と、左回転の場合とで異なっています。
    今回の処理では状態管理データを使って、右回転、左回転の判断をしています。
    ここでONは「1」、OFFは「0」です。
    状態0A:ON、B:OFFを検出
    状態1A:OFF、B:ONを検出
    状態2A:ON、B:ONを検出

    A:OFF、B:OFFの状態は管理していません。AとBが両方ONになる直前の状態が分かれば良いからです。

状態遷移図で表すと左図のようになります。

状態0でA=ON、B=ONを検出すると、右回転で設定対象桁の数字を増加させます。状態1でA=ON、B=ONを検出すると、左回転で数字を減少させます。
ロータリエンコーダの出力にはチャッタリング(ONまたはOFFになるときにON/OFFを繰り返す現象)が発生します。しかし、今回のような状態管理を行えば問題はありません。




チャッタリングを想定したときの信号変化と状態遷移の関係を左図に示します。