;***** NixieTubeClock.asm *************************************************
;
;	６桁ニキシー管時計
;
;	origin:  http://www.mars.dti.ne.jp/~ogura/e_hobby/nixie_clock.html
;
;     ( coding:  Ver. 0.00   2007/03/10  by M.Yamamoto )
;	coding:  Ver. 1.00   2007/03/14  初期バージョン
;	update:  Ver. 1.10   2007/03/15  DOWNスイッチの機能追加
;	update:  Ver. 1.11   2007/03/16  表示テスト前のウエイト挿入
;	update:  Ver. 1.20   2007/03/26  ZEROスイッチの機能変更
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0206 ******

;	Device: PIC16F876	Clock: 12.8MHz (クリスタルモジュール)

;   Ver. 1.00	オリジナルでは、HEXファイルのみでソースの公開がないため、プログラムの
;		修正変更がいっさいできない。 そこで、フリーソフトウエアの "帝" で逆ア
;		センブルをしてソースファイルを作成し、それを解析してコメントを付けた。
;		その後、不要と思われる変数、命令の削除、変更を行い、年月日の表示時の
;		区切りに"."(Period) が点灯するようにプログラムの追加を行った。

;   Ver. 1.10	年、月、日、時、分の設定時に、UP スイッチだけでは、誤って希望値を過ぎ
;		てしまった場合に操作性が悪い。そこで逆動作を行う DOWN スイッチの機能
;		を追加した。

;   Ver. 1.11	電源の投入直後はまだ高圧が出きっていないため、ニキシー全管の０～９表
;		示テストを行っても、０～９のカウントアップしていく様子が表示しきれな
;		い。そこで十分高圧になるまでのウエイトをおいた。

;   Ver. 1.20	ZERO スイッチの機能として、オリジナルでは 30分を境として毎正時ゼロと
;		していたのに対し、ここでは毎正時プラス・マイナス５分以内に押された時
;		に限り、00分00秒に設定するようにプログラム変更をした。
	
;==========================================================================

#ifdef comment

 <機能と使用法>

・まず電源を投入すると、0.5秒間づつ０から９まで順次更新しながら、ニキシー全管（６本）
　の０～９表示テストを計５秒間行う。
・時計表示は２４時間表示で、他に年月日の表示と気温の表示の機能を持っている。
　　　時間表示		ｘｘ ： ｘｘ ： ｘｘ
　　　年月日表示	ｘｘ ． ｘｘ ． ｘｘ
　　　気温表示		＿＿ 　 ｘｘ ． ｘ＿
・上記３つの表示は MODE スイッチを押下することで切り替わるが、電源の投入直後は０～９の
　表示テストを済ませ、時間表示になっている。その後、MODE スイッチの押下ごとに、時間表
　示、年月日表示、気温表示に加えてオートモードの順に４つのモードを繰り返す。
・オートモードでは、時間表示中に以下の振る舞いを行う。
　　　毎10～15秒と40～45秒の間：　年月日表示
　　　毎20～25秒と50～55秒の間：　気温表示
・年月日、時分の設定は、上記４つのどのモード時でも可能で、電源の投入直後は 07年01月01日、
　0時00分00秒からスタートするので、SET スイッチと UP または DOWN スイッチによって適宜
　行う。
・SET スイッチは、押下するごとに年、月、日、時、分と次項目に移動するので、該当の項目を
　選択後 UP または DOWN スイッチによって値を設定する。最後の分設定後にもう一度 SET ス
　イッチを押下すると、00秒からの時計動作がスタートし、必ず時間表示モードに戻る。
・DOWN／ZERO スイッチは、年月日、時分の設定中は上記のように DOWN スイッチとして機能す
　るが、それ以外では毎正時プラス・マイナス５分以内に押されると 00分00秒に設定するため
　の ZERO スイッチとして機能する。
・年月日カレンダー機能について、うるう年の計算は 2001年～2399年までの範囲で対応してい
　る。ただし、年の表示は下２桁のみになる。
・その他の機能として、周囲の明るさに応じてニキシー管の表示を減光するディマー機能を持ち、
　周囲が明るいときはニキシー管の表示も明るく、周囲が暗くなると暗く表示される。

#endif

;	PIC16F876 のピンと用途

;	  (1) MCLR: マスター・クリア入力	(28) RB7: ニキシー "HH" 桁出力
;	  (2) RA0:  CDS ディマーアナログ入力	(27) RB6: ニキシー "HL" 桁出力
;	  (3) RA1:  温度センサアナログ入力　	(26) RB5: ニキシー "MH" 桁出力
;	  (4) RA2:  予備			(25) RB4: ニキシー "ML" 桁出力
;	  (5) RA3:  VREF+アナログ入力		(24) RB3: ニキシー "SH" 桁出力
;	  (6) RA4:  予備			(23) RB2: ニキシー "SL" 桁出力
;	  (7) RA5:  １秒パルス(幅100ms)出力	(22) RB1: LED コロン(:)出力
;	  (8) VSS:  電源 GND			(21) RB0: ニキシー"DP"出力
;	  (9) OSC1: オシレータ水晶入力		(20) VDD: 電源 +5V DC
;	 (10) OSC2: オシレータ水晶入力		(19) VSS: 電源 GND
;	 (11) RC0:  BCD A 出力 			(18) RC7: SW4(MODE) スイッチ入力
;	 (12) RC1:  BCD B 出力 			(17) RC6: SW3(SET) スイッチ入力
;	 (13) RC2:  BCD C 出力 			(16) RC5: SW2(UP) スイッチ入力
;	 (14) RC3:  BCD D 出力 			(15) RC4: SW1(DOWN／ZERO) スイッチ入力

