;------------------------------------------------------------------------------
; clock.asm	タイマー時計
;------------------------------------------------------------------------------
; バージョン履歴
;
; Ver.1.01 2007/7/7
;  DPフラグの秒判定ルーチンを変更(秒によってちらつきが出たため)
;
; Ver.1.00 2007/5/21
;  完成
;  デバッグルーチン廃止。
;
; Ver.0.03 2007/5/17
;  時間設定はできないが、時計として動作するようになった。
;  キー入力をLEDに反映させた。
;
; Ver.0.02 2007/5/6
;  動作確認のためにLEDとスイッチのチェックプログラムを作成。
;  キー入力によるデバッグ分岐を作成。
;
; Ver.0.01 2007/5/4
;  基板完成、ケースに組み込み単体チェック。
;
; Ver.0.00 2007/3/11
;  基板完成、ケースに組み込み単体チェック。
;  LED付きスイッチの逆電流問題が勃発。基板の再設計を余儀なくされる。

;------------------------------------------------------------------------------
; デバイス	PIC16F873,873A,876,876A
; 動作周波数	32.768kHz
;------------------------------------------------------------------------------
	LIST		P=PIC16F873A,R=DEC,N=0
	INCLUDE		"P16F873A.INC"
	ERRORLEVEL	0,-302,-306,-307
	__CONFIG	0x3F70
;------------------------------------------------------------------------------
; 変数宣言
;------------------------------------------------------------------------------
SECOND		EQU	0x20		; 秒 時計用
MINUTE		EQU	0x21		; 分 時計用
HOUR		EQU	0x22		; 時 時計用
OFF_MINUTE	EQU	0x23		; OFFタイマ 分設定
OFF_HOUR	EQU	0x24		; OFFタイマ 時設定
ON_MINUTE	EQU	0x25		; ONタイマ  分設定
ON_HOUR		EQU	0x26		; ONタイマ  時設定

MINUTE_1	EQU	0x27		; LED 分 1位  ワークエリア
MINUTE_10	EQU	0x28		; LED 分 10位 ワークエリア
HOUR_1		EQU	0x29		; LED 時 1位  ワークエリア
HOUR_10		EQU	0x2A		; LED 時 10位 ワークエリア

LED_INDEX	EQU	0x2B		; 7セグデータをロードするときのインデックス
CONV_60		EQU	0x2C		; 60進数変換数値
KEY		EQU	0x2D		; キー入力フラグ
KEY_CMP1	EQU	0x2E		; キー照合バッファ(現在の入力)
KEY_CMP2	EQU	0x2F		; キー照合バッファ(過去の入力)
MODE		EQU	0x30		; 表示モード
KEY_WAIT	EQU	0x31		; 時間設定後のウエイト
DEF_KEY_WAIT	EQU	0x32		; 
FLAG		EQU	0x33		; <0>SECOND_05 0.5秒カウントフラグ
					; <1>UPDATE_M LEDの分表示のアップデートが必要
					; <2>UPDATE_H LEDの時表示のアップデートが必要
					; <3>TRIG_DEMAND トリガーON要求
DP_FLAG		EQU	0x34		; <0>DP_0 1桁目のDPを点灯
					; <1>DP_1 2桁目のDPを点灯
					; <2>DP_2 3桁目のDPを点灯
					; <3>DP_3 4桁目のDPを点灯

TMP01		EQU	0x35		; ウエイトカウンタ
TMP00		EQU	0x36		; 60進→10進変換で使用

;------------------------------------------------------------------------------
; 定数宣言
;------------------------------------------------------------------------------
SECOND_05	EQU	0		; FLAG-0 0.5秒間隔フラグ
UPDATE_M	EQU	1		; FLAG-1 LEDの分表示のアップデートが必要
UPDATE_H	EQU	2		; FLAG-2 LEDの時表示のアップデートが必要
TRIG_DEMAND	EQU	3		; FLAG-3 トリガーON要求

DP_0		EQU	0		; DP_FLAG-0 1桁目のDPを点灯
DP_1		EQU	1		; DP_FLAG-1 2桁目のDPを点灯
DP_2		EQU	2		; DP_FLAG-2 3桁目のDPを点灯
DP_3		EQU	3		; DP_FLAG-3 4桁目のDPを点灯

LED1		EQU	0		; PORTA-0 LED桁選択出力 一番右
LED2		EQU	1		; PORTA-1 LED桁選択出力 右
LED3		EQU	2		; PORTA-2 LED桁選択出力 左
LED4		EQU	3		; PORTA-3 LED桁選択出力 一番左
SWLED1		EQU	4		; PORTA-4 /SW-LED出力 上段
SWLED2		EQU	5		; PORTA-5 /SW-LED出力 下段

