;---------------------------------------------------------------------
;  ニキシー管時計（IN-1 * 4桁）
;                                                      2009.5.4
;                                                           naka
;  機能など
;  ・12時間表示/24時間表示切り替え（デフォルトは12時間表示）
;     (電源投入時に時刻設定モードSWを押していると24時間表示に切り替え)
;  ・10時の位はゼロサプレス（例：01:23 → 1:23）
;  ・コロンは１秒毎に点滅
;  ・瞬断対策として1Fの電気二重層キャパシタでバックアップ（約10分）
;    （電源断の間は表示OFF）
;  ・デバッグ／デモ用625倍速モード（10分を1秒に圧縮）
;    （電源投入時に時刻セットSWを押しているとデバッグモード）
;
;---------------------------------------------------------------------
;  I/Oポート
;   (1). RB0〜4          [out] ： アノード側（フォトカプラ）
;   (2). RA0〜3          [out] ： カソード側（KM155ID1）
;   (3). RA4             [in]  ： 時刻セット/ADJUST SW
;   (4). RA5             [in]  ： 時刻設定モードSW
;   (5). RA6             [in]  ： 瞬断検知用(5Vを監視)
;---------------------------------------------------------------------
;---------------------------------------------------------------------
;  デバイス定義
;---------------------------------------------------------------------
	LIST	P=PIC16F648A
	INCLUDE	"P16F648A.INC"
	__CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _EXTCLK_OSC & _MCLRE_OFF & _LVP_OFF
	ERRORLEVEL	-302	;アセンブル時のバンク警告メッセージ抑制
;---------------------------------------------------------------------
;  変数レジスタの定義(BANK0)
;---------------------------------------------------------------------
H10DGT	EQU	020H		; 10時
H01DGT	EQU	021H		; 01時
M10DGT	EQU	022H		; 10分
M01DGT	EQU	023H		; 01分
SECDIG	EQU	024H		; 秒
SECFLG	EQU	025H		; 0 : 秒フラグ
				; 1 : コロン表示/非表示
				; 2 : デバッグ用60倍速
SECLOW	EQU	026H		; 秒カウンタ（下位）
SECHIGH	EQU	027H		; 秒カウンタ（上位）
;
FLAG	EQU	028H		; 0 : モードスイッチ
				; 1 : セットスイッチ
				; 2 : 時刻設定モード（点滅判断）
				; 3 : 12H表示/24H表示
				; 4 : １０時設定中
				; 5 :   １時設定中
				; 6 : １０分設定中
				; 7 :   １分設定中
OFFSET	EQU	029H
ROWCNT	EQU	02AH		; ダイナミック表示列カウンタ(0〜3)
SMPLCNT	EQU	02BH		; チャタリング回避用(割り込み10回:3.2ms)
DSPCNT	EQU	02CH		; 表示カウンタ(割り込み8回に1度切り替え)
BLKCNT	EQU	02DH		; 時刻設定モード時の点滅用カウンタ
;
BKUPW	EQU	060H		; Wレジ待避用
BKUPS	EQU	061H		; STATUSレジ待避用
BKUPFR	EQU	062H		; FSRレジ待避用
BKUPPCL	EQU	063H		; PCLHレジ待避用
	;
;	最後は  07FH
;---------------------------------------------------------------------
;  マクロ定義
;---------------------------------------------------------------------
BANK0	MACRO
	BCF	STATUS,RP0	;BANK0に切り替える
	ENDM
BANK1	MACRO
	BSF	STATUS,RP0	;BANK1に切り替える
	ENDM
;---------------------------------------------------------------------
;  割り込みベクタ
;---------------------------------------------------------------------
	ORG	00H		; リセット時の飛び込み先
RESET
	GOTO	START		;
	ORG	04H		; 割り込み時の飛び込み先
INTER				;
	GOTO	INTRUPT
	;
;---------------------------------------------------------------------
;  メイン
;---------------------------------------------------------------------
START
	CALL	INIT		; 初期化
	;
	BTFSS	PORTA,5		; 時刻設定SWが押されている可能性があるので
	GOTO	$-1		; 離されるまで待つ
	BTFSS	PORTA,4		; 時刻セットSWが押されている可能性があるので
	GOTO	$-1		; 離されるまで待つ
	BCF	FLAG,0
	BCF	FLAG,1
MAIN
	BTFSC	FLAG,1		; ADJUSTモード
	CALL	ADJTIME
	;
	BTFSC	FLAG,0		; 時刻設定モード
	CALL	SETTIME
	;
	BTFSS	SECFLG,0	; 秒フラグ確認
	GOTO	MAIN
	;
	BCF	SECFLG,0	; 秒フラグクリア
	CALL	COUNTUP
	GOTO	MAIN
	;