;==========================================================================

	list		p=pic16f876		;デバイス情報
	include		p16f876.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;	コンフィギュレーションの設定
;==========================================================================
 
      __config _HS_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF

;==========================================================================
;	変数の定義とレジスタ割付け
;==========================================================================

		cblock  h'20'
bcd_hh					;時 BCD カウンタ
bcd_mm					;分 BCD カウンタ
bcd_ss					;秒 BCD カウンタ
bcd_yy					;年 BCD カウンタ
bcd_nn					;月 BCD カウンタ
bcd_dd					;日 BCD カウンタ
work1					;ワーク
dspdigit				;表示桁指定フラグ
updtflg					;更新フラグ, 0:時分秒更新, 1:年月日更新, 2:ディマー制御
cnt_high				;１秒カウンタ high
cnt_low					;１秒カウンタ low
NumH					;16-bit binary number high
NumL					;16-bit binary number low
TenK					;変換後BCD 10000位  ／  test_hh
Thou					;変換後BCD  1000位  ／  test_mm
Hund					;変換後BCD   100位  ／  test_ss
Tens					;変換後BCD    10位
Ones					;変換後BCD     1位
work2					;ワーク
modeflg					;MODEフラグ, 0:時間, 1:年月日, 2:気温, 3:オートモード
swstate					;スイッチのON／OFF状態
chatter					;チャタリング補正カウンタ
tempfsr					;仮のFSR
work3					;ワーク
wtcnt1					;ウェイト用ループカウンタ
wtcnt2					;ウェイト用ループカウンタ
		endc

		cblock  h'70'
s_save					;STATUS レジスタの退避用
p_save					;PCLATH レジスタの退避用
f_save					;FSR レジスタの退避用
w_save					;W レジスタの退避用
		endc

#define		test_hh		TenK
#define		test_mm		Thou
#define		test_ss		Hund

;==========================================================================
;	プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	init
		org	4		;割り込みベクタ
		goto	interrupt

;==========================================================================
;	初期化処理
;==========================================================================

init
		bcf	STATUS,RP0	;バンク 0
		clrf	PORTA
		clrf	PORTB
		clrf	PORTC

		bsf	STATUS,RP0	;バンク 1
		movlw	h'd1'		;PBPU=1: プルアップ抵抗を使用しない
					;INTEDG=1: RB0/INTピンの立ち上がりで割り込み
					;T0SE=1: RA4/T0CKIピンの立ち下がりでカウントアップ
					;PS=001: プリスケーラのスケール値 1:4
		movwf	OPTION_REG

		movlw	b'00001011'	;RA5-4,2: 出力, RA3,1-0: 入力
		movwf	TRISA
		movlw	b'00000000'	;RB7-0: 出力
		movwf	TRISB
		movlw	b'11110000'	;RC7-4: 入力, RC3-0: 出力
		movwf	TRISC

		movlw	h'05'		;ADFM=0: Ａ／Ｄ変換結果をADRESレジスタに左寄せで格納
		movwf	ADCON1		;PCFG=0101: RA4,2: D, RA1,0: A, RA3: VREF+

		bcf	STATUS,RP0	;バンク 0
		movlw	h'20'		;GIE=0: 全割り込み禁止, T0IE=1: タイマー(TMR0)オーバーフロー割り込み許可
		movwf	INTCON
		movlw	h'80'		;ADCS=10: Ａ／Ｄ変換クロックを指定 Fosc/32
		movwf	ADCON0		;CHS=000: チャネル０(RA0), ADON=0: Ａ／Ｄ変換モジュール電源ＯＦＦ

		clrf	bcd_hh		;時分秒 BCD カウンタの初期設定 (00時00分00秒)
		clrf	bcd_mm
		clrf	bcd_ss
		movlw	h'07'		;年月日 BCD カウンタの初期設定 (07年01月01日)
		movwf	bcd_yy
		movlw	h'01'
		movwf	bcd_nn
		movlw	h'01'
		movwf	bcd_dd
		clrf	modeflg		;MODEフラグの初期設定
		clrf	updtflg		;更新フラグの初期設定
		clrf	cnt_high	;１秒カウンタの初期設定
		clrf	cnt_low
		movlw	h'f0'		;すべて OFF
		movwf	swstate		;スイッチのON／OFF状態の初期設定
		bsf	INTCON,GIE	;全割り込み禁止解除

		; ニキシー全管の０～９表示テスト

ini01		movlw	h'03'		;3 秒間のウエイト
		subwf	bcd_ss,W
		btfss	STATUS,C	;秒 BCD カウンタ >= h'03' か？
		goto	ini01		;No

		clrf	test_hh		;全管の表示データを０クリア
		clrf	test_mm
		clrf	test_ss
		movlw	h'fe'		;時間(xx:xx:xx)表示
		movwf	dspdigit	;表示桁指定フラグの設定