MINUTE_SW	EQU	0		; PORTB-0 /SW入力 分
HOUR_SW		EQU	1		; PORTB-1 /SW入力 時
RESET_SW	EQU	2		; PORTB-2 /SW入力 リセット
OFF_SW		EQU	3		; PORTB-3 /SW入力 OFFタイマ設定
ENABLE_SW	EQU	4		; PORTB-4 /SW入力 タイマ有効
ON_SW		EQU	5		; PORTB-5 /SW入力 ONタイマ設定
SSR_OUT		EQU	6		; PORTB-6 /SSR ON出力
TRIG_OUT	EQU	7		; PORTB-7 /トリガー出力

SEG_A		EQU	0		; PORTC-0 /7セグメント出力 A
SEG_B		EQU	1		; PORTC-1 /7セグメント出力 B
SEG_C		EQU	2		; PORTC-2 /7セグメント出力 C
SEG_D		EQU	3		; PORTC-3 /7セグメント出力 D
SEG_E		EQU	4		; PORTC-4 /7セグメント出力 E
SEG_F		EQU	5		; PORTC-5 /7セグメント出力 F
SEG_G		EQU	6		; PORTC-6 /7セグメント出力 G
SEG_DP		EQU	7		; PORTC-7 /7セグメント出力 .

EEP_KEY_WAIT	EQU	0x00		; KEY_WAITの定数アドレス

;------------------------------------------------------------------------------
; メインプログラム
;------------------------------------------------------------------------------
		ORG	0

;------------------------------------------------------------------------------
; 電源投入時の初期化
;------------------------------------------------------------------------------
POWER_ON				; 電源ON
	CALL	startup_sequence	; メインループのサイズ制限があるため、
					; スタートアップを別のアドレスに置いて実行

;------------------------------------------------------------------------------
; ループ前処理
;------------------------------------------------------------------------------
	CLRF	TMR0			; TMR0初期化

;------------------------------------------------------------------------------
; メインループ
;------------------------------------------------------------------------------
MAINLOOP
KEY_INPUT
	MOVF	KEY_CMP1,W		; 前回のキー入力をバックアップ
	MOVWF	KEY_CMP2
	COMF	PORTB,W			; 現在の状態を入力
	MOVWF	KEY_CMP1
	ANDWF	KEY_CMP2,W		; 前回の入力とANDをとる(チャタリング防止)
	MOVWF	KEY			; 結果

	MOVF	KEY_WAIT,W		; キーウェイトの残ループチェック
	BTFSC	STATUS,Z		; HOUR,MINUTE,RESETを押した場合は、
	GOTO	MODE_CHECK		; 次のループで3つのキーを無効にする。
	DECF	KEY_WAIT,F		; 残ループ-1
	MOVLW	B'11111000'		; 3つのキーをフィルタ
	ANDWF	KEY,F

MODE_CHECK
	MOVF	MODE,W			; 前回のモードをバックアップ
	CLRF	MODE			; モードの作成
	BTFSC	KEY,OFF_SW		; 0-通常 1-OFFタイマ設定 2-ONタイマ設定 3-時間設定
	BSF	MODE,0
	BTFSC	KEY,ON_SW
	BSF	MODE,1
	SUBWF	MODE,W			; 前回のモードと一致しない場合は、
	BTFSC	STATUS,Z		; 時間表示を強制アップデートする
	GOTO	GOTO_MODE
	BSF	FLAG,UPDATE_M
	BSF	FLAG,UPDATE_H

GOTO_MODE				; モードごとのルーチンへ分岐
	MOVF	MODE,W
	ADDWF	PCL,F
	GOTO	MODE_NORMAL		; モード0の時 通常表示
	GOTO	MODE_OFFSET		; モード1の時 OFFタイマ設定
	GOTO	MODE_ONSET		; モード2の時 ONタイマ設定
	GOTO	MODE_TIMESET		; モード3の時 時間設定

;------------------------------------------------------------------------------
; 通常表示
;------------------------------------------------------------------------------
MODE_NORMAL
SW_NORMAL				; スイッチの処理
	MOVLW	B'00000011'		; HOUR,MINUTE以外をマスクして入力
	ANDWF	KEY,W
	ADDWF	PCL,F			; スイッチの状態に応じて処理を分岐
	GOTO	SWLED_NORMAL		; 0の時 処理なし
	GOTO	SW_NORMAL_SSROFF	; 1の時 SSR OFF
	GOTO	SW_NORMAL_SSRON		; 2の時 SSR ON
	GOTO	SWLED_NORMAL		; 3(同時押し)の時 処理なし