;---------------------------------------------------------------------
;  初期化
;---------------------------------------------------------------------
INIT
	BCF	INTCON,GIE	;全割込み禁止
	;
	BANK1
	MOVLW	B'11110000'
	MOVWF	TRISA		;ポートAは0-3出力、4-7入力
	CLRF	TRISB		;ポートBは全て出力端子
	BANK0
	;
	BCF	INTCON,GIE	; 割り込み禁止
	BANK1
	;割り込みタイマーセット
	MOVLW	H'81'		; プリスケーラを4にする
	MOVWF	OPTION_REG	; 3.125KHzで割り込みが入るはず
	BANK0			; clock 12.8MHz -> 3.2Mcycle
				; 3.2Mcycle/(4*256)=3.125KHz(=320usec毎)
	;
	CLRF	ROWCNT		; クリア
	CLRF	SECLOW		; 秒カウンタ（下位）クリア
	CLRF	SECHIGH		; 秒カウンタ（上位）クリア
	CLRF	SECFLG		; 秒フラグクリア
	CLRF	FLAG
	CLRF	BLKCNT
	CLRF	SECDIG
	MOVLW	D'3'
	MOVWF	SMPLCNT		; SW状態のサンプリング間隔(3*320us=約1ms)
	MOVLW	D'8'
	MOVWF	DSPCNT
	;
	CLRF	M01DGT
	CLRF	M10DGT
	BTFSS	PORTA,5		; 電源投入時に時刻設定モードスイッチONなら24時間表示
	GOTO	MODE24H
MODE12H				; 12H表示の時は初期値が12:00
	MOVLW	D'2'
	MOVWF	H01DGT
	MOVLW	D'1'
	MOVWF	H10DGT
	GOTO	CHKDBG
MODE24H				; 24H表示の時は初期値が00:00
	CLRF	H01DGT
	CLRF	H10DGT
	BSF	FLAG,3		; 24H表示
	;
CHKDBG
	BTFSS	PORTA,4		; 電源投入時に時刻セットスイッチONなら60倍速モード
	BSF	SECFLG,2
	;
	BSF	INTCON,T0IE	;RTCCマスクイネーブル
	BSF	INTCON,GIE	;割り込み許可
	RETURN
	;
;---------------------------------------------------------------------
;  割り込み処理で１秒のカウントと、時刻のダイナミック表示を行う。
;    3,125回で1秒
;---------------------------------------------------------------------
INTRUPT
	;レジスタ待避
	MOVWF	BKUPW		; バックアップ（Wレジ）
	SWAPF	STATUS,W	; バックアップ（STATUSレジ）
	MOVWF	BKUPS
	MOVF	FSR,W		; バックアップ（FSRレジ）
	MOVWF	BKUPFR
	MOVF	PCLATH,W	; バックアップ（PCLHレジ）
	MOVWF	BKUPPCL
	;
	BCF	INTCON,T0IF	; 割り込みフラグリセット
	;
	; デバッグモードの１秒カウント（625倍、10分を1秒に圧縮）
	BTFSS	SECFLG,2
	GOTO	CNT1S
	INCF	SECLOW,F
	MOVLW	D'5'		; 320us*5=1.6ms(625倍速)
	SUBWF	SECLOW,W
	BTFSS	STATUS,Z
	GOTO	END1S
	GOTO	CNT1SEC
CNT1S
	;
	; １秒カウント
	;
	INCF	SECLOW,F
	BTFSC	STATUS,Z
	INCF	SECHIGH,F
	;
	MOVLW	D'12'		; 12*256 + 53 = 3125
	SUBWF	SECHIGH,W	;
	BTFSS	STATUS,Z	;
	GOTO	END1S		; 1秒カウント終わり
	MOVLW	D'53'		;
	SUBWF	SECLOW,W
	BTFSS	STATUS,Z
	GOTO	END1S		; 1秒カウント終わり
	;
CNT1SEC
	CLRF	SECLOW
	CLRF	SECHIGH
	BSF	SECFLG,0	; 1秒経ったのでSECFLGセット
END1S
	BTFSC	PORTA,6		; 停電監視
	GOTO	DISPROW		; １桁表示
	CALL	DISPOFF		; 消灯
	GOTO	INTRTRN		; リターン
	;