ini02		movlw	test_hh
		movwf	tempfsr		;間接アドレスの先頭番地の設定
		movlw	h'06'		;h'0C35'/2 = d'3125'/2 = d'1562' = h'061a'
		movwf	cnt_high
		movlw	h'1a'
		movwf	cnt_low
		call	nixie_display	;ニキシー管の表示 (0.5秒間)
		movlw	h'99'
		subwf	test_hh,W
		btfsc	STATUS,Z	;全管の０～９表示テスト終了か？
		goto	ini03		;Yes

		movlw	h'11'		;全管の表示データを＋１
		addwf	test_hh,F
		movlw	h'11'
		addwf	test_mm,F
		movlw	h'11'
		addwf	test_ss,F
		goto	ini02		;全管の０～９表示テストの繰り返し

ini03		clrf	bcd_ss		;秒 BCD カウンタの初期設定

;==========================================================================
;	メイン・ルーチン
;==========================================================================

main
		call	dimrflg_cntrl	;ディマーフラグ制御
		movlw	h'00'
		subwf	modeflg,W
		btfss	STATUS,Z	;MODEフラグ = 0(時間)表示 か？
		goto	mai02		;No

		; ニキシー管の(時間)表示

mai01		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	tempfsr		;間接アドレスの先頭番地の設定
		movlw	h'fe'		;時間(xx:xx:xx)表示指定
		movwf	dspdigit	;表示桁指定フラグの設定
		movlw	h'10'
		subwf	bcd_hh,W
		btfss	STATUS,C	;時 BCD カウンタ >= h'10' か？
		bcf	dspdigit,7	;No. ゼロサプレス "HH"桁を非表示(_x:xx:xx) dspdigit = h'7e'
		goto	mai07		;ニキシー管の表示へ

mai02		movlw	h'01'
		subwf	modeflg,W
		btfss	STATUS,Z	;MODEフラグ = 1(年月日)表示 か？
		goto	mai04		;No

		; ニキシー管の(年月日)表示

mai03		movlw	bcd_yy		;年 BCD カウンタの番地
		movwf	tempfsr		;間接アドレスの先頭番地の設定
		movlw	h'fd'		;年月日(xx.xx.xx)表示指定
		movwf	dspdigit	;表示桁指定フラグの設定
		goto	mai07		;ニキシー管の表示へ

mai04		movlw	h'02'
		subwf	modeflg,W
		btfss	STATUS,Z	;MODEフラグ = 2(気温)表示 か？
		goto	mai06		;No

		; ニキシー管の(気温)表示

mai05		call	temperature	;気温測定
		movlw	TenK
		movwf	tempfsr		;間接アドレスの先頭番地の設定
		movlw	h'39'		;気温(__ xx.x_)表示指定
		movwf	dspdigit	;表示桁指定フラグの設定
		movlw	h'10'
		subwf	Thou,W
		btfss	STATUS,C	;Thou >= 10 か？
		bcf	dspdigit,5	;No. ゼロサプレス "MH"桁を非表示(__ _x.x_) dspdigit = h'19'
		goto	mai07		;ニキシー管の表示へ

		; オートモードの処理
		; (時間表示中、毎10～15秒と40～45秒の間が年月日表示)
		; (時間表示中、毎20～25秒と50～55秒の間が気温表示)

mai06		movlw	h'ff' - h'10'	;= h'ef'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'10' か？
		goto	mai01		;No. (時間)表示へ

		movlw	h'ff' - h'15'	;= h'ea'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'15' か？
		goto	mai03		;No. (年月日)表示へ

		movlw	h'ff' - h'20'	;= h'df'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'20' か？
		goto	mai01		;No. (時間)表示へ

		movlw	h'ff' - h'25'	;= h'da'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'25' か？
		goto	mai05		;No. (気温)表示へ

		movlw	h'ff' - h'40'	;= h'bf'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'40' か？
		goto	mai01		;No. (時間)表示へ

		movlw	h'ff' - h'45'	;= h'ba'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'45' か？
		goto	mai03		;No. (年月日)表示へ

		movlw	h'ff' - h'50'	;= h'af'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'50' か？
		goto	mai01		;No. (時間)表示へ

		movlw	h'ff' - h'55'	;= h'aa'
		addwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss > h'55' か？
		goto	mai05		;No. (気温)表示へ
		goto	mai01		;Yes.(時間)表示へ

mai07		call	nixie_display	;ニキシー管の表示

		; スイッチのON／OFF状態フラグのチェック

		btfsc	swstate,7	;MODEスイッチ = ON か？
		goto	mai08		;No

		; MODEスイッチの処理

		incf	modeflg,F	;MODEフラグ +1 更新
		movlw	h'04'
		subwf	modeflg,W
		btfsc	STATUS,Z	;MODEフラグ <> 4 か？
		clrf	modeflg		;No. modeflg = 0
		goto	mai12

mai08		btfsc	swstate,6	;SETスイッチ = ON か？
		goto	mai09		;No

		; SETスイッチの処理

		call	set_switch	;SETスイッチの処理
		goto	mai12

mai09		btfsc	swstate,4	;ZEROスイッチ = ON か？
		goto	mai12		;No

		; ZEROスイッチの処理

		movlw	h'06'
		subwf	bcd_mm,W
		btfss	STATUS,C	;分 BCD カウンタ >= h'06' か？
		goto	mai10		;No

		movlw	h'55'
		subwf	bcd_mm,W
		btfss	STATUS,C	;分 BCD カウンタ >= h'55' か？
		goto	mai12		;No

		bcf	INTCON,GIE	;全割り込み禁止
		call	bcd_hh_inc	;時 BCD カウンタのインクリメント
		goto	mai11