SW_NORMAL_SSROFF
	MOVLW	B'11000000'		; SSR,トリガーOFF
	MOVWF	PORTB
	GOTO	SWLED_NORMAL
SW_NORMAL_SSRON
	MOVLW	B'10000000'		; SSR ON
	MOVWF	PORTB
	BSF	FLAG,TRIG_DEMAND	; トリガー予定

SWLED_NORMAL				; スイッチLEDの処理
	MOVLW	B'00010001'		; 仮でSSRがOFFしている時のパターンをロード
	BTFSS	PORTB,SSR_OUT		; SSRがONの時は
	MOVLW	B'00100001'		; HOURのLEDをON
	MOVWF	PORTA
	MOVLW	2
	CALL	wait
	BTFSS	KEY,ENABLE_SW		; タイマーイネーブルの時は
	GOTO	SWLED_NORMAL_2
	MOVLW	B'00010100'		; イネーブルのLEDをON
	MOVWF	PORTA
	MOVLW	1			; 赤LEDは明るいのでウエイトは1でよい
	CALL	wait
SWLED_NORMAL_2
	MOVLW	B'00110000'		; LEDオールオフ
	MOVWF	PORTA

DISPLED_NORMAL				; 数値LEDのアップデートチェック
DISPLED_NORMAL_CHECK_M
	BTFSS	FLAG,UPDATE_M		; 分LEDのアップデートをチェック
	GOTO	DISPLED_NORMAL_CHECK_H
	BCF	FLAG,UPDATE_M		; 分表示のアップデートチェックをクリア
	MOVF	MINUTE,W		; 分を60進→10進変換
	MOVWF	CONV_60
	MOVLW	MINUTE_10
	MOVWF	FSR
	CALL	devide
DISPLED_NORMAL_CHECK_H
	BTFSS	FLAG,UPDATE_H		; 時LEDのアップデートをチェック
	GOTO	DISPLED_NORMAL_EXEC
	BCF	FLAG,UPDATE_H		; 時表示のアップデートチェックをクリア
	MOVF	HOUR,W			; 時を60進→10進変換
	MOVWF	CONV_60
	MOVLW	HOUR_10
	MOVWF	FSR
	CALL	devide
DISPLED_NORMAL_EXEC			; 数値LED表示へ
	GOTO	DISP_LED

;------------------------------------------------------------------------------
; OFFタイマ設定
;------------------------------------------------------------------------------
MODE_OFFSET				; OFFタイマ設定
SW_OFFSET				; スイッチの処理
	MOVLW	B'00000111'		; HOUR,MINUTE以外をマスクして入力
	ANDWF	KEY,W
	ADDWF	PCL,F			; スイッチの状態に応じて処理を分岐
	GOTO	SWLED_OFFSET		; 0の時 処理なし
	GOTO	SW_OFFSET_MINUTE	; 1の時 分セット
	GOTO	SW_OFFSET_HOUR		; 2の時 時セット
	GOTO	SWLED_OFFSET		; 3(同時押し)の時 処理なし
	GOTO	SW_OFFSET_RESET		; 4の時 分リセット
	GOTO	SWLED_OFFSET		; 5(同時押し)の時 処理なし
	GOTO	SWLED_OFFSET		; 6(同時押し)の時 処理なし
	GOTO	SWLED_OFFSET		; 7(同時押し)の時 処理なし

SW_OFFSET_MINUTE
	INCF	OFF_MINUTE,F		; OFF分をインクリメント
	MOVLW	60			; 60分になった？
	SUBWF	OFF_MINUTE,W
	BTFSC	STATUS,Z
	CLRF	OFF_MINUTE		; OFF分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート
	GOTO	SWLED_OFFSET
SW_OFFSET_HOUR
	INCF	OFF_HOUR,F		; OFF時をインクリメント
	MOVLW	24			; 24時になった？
	SUBWF	OFF_HOUR,W
	BTFSC	STATUS,Z
	CLRF	OFF_HOUR		; OFF時をクリア
	BSF	FLAG,UPDATE_H		; 表示アップデート
	GOTO	SWLED_OFFSET
SW_OFFSET_RESET
	CLRF	OFF_MINUTE		; OFF分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート

SWLED_OFFSET				; スイッチLEDの処理
	MOVLW	B'00000001'		; H,Mを点灯
	MOVWF	PORTA
	MOVLW	2
	CALL	wait
	MOVLW	B'00000010'		; OFF-T,RESETを点灯
	BTFSC	FLAG,SECOND_05		; OFF-T LEDを0.5秒ごとに点滅させる
	MOVLW	B'00010010'		; OFF-Tを消灯,RESETを点灯
	MOVWF	PORTA
	MOVLW	1			; 緑LEDは明るいのでウエイトは1でよい
	CALL	wait
	BTFSS	KEY,ENABLE_SW		; タイマーイネーブルの時は
	GOTO	SWLED_OFFSET_2
	MOVLW	B'00010100'		; ENABLEのLEDを0.5秒ごとに点滅させる
	BTFSC	FLAG,SECOND_05
	MOVLW	B'00110000'
	MOVWF	PORTA
	MOVLW	1			; 赤、緑LEDは明るいのでウエイトは1でよい
	CALL	wait
SWLED_OFFSET_2
	MOVLW	B'00110000'		; LEDオールオフ
	MOVWF	PORTA

DISPLED_OFFSET				; 数値LEDのアップデートチェック
DISPLED_OFFSET_CHECK_M
	BTFSS	FLAG,UPDATE_M		; 分LEDのアップデートをチェック
	GOTO	DISPLED_OFFSET_CHECK_H
	BCF	FLAG,UPDATE_M		; 分表示のアップデートチェックをクリア
	MOVF	OFF_MINUTE,W		; 分を60進→10進変換
	MOVWF	CONV_60
	MOVLW	MINUTE_10
	MOVWF	FSR
	CALL	devide
DISPLED_OFFSET_CHECK_H
	BTFSS	FLAG,UPDATE_H		; 時LEDのアップデートをチェック
	GOTO	DISPLED_OFFSET_EXEC
	BCF	FLAG,UPDATE_H		; 時表示のアップデートチェックをクリア
	MOVF	OFF_HOUR,W		; 時を60進→10進変換
	MOVWF	CONV_60
	MOVLW	HOUR_10
	MOVWF	FSR
	CALL	devide
DISPLED_OFFSET_EXEC			; 数値LED表示へ
	GOTO	DISP_LED

;------------------------------------------------------------------------------
; ONタイマ設定
;------------------------------------------------------------------------------
MODE_ONSET
SW_ONSET				; スイッチの処理
	MOVLW	B'00000111'		; HOUR,MINUTE以外をマスクして入力
	ANDWF	KEY,W
	ADDWF	PCL,F			; スイッチの状態に応じて処理を分岐
	GOTO	SWLED_ONSET		; 0の時 処理なし
	GOTO	SW_ONSET_MINUTE		; 1の時 分セット
	GOTO	SW_ONSET_HOUR		; 2の時 時セット
	GOTO	SWLED_ONSET		; 3(同時押し)の時 処理なし
	GOTO	SW_ONSET_RESET		; 4の時 分リセット
	GOTO	SWLED_ONSET		; 5(同時押し)の時 処理なし
	GOTO	SWLED_ONSET		; 6(同時押し)の時 処理なし
	GOTO	SWLED_ONSET		; 7(同時押し)の時 処理なし

SW_ONSET_MINUTE
	INCF	ON_MINUTE,F		; ON分をインクリメント
	MOVLW	60			; 60分になった？
	SUBWF	ON_MINUTE,W
	BTFSC	STATUS,Z
	CLRF	ON_MINUTE		; ON分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート
	GOTO	SWLED_ONSET
SW_ONSET_HOUR
	INCF	ON_HOUR,F		; ON時をインクリメント
	MOVLW	24			; 24時になった？
	SUBWF	ON_HOUR,W
	BTFSC	STATUS,Z
	CLRF	ON_HOUR			; ON時をクリア
	BSF	FLAG,UPDATE_H		; 表示アップデート
	GOTO	SWLED_ONSET
SW_ONSET_RESET
	CLRF	ON_MINUTE		; ON分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート

SWLED_ONSET				; スイッチLEDの処理
	MOVLW	B'00000001'		; H,Mを点灯
	MOVWF	PORTA
	MOVLW	2
	CALL	wait
	MOVLW	B'00010010'		; OFF-Tを消灯,RESETを点灯
	MOVWF	PORTA
	MOVLW	2
	CALL	wait
	MOVLW	B'00100100'		; 仮でENABLEがOFFしている時のパターンをロード
	BTFSS	PORTB,ENABLE_SW		; タイマーイネーブルの時は
	MOVLW	B'00000100'		; ENABLEのLEDを0.5秒ごとに点滅させる
	BTFSC	FLAG,SECOND_05		; ON-T LEDを0.5秒ごとに点滅させる
	MOVLW	B'00110000'
	MOVWF	PORTA
	MOVLW	1			; 赤、緑LEDは明るいのでウエイトは1でよい
	CALL	wait
	MOVLW	B'00110000'		; LEDオールオフ
	MOVWF	PORTA