DISPROW
	MOVF	DSPCNT,W
	SUBLW	D'3'
	BTFSC	STATUS,C
	CLRF	PORTB		; 一旦アノード側オフ(320us×2オフ、320us×6オン)
	;
	DECFSZ	DSPCNT,F	; 表示切り替えタイミング確認（割り込み8回に1回）
	GOTO	DISPSKP		; 320us * 8 * 4列 = 10.24ms = 約98Hz
	;
	CALL	CHKBLNK		; 時刻設定モード時の点滅チェック
	BTFSS	STATUS,Z
	GOTO	SKIPDGT		; この桁は非表示
	;
	BTFSC	FLAG,2		; 通常表示時（時刻設定モード以外）は、
	GOTO	DISPDGT		; １０時の位のゼロサプレス
	MOVF	ROWCNT,W
	SUBLW	D'3'
	BTFSC	STATUS,Z
	MOVF	H10DGT,F
	BTFSC	STATUS,Z
	GOTO	SKIPDGT		; ゼロなので非表示
	;
DISPDGT
	CALL	SELDGT		; 表示する数字を選択
	MOVWF	PORTA		; カソード側設定
	;
	MOVF	ROWCNT,W
	CALL	DECBIT
	BTFSC	SECFLG,1	; コロン表示チェック
	IORLW	B'00010000'	; 表示
	MOVWF	PORTB		; アノード側設定
	;
SKIPDGT
	INCF	ROWCNT,F	; 次回、次の桁を表示するためにインクリメント
	MOVLW	D'4'
	SUBWF	ROWCNT,W
	BTFSC	STATUS,Z
	CLRF	ROWCNT
	MOVLW	D'8'		; 表示用カウンタセット
	MOVWF	DSPCNT
DISPSKP
	;
	; スイッチの状態確認
	DECFSZ	SMPLCNT,F	; チャタリング回避のためのサンプル時間確認
	GOTO	INTRTRN		; リターン
	;
	MOVLW	D'3'		; 次回のためにカウンタセット
	MOVWF	SMPLCNT
	;
	BCF	FLAG,0		; 時刻設定モードスイッチクリア
	BTFSS	PORTA,5
	BSF	FLAG,0		; 時刻設定モードスイッチON
	;
	BCF	FLAG,1		; セット/ADJUSTスイッチクリア
	BTFSS	PORTA,4
	BSF	FLAG,1		; セットスイッチON
	;
INTRTRN
	;
	;レジスタ復元
	MOVF	BKUPPCL,W	;復元（PCLATH)
	MOVWF	PCLATH
	MOVF	BKUPFR,W	;復元（FSRレジ）
	MOVWF	FSR
	SWAPF	BKUPS,W		;復元（STATUSレジ)
	MOVWF	STATUS
	SWAPF	BKUPW,F		;復元（Wレジ）
	SWAPF	BKUPW,W
	;
	RETFIE
	;
;---------------------------------------------------------------------
;  Wレジ値をビット位置にデコード
;---------------------------------------------------------------------
DECBIT
	CLRF	PCLATH		;
	ADDWF	PCL,F
	RETLW	B'00000001'	;0
	RETLW	B'00000010'	;1
	RETLW	B'00000100'	;2
	RETLW	B'00001000'	;3
	RETLW	B'00010000'	;4
	RETLW	B'00100000'	;5
	RETLW	B'01000000'	;6
	RETLW	B'10000000'	;7
	;
;---------------------------------------------------------------------
;  ROWCNT値から表示桁を選択
;---------------------------------------------------------------------
SELDGT
	BCF	STATUS,C
	RLF	ROWCNT,W	; オフセット値（カウンタの２倍）
	CLRF	PCLATH
	ADDWF	PCL,F
	MOVF	M01DGT,W	;   １分
	RETURN
	MOVF	M10DGT,W	; １０分
	RETURN
	MOVF	H01DGT,W	;   １時
	RETURN
	MOVF	H10DGT,W	; １０時
	RETURN
	;
;---------------------------------------------------------------------
;  表示OFF
;---------------------------------------------------------------------
DISPOFF
	CLRF	PORTA
	CLRF	PORTB
	RETURN
;---------------------------------------------------------------------
;  時刻設定モード時の桁点滅確認
;---------------------------------------------------------------------
CHKBLNK
	BTFSS	FLAG,2		; 時刻設定モードなら点滅判断
	GOTO	CHKON
	;
	INCF	BLKCNT,F
	; 点滅対象の桁か確認する
	MOVLW	H'FF'
	BTFSS	FLAG,4
	GOTO	$+2
	MOVLW	D'3'
	BTFSS	FLAG,5
	GOTO	$+2
	MOVLW	D'2'
	BTFSS	FLAG,6
	GOTO	$+2
	MOVLW	D'1'
	BTFSS	FLAG,7
	GOTO	$+2
	MOVLW	D'0'
	;
	SUBWF	ROWCNT,W	; 一致したら対象となる
	BTFSS	STATUS,Z
	GOTO	CHKON		; 点滅対象外なのでオンでリターン
	;
	; 対象の桁なのでオン／オフか確認する
	MOVF	BLKCNT,W
	SUBLW	D'90'		; 90以下ならオン
	BTFSS	STATUS,C
	GOTO	CHKOFF