mai10		bcf	INTCON,GIE	;全割り込み禁止

mai11		clrf	bcd_mm		;分 BCD カウンタのクリア
		clrf	bcd_ss		;秒 BCD カウンタのクリア
		clrf	cnt_high	;１秒カウンタの初期設定
		clrf	cnt_low
		bsf	INTCON,GIE	;全割り込み禁止解除

mai12		btfss	updtflg,1	;年月日更新フラグ = ON か？
		goto	main		;No

		; 年月日の更新

		call	bcd_dd_inc	;日 BCD カウンタのインクリメント
		bcf	updtflg,1	;年月日更新フラグのクリア
		movlw	h'01'
		subwf	bcd_dd,W
		btfss	STATUS,Z	;日 BCD カウンタ = h'01' か？
		goto	main		;No

		call	bcd_nn_inc	;月 BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'01' か？
		goto	main		;No

		call	bcd_yy_inc	;年 BCD カウンタのインクリメント
		goto	main

;==========================================================================

;		ディマーフラグ制御

dimrflg_cntrl
		movlw	h'81'		;ADCS=10: Ａ／Ｄ変換クロックを指定 Fosc/32, 
		movwf	ADCON0		;CHS=000: チャネル０(RA0), ADON=1: Ａ／Ｄ変換モジュール電源ＯＮ
		call	wait_22us
		bsf	ADCON0,GO_DONE	;Ａ／Ｄ変換起動／処理中

dfcnt01		btfsc	ADCON0,GO_DONE	;変換完了(ハードでクリア) か？
		goto	dfcnt01		;No

		movlw	h'75'
		addwf	ADRESH,W
		btfsc	STATUS,C	;ADRESH =< h'8a' (h'ff' - h'75')
		goto	dfcnt02		;No

		movlw	h'76'
		subwf	ADRESH,W
		btfss	STATUS,C	;ADRESH >= h'76'
		goto	dfcnt03		;No

		return		

dfcnt02		bcf	updtflg,2	;ディマー制御フラグのクリア
		return		

dfcnt03		bsf	updtflg,2	;ディマー制御フラグのセット
		return		

;		気温の測定

temperature
		movlw	h'89'		;ADCS=10: Ａ／Ｄ変換クロックを指定 Fosc/32, 
		movwf	ADCON0		;CHS=001: チャネル１(RA1), ADON=1: Ａ／Ｄ変換モジュール電源ＯＮ
		call	wait_22us
		bsf	ADCON0,GO_DONE	;GO/DONE=1: Ａ／Ｄ変換起動／処理中

temp01		btfsc	ADCON0,GO_DONE	;変換完了(ハードでクリア) か？
		goto	temp01		;No

		movf	ADRESH,W
		movwf	NumL
		bsf	STATUS,RP0	;バンク 1
		movf	ADRESL,W
		bcf	STATUS,RP0	;バンク 0
		movwf	work3
		clrf	NumH
		rlf	work3,F
		rlf	NumL,F
		rlf	NumH,F
		call	Convert		;Binary-to-BCD 変換
		movf	Hund,W
		movwf	Thou
		swapf	Thou,F		;"MH" 桁: 上位4ビット
		movf	Tens,W
		iorwf	Thou,F		;"ML" 桁: 下位4ビット
		movf	Ones,W
		movwf	Hund
		swapf	Hund,F		;"SH" 桁: 上位4ビット
		return		

;==========================================================================
;	SETスイッチの処理	
;==========================================================================

set_switch
		bcf	INTCON,GIE	;全割り込み禁止
		movlw	bcd_yy		;年 BCD カウンタの番地
		movwf	tempfsr		;間接アドレスの先頭番地の設定

		; 年の処理

set01		movlw	h'c0'		;"HH","HL" 桁
		movwf	dspdigit	;表示桁指定フラグの設定
		call	nixie_display	;ニキシー管の表示
		btfss	swstate,6	;SETスイッチ = OFF か？
		goto	set03		;No

		btfss	swstate,4	;DOWNスイッチ = OFF か？
		goto	set02		;No

		btfsc	swstate,5	;UPスイッチ = ON か？
		goto	set01		;No

		call	bcd_yy_inc	;年 BCD カウンタのインクリメント
		goto	set01

set02		call	bcd_yy_dec	;年 BCD カウンタのデクリメント
		goto	set01

		; 月の処理

set03		movlw	h'30'		;"MH","ML" 桁
		movwf	dspdigit	;表示桁指定フラグの設定
		call	nixie_display	;ニキシー管の表示
		btfss	swstate,6	;SETスイッチ = OFF か？
		goto	set05		;No

		btfss	swstate,4	;DOWNスイッチ = OFF か？
		goto	set04		;No

		btfsc	swstate,5	;UPスイッチ = ON か？
		goto	set03		;No

		call	bcd_nn_inc	;月 BCD カウンタのインクリメント
		goto	set03

set04		call	bcd_nn_dec	;月 BCD カウンタのデクリメント
		goto	set03

		; 日の処理