DISPLED_ONSET				; 数値LEDのアップデートチェック
DISPLED_ONSET_CHECK_M
	BTFSS	FLAG,UPDATE_M		; 分LEDのアップデートをチェック
	GOTO	DISPLED_ONSET_CHECK_H
	BCF	FLAG,UPDATE_M		; 分表示のアップデートチェックをクリア
	MOVF	ON_MINUTE,W		; 分を60進→10進変換
	MOVWF	CONV_60
	MOVLW	MINUTE_10
	MOVWF	FSR
	CALL	devide
DISPLED_ONSET_CHECK_H
	BTFSS	FLAG,UPDATE_H		; 時LEDのアップデートをチェック
	GOTO	DISPLED_ONSET_EXEC
	BCF	FLAG,UPDATE_H		; 時表示のアップデートチェックをクリア
	MOVF	ON_HOUR,W			; 時を60進→10進変換
	MOVWF	CONV_60
	MOVLW	HOUR_10
	MOVWF	FSR
	CALL	devide
DISPLED_ONSET_EXEC			; 数値LED表示へ
	GOTO	DISP_LED

;------------------------------------------------------------------------------
; 時刻設定
;------------------------------------------------------------------------------
MODE_TIMESET
SW_TIMESET				; スイッチの処理
	MOVLW	B'00000111'		; HOUR,MINUTE以外をマスクして入力
	ANDWF	KEY,W
	ADDWF	PCL,F			; スイッチの状態に応じて処理を分岐
	GOTO	SWLED_TIMESET		; 0の時 処理なし
	GOTO	SW_TIMESET_MINUTE	; 1の時 分セット+秒クリア
	GOTO	SW_TIMESET_HOUR		; 2の時 時セット
	GOTO	SWLED_TIMESET		; 3(同時押し)の時 処理なし
	GOTO	SW_TIMESET_RESET	; 4の時 分リセット+秒クリア
	GOTO	SWLED_TIMESET		; 5(同時押し)の時 処理なし
	GOTO	SWLED_TIMESET		; 6(同時押し)の時 処理なし
	GOTO	SWLED_TIMESET		; 7(同時押し)の時 処理なし

SW_TIMESET_MINUTE
	CLRF	TMR0			; TMR0初期化
	BCF	FLAG,SECOND_05		; 0.5秒フラグクリア
	CLRF	SECOND			; 秒初期化
	INCF	MINUTE,F		; 分をインクリメント
	MOVLW	60			; 60分になった？
	SUBWF	MINUTE,W
	BTFSC	STATUS,Z
	CLRF	MINUTE			; 分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート
	GOTO	SWLED_TIMESET
SW_TIMESET_HOUR
	INCF	HOUR,F			; 時をインクリメント
	MOVLW	24			; 24時になった？
	SUBWF	HOUR,W
	BTFSC	STATUS,Z
	CLRF	HOUR			; ON時をクリア
	BSF	FLAG,UPDATE_H		; 表示アップデート
	GOTO	SWLED_TIMESET
SW_TIMESET_RESET
	CLRF	TMR0			; TMR0初期化
	BCF	FLAG,SECOND_05		; 0.5秒フラグクリア
	CLRF	SECOND			; 秒初期化
	CLRF	MINUTE			; 分をクリア
	BSF	FLAG,UPDATE_M		; 表示アップデート

SWLED_TIMESET				; スイッチLEDの処理
	MOVLW	B'00000001'		; H,Mを点灯
	MOVWF	PORTA
	MOVLW	2
	CALL	wait
	MOVLW	B'00000010'		; OFF-T,RESETを点灯
	BTFSC	FLAG,SECOND_05		; OFF-T LEDを0.5秒ごとに点滅させる
	MOVLW	B'00010010'		; OFF-Tを消灯,RESETを点灯
	MOVWF	PORTA
	MOVLW	1			; 緑LEDは明るいのでウエイトは1でよい
	CALL	wait
	MOVLW	B'00100100'		; 仮でENABLEがOFFしている時のパターンをロード
	BTFSS	PORTB,ENABLE_SW		; タイマーイネーブルの時はENABLEのLEDを0.5秒ごとに点滅させる
	MOVLW	B'00000100'
	BTFSC	FLAG,SECOND_05		; ON-T LEDを0.5秒ごとに点滅させる
	MOVLW	B'00110000'
	MOVWF	PORTA
	MOVLW	1			; 赤、緑LEDは明るいのでウエイトは1でよい
	CALL	wait
	MOVLW	B'00110000'		; LEDオールオフ
	MOVWF	PORTA