CHKON
	BSF	STATUS,Z	; オンでリターン
	RETURN
	;
CHKOFF
	MOVF	BLKCNT,F
	SUBLW	D'150'
	BTFSC	STATUS,Z
	CLRF	BLKCNT
	BCF	STATUS,Z	; オフでリターン
	RETURN
	;
;---------------------------------------------------------------------
;  時刻アジャスト（秒を四捨五入：30秒以上なら分繰り上げ）
;---------------------------------------------------------------------
ADJTIME
	MOVLW	D'30'
	SUBWF	SECDIG,W
	BTFSC	STATUS,C
	CALL	CNTUPMIN	; 分をカウントアップ
	;
	CLRF	SECLOW		; 秒カウンタ（下位）クリア
	CLRF	SECHIGH		; 秒カウンタ（上位）クリア
	CLRF	SECDIG		; 秒をクリア
	BCF	SECFLG,0	; 秒フラグクリア
	;
	BTFSC	FLAG,1		; スイッチが離される迄待つ
	GOTO	$-1
	;
	RETURN
	;
;---------------------------------------------------------------------
;  時刻設定モード（時、分の各桁毎に数字をカウントアップ）
;---------------------------------------------------------------------
SETTIME
	BSF	FLAG,2		; 時刻設定モード
	BTFSC	FLAG,0		; モードSWが離されるまで待つ
	GOTO	$-1
	;
SET10H
	BSF	FLAG,4		; 10の位 設定モード（数字が点滅）
	BTFSC	FLAG,1		; セットスイッチが押された？
	GOTO	INC10H		;
	BTFSS	FLAG,0		; モードスイッチが押された？
	GOTO	SET10H
	BCF	FLAG,4
	BTFSC	FLAG,0		; モードSWが離されるまで待つ
	GOTO	$-1
	GOTO	SET01H
INC10H
	INCF	H10DGT,F
	CLRF	H01DGT		; １時の桁をクリア
	MOVLW	D'2'
	BTFSC	FLAG,3		; 12時間/24時間表示でのカウントアップ方法切り替え
	MOVLW	D'3'
	SUBWF	H10DGT,W
	BTFSC	STATUS,Z
	CLRF	H10DGT
SET10HE
	BTFSC	FLAG,1		; 離されるまで待つ
	GOTO	$-1
	GOTO	SET10H
	;
SET01H
	BSF	FLAG,5		; 1の位 設定モード（数字が点滅）
	BTFSC	FLAG,1		; セットスイッチが押された？
	GOTO	INC01H		;
	BTFSS	FLAG,0		; モードスイッチが押された？
	GOTO	SET01H
	BCF	FLAG,5
	BTFSC	FLAG,0		; モードSWが離されるまで待つ
	GOTO	$-1
	GOTO	SET10M		;
INC01H
	INCF	H01DGT,F
	;
	BTFSC	FLAG,3		; 12時間/24時間表示でのカウントアップ方法切り替え
	GOTO	M24H
M12H
	MOVF	H10DGT,F
	BTFSC	STATUS,Z
	GOTO	SET01HC		; 10時の桁が0なら通常インクリメントチェック
	MOVLW	D'3'		; 10時の桁が1のときは2迄
	SUBWF	H01DGT,W
	BTFSS	STATUS,Z
	GOTO	SET01HE
	CLRF	H01DGT
	GOTO	SET01HE
M24H
	BTFSS	H10DGT,1
	GOTO	SET01HC		; 10時の桁が0,1(!=2)なら通常インクリメントチェック
	MOVLW	D'4'		; それ以外のときは3迄
	SUBWF	H01DGT,W
	BTFSS	STATUS,Z
	GOTO	SET01HE
	CLRF	H01DGT
	GOTO	SET01HE
SET01HC
	MOVLW	D'10'
	SUBWF	H01DGT,W
	BTFSC	STATUS,Z
	CLRF	H01DGT
SET01HE
	BTFSC	FLAG,1		; 離されるまで待つ
	GOTO	$-1
	GOTO	SET01H
	;