set05		movlw	h'0c'		;"SH","SL" 桁
		movwf	dspdigit	;表示桁指定フラグの設定
		call	nixie_display	;ニキシー管の表示
		btfss	swstate,6	;SETスイッチ = OFF か？
		goto	set07		;No

		btfss	swstate,4	;DOWNスイッチ = OFF か？
		goto	set06		;No

		btfsc	swstate,5	;UPスイッチ = ON か？
		goto	set05		;No

		call	bcd_dd_inc	;日 BCD カウンタのインクリメント
		goto	set05

set06		call	bcd_dd_dec	;日 BCD カウンタのデクリメント
		goto	set05

set07		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	tempfsr		;間接アドレスの先頭番地の設定
		clrf	cnt_high	;１秒カウンタの初期設定
		clrf	cnt_low
		clrf	bcd_ss		;秒 BCD カウンタのクリア
		movlw	h'f2'		;"HH","HL",":","MH","ML",":" 桁
		movwf	dspdigit	;表示桁指定フラグの設定

		; 時の処理

set08		call	nixie_display	;ニキシー管の表示
		btfss	swstate,6	;SETスイッチ = OFF か？
		goto	set10		;No

		btfss	swstate,4	;DOWNスイッチ = OFF か？
		goto	set09		;No

		btfsc	swstate,5	;UPスイッチ = ON か？
		goto	set08		;No

		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'24'
		subwf	bcd_hh,W
		btfsc	STATUS,C	;時 BCD カウンタ < h'24' か？
		clrf	bcd_hh		;No. 時 BCD カウンタのクリア
		goto	set08

set09		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	dec_bcd		;BCDデクリメント
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	bcd_hh,W
		btfss	STATUS,Z	;時 BCD カウンタ = h'f9' か？
		goto	set08		;No

		movlw	h'23'
		movwf	bcd_hh		;時 BCD カウンタ = h'23' 設定
		goto	set08

		; 分の処理

set10		call	nixie_display	;ニキシー管の表示
		btfss	swstate,6	;SETスイッチ = OFF か？
		goto	set12		;No

		btfss	swstate,4	;DOWNスイッチ = OFF か？
		goto	set11		;No

		btfsc	swstate,5	;UPスイッチ = ON か？
		goto	set10		;No

		movlw	bcd_mm		;分 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_mm,W
		btfsc	STATUS,C	;分 BCD カウンタ < h'60' か？
		clrf	bcd_mm		;No. 分 BCD カウンタのクリア
		goto	set10

set11		movlw	bcd_mm		;分 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	dec_bcd		;BCDデクリメント
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	bcd_mm,W
		btfss	STATUS,Z	;分 BCD カウンタ = h'f9' か？
		goto	set10		;No

		movlw	h'59'
		movwf	bcd_mm		;分 BCD カウンタ = h'59' 設定
		goto	set10

set12		clrf	modeflg		;MODEフラグの初期設定
		bsf	INTCON,GIE	;全割り込み禁止解除
		return		

;==========================================================================
;	ニキシー管の表示とスイッチチェック
;==========================================================================

		; ニキシー管の表示

nixie_display
		movf	tempfsr,W	;間接アドレスの先頭番地
		movwf	FSR
		btfss	dspdigit,7	;表示桁指定フラグ = 7 ("HH") on か？
		goto	nxdsp01		;No

		swapf	INDF,W		;上位4ビット
		movwf	PORTC
		movlw	h'80'		;"HH" 桁
		movwf	PORTB

nxdsp01		call	dimmer_cntrl	;ディマーコントロール
		btfss	dspdigit,6	;表示桁指定フラグ = 6 ("HL") on か？
		goto	nxdsp02		;No

		movf	INDF,W		;下位4ビット
		movwf	PORTC
		movlw	h'40'		;"HL" 桁
		btfsc	dspdigit,0	;表示桁指定フラグ = 0 ("Period") off か？
		movlw	h'41'		;"HL" 桁 + .("Period")
		movwf	PORTB

nxdsp02		call	dimmer_cntrl	;ディマーコントロール
		incf	FSR,F		;間接アドレス +1 更新
		btfss	dspdigit,5	;表示桁指定フラグ = 5 ("MH") on か？
		goto	nxdsp03		;No

		swapf	INDF,W		;上位4ビット
		movwf	PORTC
		movlw	h'20'		;"MH" 桁
		btfsc	dspdigit,1	;表示桁指定フラグ = 1 ("Colon") off か？
		movlw	h'22'		;"MH" 桁 + :("Colon")
		movwf	PORTB

nxdsp03		call	dimmer_cntrl	;ディマーコントロール
		btfss	dspdigit,4	;表示桁指定フラグ = 4 ("ML") on か？
		goto	nxdsp04		;No

		movf	INDF,W		;下位4ビット
		movwf	PORTC
		movlw	h'10'		;"ML" 桁
		btfsc	dspdigit,0	;表示桁指定フラグ = 0 ("Period") off か？
		movlw	h'11'		;"ML" 桁 + .("Period")
		movwf	PORTB

nxdsp04		call	dimmer_cntrl	;ディマーコントロール
		incf	FSR,F		;間接アドレス +1 更新
		btfss	dspdigit,3	;表示桁指定フラグ = 3 ("SH") on か？
		goto	nxdsp05		;No

		swapf	INDF,W		;上位4ビット
		movwf	PORTC
		movlw	h'08'		;"SH" 桁
		movwf	PORTB