DISPLED_TIMESET				; 数値LEDのアップデートチェック
DISPLED_TIMESET_CHECK_M
	BTFSS	FLAG,UPDATE_M		; 分LEDのアップデートをチェック
	GOTO	DISPLED_TIMESET_CHECK_H
	BCF	FLAG,UPDATE_M		; 分表示のアップデートチェックをクリア
	MOVF	MINUTE,W		; 分を60進→10進変換
	MOVWF	CONV_60
	MOVLW	MINUTE_10
	MOVWF	FSR
	CALL	devide
DISPLED_TIMESET_CHECK_H
	BTFSS	FLAG,UPDATE_H		; 時LEDのアップデートをチェック
	GOTO	DISPLED_TIMESET_EXEC
	BCF	FLAG,UPDATE_H		; 時表示のアップデートチェックをクリア
	MOVF	HOUR,W			; 時を60進→10進変換
	MOVWF	CONV_60
	MOVLW	HOUR_10
	MOVWF	FSR
	CALL	devide
DISPLED_TIMESET_EXEC			; 数値LED表示へ

;------------------------------------------------------------------------------
; 時間LED表示
;------------------------------------------------------------------------------
DISP_LED
DISPLED_MINUTE_1
	MOVF	MINUTE_1,W		; LEDパターンをロード
	MOVWF	LED_INDEX
	CALL	load_led
	BTFSS	DP_FLAG,DP_0		; DPのフラグがセットされていない場合はDPを消灯する
	BSF	PORTC,SEG_DP
	MOVLW	B'00110001'
	MOVWF	PORTA
	MOVLW	1
	CALL	wait
	MOVLW	B'00110000'
	MOVWF	PORTA
DISPLED_MINUTE_10
	MOVF	MINUTE_10,W		; LEDパターンをロード
	MOVWF	LED_INDEX
	CALL	load_led
	BTFSS	DP_FLAG,DP_1		; DPのフラグがセットされていない場合はDPを消灯する
	BSF	PORTC,SEG_DP
	MOVLW	B'00110010'
	MOVWF	PORTA
	MOVLW	1
	CALL	wait
	MOVLW	B'00110000'
	MOVWF	PORTA
DISPLED_HOUR_1
	MOVF	HOUR_1,W		; LEDパターンをロード
	MOVWF	LED_INDEX
	CALL	load_led
	BTFSS	DP_FLAG,DP_2		; DPのフラグがセットされていない場合はDPを消灯する
	BSF	PORTC,SEG_DP
	MOVLW	B'00110100'
	MOVWF	PORTA
	MOVLW	1
	CALL	wait
	MOVLW	B'00110000'
	MOVWF	PORTA
DISPLED_HOUR_10
	MOVF	HOUR_10,W		; LEDパターンをロード
	BTFSC	STATUS,Z		; 数字が0の時はスペースに置き換える
	MOVLW	10
	MOVWF	LED_INDEX
	CALL	load_led
	BTFSS	DP_FLAG,DP_3		; DPのフラグがセットされていない場合はDPを消灯する
	BSF	PORTC,SEG_DP
	MOVLW	B'00111000'
	MOVWF	PORTA
	MOVLW	1
	CALL	wait
	MOVLW	B'00110000'
	MOVWF	PORTA

	MOVLW	B'11111111'		; SW-LED点灯の邪魔になるので処理しておく
	MOVWF	PORTC

;------------------------------------------------------------------------------
; 時間カウント/タイマ実行
;------------------------------------------------------------------------------
TIME_COUNT				; タイマーのポーリング
	BTFSS	INTCON,T0IF		; タイマーのロールオーバーが発生したか？
	GOTO	COUNT_END		; 割り込みは使わず500ms以内にポーリングする
	BCF	INTCON,T0IF		; フラグクリア
	BTFSS	FLAG,SECOND_05		; 0.5秒カウントチェック
	GOTO	COUNT_05		; 0の時0.5カウントへ

	BCF	FLAG,SECOND_05		; 1の時1秒カウントアップ
	BSF	PORTB,TRIG_OUT		; トリガーOFF
	INCF	SECOND,F		; +1秒

	MOVLW	60			; 秒数が60の時、分カウントへ
	SUBWF	SECOND,W
	BTFSC	STATUS,Z
	GOTO	MIN_COUNT
DP_COUNT0				; 秒数は30以上？
	MOVLW	30
	SUBWF	SECOND,W
	BTFSC	STATUS,C
	GOTO	DP_COUNT2
DP_COUNT1				; 秒数が15以上？
	MOVLW	15
	SUBWF	SECOND,W
	MOVLW	B'00000001'		; 15未満の時のフラグ状態
	BTFSC	STATUS,C
	MOVLW	B'00000010'		; 15以上の時のフラグ状態
	MOVWF	DP_FLAG
	GOTO	COUNT_END