SET10M
	BSF	FLAG,6		; 1の位 設定モード（数字が点滅）
	BTFSC	FLAG,1		; セットスイッチが押された？
	GOTO	INC10M		;
	BTFSS	FLAG,0		; モードスイッチが押された？
	GOTO	SET10M
	BCF	FLAG,6
	BTFSC	FLAG,0		; モードSWが離されるまで待つ
	GOTO	$-1
	GOTO	SET01M		;
INC10M
	INCF	M10DGT,F
	MOVLW	D'6'
	SUBWF	M10DGT,W
	BTFSC	STATUS,Z
	CLRF	M10DGT
	;
	BTFSC	FLAG,1		; 離されるまで待つ
	GOTO	$-1
	GOTO	SET10M
	;
SET01M
	BSF	FLAG,7		; 1の位 設定モード（数字が点滅）
	BTFSC	FLAG,1		; セットスイッチが押された？
	GOTO	INC01M		;
	BTFSS	FLAG,0		; モードスイッチが押された？
	GOTO	SET01M
	BCF	FLAG,7
	BTFSC	FLAG,0		; モードスイッチが離されたらモード終わり
	GOTO	$-1
	GOTO	SETEND
INC01M
	INCF	M01DGT,F
	MOVLW	D'10'
	SUBWF	M01DGT,W
	BTFSC	STATUS,Z
	CLRF	M01DGT
	;
	BTFSC	FLAG,1		; 離されるまで待つ
	GOTO	$-1
	GOTO	SET01M
	;
SETEND
	BCF	FLAG,2		; 時刻設定モード終了
	CLRF	SECLOW		; 秒カウンタ（下位）クリア
	CLRF	SECHIGH		; 秒カウンタ（上位）クリア
	CLRF	SECDIG		; 秒をクリア
	BCF	SECFLG,0	; 秒フラグクリア
	RETURN
	;
;---------------------------------------------------------------------
;  時刻カウントアップ
;---------------------------------------------------------------------
COUNTUP
	CALL	TGLCOL		; ：（コロン）表示をトグル
	;
	INCF	SECDIG,F	; 秒カウントアップ
	MOVLW	D'60'
	SUBWF	SECDIG,W
	BTFSS	STATUS,Z
	RETURN
	CLRF	SECDIG		; 秒クリア
	;
CNTUPMIN
	INCF	M01DGT,F	; 分（１の位）カウントアップ
	MOVLW	D'10'
	SUBWF	M01DGT,W
	BTFSS	STATUS,Z
	RETURN
	CLRF	M01DGT
	;
	INCF	M10DGT,F	; 分（１０の位）カウントアップ
	MOVLW	D'6'
	SUBWF	M10DGT,W
	BTFSS	STATUS,Z
	RETURN
	CLRF	M10DGT
	;
	INCF	H01DGT,F	; 時（１の位）カウントアップ
	MOVLW	D'10'
	SUBWF	H01DGT,W
	BTFSC	STATUS,Z
	GOTO	H10UP
	;
	; 12時間/24時間表示でのカウントアップ方法切り替え
	BTFSC	FLAG,3
	GOTO	CNTUP24
CNTUP12	; 12時間表示のカウントアップ
	MOVLW	D'3'		; 13時のチェック
	SUBWF	H01DGT,W
	BTFSS	STATUS,Z
	RETURN
	MOVLW	D'1'
	SUBWF	H10DGT,W
	BTFSS	STATUS,Z
	RETURN
	MOVLW	D'1'
	MOVWF	H01DGT
	CLRF	H10DGT
	RETURN
	;
CNTUP24	; 24時間表示のカウントアップ
	MOVLW	D'4'		; 24時のチェック
	SUBWF	H01DGT,W
	BTFSS	STATUS,Z
	RETURN
	MOVLW	D'2'
	SUBWF	H10DGT,W
	BTFSS	STATUS,Z
	RETURN
	CLRF	H01DGT
	CLRF	H10DGT
	RETURN
H10UP
	CLRF	H01DGT
	INCF	H10DGT,F	; 時（１０の位）カウントアップ
	RETURN
	;
;---------------------------------------------------------------------
;  ：（コロン）の表示／非表示（呼び出すたびにトグルする）
;---------------------------------------------------------------------
TGLCOL
	BTFSS	SECFLG,1
	GOTO	$+3
	BCF	SECFLG,1	; 表示中ならオフ
	RETURN
	BSF	SECFLG,1	; 非表示中ならオン
	RETURN
	;
;---------------------------------------------------------------------
	END
;---------------------------------------------------------------------
;  終わり
;---------------------------------------------------------------------