nxdsp05		call	dimmer_cntrl	;ディマーコントロール
		btfss	dspdigit,2	;表示桁指定フラグ = 2 ("SL") on か？
		goto	nxdsp06		;No

		movf	INDF,W		;下位4ビット
		movwf	PORTC
		movlw	h'04'		;"SL" 桁
		movwf	PORTB

nxdsp06		call	dimmer_cntrl	;ディマーコントロール

		; スイッチチェック

		movf	PORTC,W
		movwf	swstate		;スイッチの状態(ON:0／OFF:1)を読み込む
		movlw	h'f0'
		andwf	swstate,F
		movlw	h'f0'
		subwf	swstate,W
		btfss	STATUS,Z	;スイッチON がなかったか？
		goto	nxdsp07		;No

		clrf	chatter		;チャタリング補正カウンタのクリア
		goto	nxdsp09

nxdsp07		incf	chatter,F	;チャタリング補正カウンタの +1 更新
		movlw	h'01'
		subwf	chatter,W
		btfsc	STATUS,Z	;チャタリング補正カウンタ <> 1 か？
		goto	nxdsp10		;No

		movlw	d'60'
		subwf	chatter,W
		btfss	STATUS,Z	;チャタリング補正カウンタ = 60 か？
		goto	nxdsp08		;No

		movlw	d'50'
		movwf	chatter		;チャタリング補正カウンタ = 50 に設定
		goto	nxdsp10

nxdsp08		movlw	h'f0'
		movwf	swstate		;スイッチのON／OFF状態をすべて OFF に戻す

nxdsp09		btfss	updtflg,0	;時分秒更新フラグ = ON か？
		goto	nixie_display	;No.

		bcf	updtflg,0	;時分秒更新フラグのクリア

nxdsp10		return		

;==========================================================================

;		ディマーコントロール

dimmer_cntrl
		call	wait_100us
		call	wait_100us
		btfsc	updtflg,2	;ディマー制御フラグ = OFF か？
		clrf	PORTB		;No.

		movlw	h'02'
		movwf	wtcnt1
		call	wait_1xms	;2m 秒 ウェイト
		clrf	PORTB

		call	wait_100us
		call	wait_100us
		call	wait_100us
		return		

;		日 BCD カウンタのインクリメント

bcd_dd_inc
		incf	bcd_dd,F	;日 BCD カウンタ +1 更新
		movf	bcd_dd,W
		movwf	work1
		movlw	h'0f'
		andwf	work1,F		;下位4ビット
		movlw	h'0a'
		subwf	work1,W
		btfss	STATUS,Z	;work1 = 10 か？
		goto	ddinc01		;No

		movlw	h'06'
		addwf	bcd_dd,F	;下位4ビット = 0, 上位4ビット = +1

ddinc01		call	month_days	;各月の日数計算
		movwf	work1		;各月の日数
		movf	bcd_dd,W
		subwf	work1,W
		btfss	STATUS,C	;日 BCD カウンタ =< work1 か？
		goto	ddinc02		;No
		return		

ddinc02		movlw	h'01'
		movwf	bcd_dd		;日 BCD カウンタ = h'01' 設定
		return		

;		各月の日数計算

month_days
		movlw	h'02'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'02' か？
		goto	mday03		;No

		movlw	h'00'
		subwf	bcd_yy,W
		btfsc	STATUS,Z	;年 BCD カウンタ <> h'00' か？
		goto	mday01		;No

		movf	bcd_yy,W
		movwf	work1
		movlw	h'03'
		andwf	work1,F		;下位2ビット
		movlw	h'00'
		subwf	work1,W
		btfsc	STATUS,Z	;work1 <> 0 か？
		goto	mday02		;No

mday01		movlw	h'28'		;平年 2月
		goto	mday05

mday02		movlw	h'29'		;閏年 2月
		goto	mday05

mday03		movlw	h'04'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ <> h'04' か？
		goto	mday04		;No

		movlw	h'06'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ <> h'06' か？
		goto	mday04		;No

		movlw	h'09'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ <> h'09' か？
		goto	mday04		;No

		movlw	h'11'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ <> h'11' か？
		goto	mday04		;No

		movlw	h'31'		;h'01', h'03', h'05', h'07', h'08', h'10', h'12'
		goto	mday05

mday04		movlw	h'30'		;h'04', h'06', h'09', h'11'

mday05		return

;		月 BCD カウンタのインクリメント

bcd_nn_inc
		incf	bcd_nn,F	;月 BCD カウンタ +1 更新
		movf	bcd_nn,W
		movwf	work1
		movlw	h'0f'
		andwf	work1,F		;下位4ビット
		movlw	h'0a'
		subwf	work1,W
		btfss	STATUS,Z	;work1 = 10 か？
		goto	nninc01		;No
		movlw	h'06'
		addwf	bcd_nn,F	;下位4ビット = 0, 上位4ビット = +1

nninc01		movlw	h'13'
		subwf	bcd_nn,W
		btfss	STATUS,C	;月 BCD カウンタ >= h'13' か？
		return			;No

		movlw	h'01'
		movwf	bcd_nn		;月 BCD カウンタ = h'01' 設定
		return		

;		年 BCD カウンタのインクリメント