DP_COUNT2				; 秒数が45以上？
	MOVLW	45
	SUBWF	SECOND,W
	MOVLW	B'00000100'		; 45未満の時のフラグ状態
	BTFSC	STATUS,C
	MOVLW	B'00001000'		; 45以上の時のフラグ状態
	MOVWF	DP_FLAG
	GOTO	COUNT_END

MIN_COUNT				; 秒数が60の時
	BSF	FLAG,UPDATE_M		; 分表示のアップデートが必要
	MOVLW	B'00000001'		; 60秒の時は0と同じDPを点灯する
	MOVWF	DP_FLAG
	CLRF	SECOND			; 秒をクリアして
	INCF	MINUTE,F		; +1分
	MOVLW	60			; 60分のロールがあったか？
	SUBWF	MINUTE,W
	BTFSS	STATUS,Z
	GOTO	TIMER_CHK		; タイマー発動のチェック

	BSF	FLAG,UPDATE_H		; 時表示のアップデートが必要
	CLRF	MINUTE			; 分をクリアして
	INCF	HOUR,F			; +1時間
	MOVLW	24			; 24時間のロールがあったか？
	SUBWF	HOUR,W
	BTFSS	STATUS,Z
	GOTO	TIMER_CHK

	CLRF	HOUR			; 1時間カウンタをクリアする
TIMER_CHK				; タイマー発動のチェック
	BTFSS	KEY,ENABLE_SW		; タイマーイネーブルがOFFの時はタイマを実行しない
	GOTO	COUNT_END
TIMER_CHK_OFF
	MOVF	MINUTE,W		; 現在の分とOFFタイマの分を比較
	SUBWF	OFF_MINUTE,W
	BTFSS	STATUS,Z		; 一致しない場合はONタイマへ
	GOTO	TIMER_CHK_ON
	MOVF	HOUR,W			; 現在の時とOFFタイマの時を比較
	SUBWF	OFF_HOUR,W
	BTFSS	STATUS,Z		; 一致しない場合はONタイマへ
	GOTO	TIMER_CHK_ON
	MOVLW	B'11000000'		; SSR,トリガーOFF
	MOVWF	PORTB
	GOTO	COUNT_END
TIMER_CHK_ON
	MOVF	MINUTE,W		; 現在の分とONタイマの分を比較
	SUBWF	ON_MINUTE,W
	BTFSS	STATUS,Z		; 一致しない場合はタイマ非動作
	GOTO	COUNT_END
	MOVF	HOUR,W			; 現在の時とONタイマの時を比較
	SUBWF	ON_HOUR,W
	BTFSS	STATUS,Z		; 一致しない場合はタイマ非動作
	GOTO	COUNT_END
	MOVLW	B'10000000'		; SSR ON
	MOVWF	PORTB
	BSF	FLAG,TRIG_DEMAND
	GOTO	COUNT_END

COUNT_05				; 0.5秒カウント
	BSF	FLAG,SECOND_05		; フラグをセットする
	BTFSC	FLAG,TRIG_DEMAND	; トリガーON要求のチェック
	BCF	PORTB,TRIG_OUT		; トリガーON
	BCF	FLAG,TRIG_DEMAND	; トリガーON要求のクリア

COUNT_END				; カウント部終了
	MOVLW	B'00000111'		; HOUR,MINUTE,RESETを押した場合は、
	ANDWF	KEY,W			; 次のループで3つのキーを無効にする。
	BTFSC	STATUS,Z
	GOTO	MAINLOOP

	MOVF	DEF_KEY_WAIT,W
	MOVWF	KEY_WAIT
	GOTO	MAINLOOP

;------------------------------------------------------------------------------
; サブルーチン群
;------------------------------------------------------------------------------
startup_sequence			; スタートアップシーケンス
	MOVLW	B'00110000'		; I/O初期化
	MOVWF	PORTA			; 負論理動作のビットを立てておく
	MOVLW	B'11000000'
	MOVWF	PORTB
	MOVLW	B'11111111'
	MOVWF	PORTC

	BSF	STATUS,RP0
	CLRF	TRISA			; RA[0-3]LED桁選択 RA[45]SW-LED選択
	MOVLW	B'00111111'		; RB[0-5]SW入力 RB[6]SSR出力 RB[7]トリガー出力
	MOVWF	TRISB
	CLRF	TRISC			; RC[0-7]7セグメント出力

	MOVLW	B'00000110'		; 使わないA/DをOFFにする
	MOVWF	ADCON1
	MOVLW	B'01010011'		; RBプルアップ、TMR0設定、プリスケーラ1/16(0.5秒)