bcd_yy_inc
		incf	bcd_yy,F	;年 BCD カウンタ +1 更新
		movf	bcd_yy,W
		movwf	work1
		movlw	h'0f'
		andwf	work1,F		;下位4ビット
		movlw	h'0a'
		subwf	work1,W
		btfss	STATUS,Z	;work1 = 10 か？
		goto	yyinc01		;No

		movlw	h'06'
		addwf	bcd_yy,F	;下位4ビット = 0, 上位4ビット = +1

yyinc01		movlw	h'a0'
		subwf	bcd_yy,W
		btfss	STATUS,C	;年 BCD カウンタ >= 'a0' か？
		return			;No

		clrf	bcd_yy		;年 BCD カウンタ = h'00' 設定
		return		

;		日 BCD カウンタのデクリメント

bcd_dd_dec
		decf	bcd_dd,F	;日 BCD カウンタ -1 更新
		btfsc	STATUS,Z	;日 BCD カウンタ <> h'00' か？
		goto	dddec01		;No

		movf	bcd_dd,W
		movwf	work1
		movlw	h'0f'
		andwf	work1,F		;下位4ビット
		subwf	work1,W
		btfss	STATUS,Z	;work1 = h'0f' か？
		return			;No

		movlw	h'06'
		subwf	bcd_dd,F	;日 BCD カウンタ 更新
		return		

dddec01		call	month_days	;各月の日数計算
		movwf	bcd_dd		;日 BCD カウンタ 設定
		return		

;		月 BCD カウンタのデクリメント

bcd_nn_dec
		decf	bcd_nn,F	;月 BCD カウンタ -1 更新
		btfss	STATUS,Z	;月 BCD カウンタ = h'00' か？
		goto	nndec01		;No

		movlw	h'12'
		goto	nndec02

nndec01		movlw	h'0f'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'0f' か？
		return			;No

		movlw	h'09'

nndec02		movwf	bcd_nn		;月 BCD カウンタの設定
		return		

;		年 BCD カウンタのデクリメント

bcd_yy_dec
		decf	bcd_yy,F	;年 BCD カウンタ -1 更新
		movlw	h'ff'
		subwf	bcd_yy,W
		btfss	STATUS,Z	;年 BCD カウンタ = h'ff' か？
		goto	yydec01		;No

		movlw	h'66'
		goto	yydec02

yydec01		movf	bcd_yy,W
		movwf	work1
		movlw	h'0f'
		andwf	work1,F		;下位4ビット
		subwf	work1,W
		btfss	STATUS,Z	;work1 = h'0f' か？
		return			;No

		movlw	h'06'

yydec02		subwf	bcd_yy,F	;年 BCD カウンタ 更新
		return		

;		BCDデクリメント

dec_bcd
		decf	INDF,F		;-1 更新
		movf	INDF,W
		movwf	work2
		movlw	h'0f'
		andwf	work2,F		;下位4ビット
		subwf	work2,W
		btfss	STATUS,Z	;work2 = h'0f' か？
		return			;No

		movlw	h'06'
		subwf	INDF,F		;下位4ビット = 9
		return		

;==========================================================================
;	ウェイト・ルーチン (12.8 MHz)
;==========================================================================

;		100μ秒 ウェイトルーチン

wait_100us
		movlw	d'105'		;1
		movwf	wtcnt1		;1

wt01		decfsz	wtcnt1,F	;1,2
		goto	wt01		;2,0	1+1+(1+2)*104+(2+0)=316

		return			;2	316+2=318
					;Total	318/12.8MHz*4 = 99.375 μS

;		22μ秒 ウェイトルーチン

wait_22us
		movlw	d'22'		;1
		movwf	wtcnt1		;1

wt02		decfsz	wtcnt1,F	;1,2
		goto	wt02		;2,0	1+1+(1+2)*21+(2+0)=67

		return			;2	67+2=69
					;Total	69/12.8MHz*4 = 21.5625 μS

;		1x m秒 ウェイトルーチン

wait_1xms
		movlw	h'00'		;1
		movwf	wtcnt2		;1

wt03		nop			;1
		nop			;1
		nop			;1
		nop			;1
		nop			;1
		nop			;1
		nop			;1
		nop			;1
		nop			;1
		decfsz	wtcnt2,F	;1,2
		goto	wt03		;2,0	1+1+(1*9+1+2)*255+(1*9+2+0)=3073

		decfsz	wtcnt1,F	;1,2
		goto	wait_1xms	;2,0	(wtcnt1-1)*(3073+1+2)+(3073+2+0)=3076x+3075

		return			;2	3076x+3075+2=3076x+3077
					;Total	(3076x+3077)/12.8MHz*4 = 961.25x + 961.5625 mS

;==========================================================================
;	割り込み処理
;==========================================================================

interrupt
		movwf	w_save		;W レジスタの保存
		swapf	STATUS,W
		clrf	STATUS
		movwf	s_save		;STATUS レジスタの保存
		movf	PCLATH,W
		movwf	p_save		;PCLATH レジスタの保存
		clrf	PCLATH
		movf	FSR,W
		movwf	f_save		;FSR レジスタの保存
		btfss	INTCON,T0IF	;タイマ０オーバフロー か？
		goto	int02		;No

		; タイムアウト割り込み処理

		incfsz	cnt_low,F	;１秒カウンタcnt_low = +1 更新
;		btfsc	PCLATH,7	;????????????????????????????
		goto	$+2		;(オリジナルの上記命令を変更)
		incf	cnt_high,F

		; 100m秒 チェック	;(1/(12.8M/4) * 4(プリスケーラ値) * 256) * 312 = 99840μS = 100mS

		movlw	h'38'		;h'0138' = d'312'
		subwf	cnt_low,W
		btfss	STATUS,Z	;１秒カウンタcnt_low = h'38' か？
		goto	int01		;No

		movlw	h'01'
		subwf	cnt_high,W
		btfss	STATUS,Z	;１秒カウンタcnt_high = h'01' か？
		goto	int01		;No

		bcf	PORTA,5		;１秒パルス(幅100ms) OFF 出力

		; 1秒 チェック		;1秒 / (1/(12.8M/4) * 4(プリスケーラ値) * 256) = 3125

int01		movlw	h'35'		;h'0C35' = d'3125'
		subwf	cnt_low,W
		btfss	STATUS,Z	;１秒カウンタcnt_low = h'35' か？
		goto	int02		;No

		movlw	h'0c'
		subwf	cnt_high,W
		btfss	STATUS,C	;１秒カウンタcnt_high >= h'0c' か？
		goto	int02		;No

		clrf	cnt_high	;１秒カウンタの初期設定
		clrf	cnt_low
		call	bcd_ssmmhh_inc	;時分秒 BCD カウンタのインクリメント
		bsf	PORTA,5		;１秒パルス(幅100ms) ON 出力
		bsf	updtflg,0	;時分秒更新フラグのセット

int02		movlw	h'a0'		;GIE: 全割り込み禁止解除, 
		movwf	INTCON		;T0IE: タイマー(TMR0)オーバーフロー割り込み許可
		clrf	STATUS
		movf	f_save,W
		movwf	FSR		;FSR レジスタの復帰
		movf	p_save,W
		movwf	PCLATH		;PCLATH レジスタの復帰
		swapf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰	

;		時分秒 BCD カウンタのインクリメント

bcd_ssmmhh_inc
		movlw	bcd_ss		;秒 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	inc_bcd		;秒 bcd_ss BCDインクリメント
		movlw	h'60'
		subwf	bcd_ss,W
		btfss	STATUS,C	;bcd_ss >= h'60' か？
		return			;No

		clrf	bcd_ss		;bcd_ss = h'00'
		movlw	bcd_mm		;分 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	inc_bcd		;分 bcd_mm BCDインクリメント
		movlw	h'60'
		subwf	bcd_mm,W
		btfss	STATUS,C	;bcd_mm >= h'60' か？
		return			;No

		clrf	bcd_mm		;bcd_mm = h'00'

;		時 BCD カウンタのインクリメント

bcd_hh_inc
		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	FSR		;間接アドレスの先頭番地の設定
		call	inc_bcd		;時 bcd_hh BCDインクリメント
		movlw	h'24'
		subwf	bcd_hh,W
		btfss	STATUS,C	;bcd_hh >= h'24' か？
		return			;No

		bsf	updtflg,1	;年月日更新フラグのセット
		clrf	bcd_hh		;bcd_hh = h'00'
		return		

;		BCDインクリメント

inc_bcd
		incf	INDF,F		;+1 更新
		movf	INDF,W
		movwf	work2
		movlw	h'0f'
		andwf	work2,F		;下位4ビット
		movlw	h'0a'
		subwf	work2,W
		btfss	STATUS,Z	;work2 = 10 か？
		return			;No

		movlw	h'06'
		addwf	INDF,F		;下位4ビット = 0, 上位4ビット = +1
		return		

;==========================================================================
;	Binary-to-BCD.  Written by John Payson.
;	Enter with 16-bit binary number in NumH:NumL.
;	Exits with BCD equivalent in TenK:Thou:Hund:Tens:Ones.
;==========================================================================

Convert
		swapf	NumH,W
		andlw	h'0f'
		addlw	h'f0'
		movwf	Thou
		addwf	Thou,F
		addlw	h'e2'
		movwf	Hund
		addlw	h'32'
		movwf	Ones

		movf	NumH,W
		andlw	h'0f'
		addwf	Hund,F
		addwf	Hund,F
		addwf	Ones,F
		addlw	h'e9'
		movwf	Tens
		addwf	Tens,F
		addwf	Tens,F

		swapf	NumL,W
		andlw	h'0f'
		addwf	Tens,F
		addwf	Ones,F

		rlf	Tens,F
		rlf	Ones,F
		comf	Ones,F
		rlf	Ones,F

		movf	NumL,W
		andlw	h'0f'
		addwf	Ones,F
		rlf	Thou,F

		movlw	h'07'
		movwf	TenK

		movlw	h'0a'

Lb1		addwf	Ones,F
		decf	Tens,F
		btfss	STATUS,C
		goto	Lb1

Lb2		addwf	Tens,F
		decf	Hund,F
		btfss	STATUS,C
		goto	Lb2

Lb3		addwf	Hund,F
		decf	Thou,F
		btfss	STATUS,C
		goto	Lb3

Lb4		addwf	Thou,F
		decf	TenK,F
		btfss	STATUS,C
		goto	Lb4
		return		

		end			;プログラムの終了