;	MOVLW	B'01010010'		; RBプルアップ、TMR0設定、プリスケーラ1/8(0.25秒)
;	MOVLW	B'01010001'		; RBプルアップ、TMR0設定、プリスケーラ1/4(0.125秒)
;	MOVLW	B'01010000'		; RBプルアップ、TMR0設定、プリスケーラ1/2(0.0625秒)
;	MOVLW	B'01011000'		; RBプルアップ、TMR0設定、プリスケーラなし
	MOVWF	OPTION_REG

	BCF	STATUS,RP0
	CLRF	INTCON			; 割り込み全OFF

	CLRF	SECOND			; 時間をリセット
	CLRF	MINUTE
	CLRF	HOUR
	CLRF	OFF_MINUTE
	CLRF	OFF_HOUR
	CLRF	ON_MINUTE
	CLRF	ON_HOUR
	CLRF	KEY_CMP1		; キー入力履歴を初期化する
	MOVLW	B'00000001'
	MOVWF	DP_FLAG

	BCF	FLAG,SECOND_05		; 0.5秒フラグをクリア
	BSF	FLAG,UPDATE_M		; 初回の表示アップデートを強制
	BSF	FLAG,UPDATE_H

	BSF	STATUS,RP1		; キー入力ウエイトの定数を
	MOVLW	EEP_KEY_WAIT		; EEPROMから読み出す
	MOVWF	EEADR
	BSF	STATUS,RP0
	BCF	EECON1,EEPGD		; データEEPROMを選択
	BSF	EECON1,RD		; 読み出し
	BCF	STATUS,RP0
	MOVF	EEDATA,W
	BCF	STATUS,RP1
	MOVWF	DEF_KEY_WAIT

	RETURN

load_led				; PORTCに7セグのパターンをロードする
	MOVF	LED_INDEX,W		; 実行時間は呼び出しのCALLを含めて14クロック(1.709ms)
	CALL	LED_TABLE		; インデックスをロード
	BTFSS	FLAG,SECOND_05		; 0.5秒のカウントでドットをONする
	ANDLW	B'01111111'		; 負論理なので、ドットを0にする
	MOVWF	PORTC
	BCF	PCLATH,0		; 使用済みのPCLATHを戻す
	RETURN

LED_TABLE				; LED点灯パターンテーブル
	BSF	PCLATH,0		; 計算GOTOで0x0100のためPCLATHのビット0を立てる
	ADDWF	PCL,F			; '.GFEDCBA' (負論理)
	RETLW	B'11000000'		; '0'
	RETLW	B'11111001'		; '1'
	RETLW	B'10100100'		; '2'
	RETLW	B'10110000'		; '3'
	RETLW	B'10011001'		; '4'
	RETLW	B'10010010'		; '5'
	RETLW	B'10000010'		; '6'
	RETLW	B'11011000'		; '7'
	RETLW	B'10000000'		; '8'
	RETLW	B'10010000'		; '9'
	RETLW	B'11111111'		; ' '

devide					; 60進→10進2桁変換用割り算(時計[0〜59]専用)
	CLRF	INDF			; FSRに10の位のアドレスを入れておく
DEVIDE_LOOP				; 実行時間は呼び出しのCALLを含めて65クロック(7.935ms)固定
	MOVLW	10			; CONV_60から10を引く
	SUBWF	CONV_60,W
	BTFSS	STATUS,C		; 桁下がりが起きない場合はループ
	GOTO	DEVIDE_END		; 桁下がりあり
	INCF	INDF,F			; 10の位を+1
	MOVWF	CONV_60			; 10を引いた結果をCONV_60に入れて次の引き算に備える
	GOTO	DEVIDE_LOOP
DEVIDE_END
	MOVF	INDF,W			; 数値によってルーチンを抜ける時間が変わらないように
	MOVWF	TMP00			; 補正タイマを実行する

	DECF	FSR,F			; FSRを-1して1の位を書き込む
	MOVF	CONV_60,W
	MOVWF	INDF

	MOVF	TMP00,W
	SUBLW	6			; 6-(10位)をしてループ回数を決定する
	MOVWF	TMP00
DEVIDE_TIMER				; 時間補正用ループ
	NOP
	NOP
	NOP
	NOP
	NOP
	DECFSZ	TMP00,F
	GOTO	DEVIDE_TIMER
	RETURN

wait
	MOVWF	TMP01
WAIT1
	DECFSZ	TMP01,F
	GOTO	WAIT1
	RETURN

;------------------------------------------------------------------------------
; EEPROMデータ
;------------------------------------------------------------------------------
	ORG	0x2100

	DE	0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	DE	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

	END
