;***** ElapsedClockII.asm *************************************************
;
;	アラーム音通知型経過時計II
;
;	Copyright (C) 2016-2017   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2016/08/25  by M.Yamamoto )
;	coding:  Ver. 1.00   2016/09/21  初期バージョン
;	coding:  Ver. 1.01   2017/01/07  コメントの修正
;	bugfix:  Ver. 1.10   2017/06/21  基準時間の未調整と"時"更新の修正
;	update:  Ver. 1.20   2017/07/01  タイマー機能を追加
;
;******************************************************* PicAsm 0241 ******

;	Device: PIC16F628A	Clock: 4MHz (Internal OSC)

#ifdef comment

 <機能概要>

・本機は、アラーム音で時間の経過を通知する経過時計である。利用法はいろいろと考えられるが、たとえば、何かの作業をするときに、刻々と経
　過して行く時間を、目を作業から離すことなくアラーム音で把握しながら作業をしたい、というような場合などに使用するのを目的とする。

・まず、本機の電源をＯＮにすると、５桁の７セグＬＥＤ（1S、10S、1M、10M、1H）の Dp（デシマルポイント）が数秒間点滅を繰り返した後、開始
　音としての "ドミソド" ブザー音が出力される。その後本機は、スイッチの操作待ち状態となって、ユーザのスイッチ操作を待ち続ける。

・この状態のとき、STARTスイッチを操作することによって経過時計の動作が開始される。経過時計が動作すると刻々と"秒" が刻まれ続け、以降、
　"音" と "光" でそのときの時間経過を知らせる。（"光" はあくまで補助）

・毎 "秒" の更新ごとに "ピッ"、"ピッ"、"ピッ"、"ピッ"、・・・ と "秒" アラーム音が断続的に鳴り続ける。また、"秒" アラーム音に加え、毎 
　"十秒" ごとには "ポッ" という "十秒" アラーム音が鳴る。このとき "十秒" アラーム音の方が優先で "秒" アラーム音は鳴らない。
　（"秒"アラーム = "ピッ": ソ音 (約 392 Hz)、"十秒"アラーム = "ポッ": ド音 (約 523 Hz)）

・同様に、毎 "分" ごとには "ポポッ" という "分" アラーム音が鳴り、毎 "十分" ごとには "ポポポポッ" という "十分" アラーム音が鳴る。そ
　してかつ、その後に "ピポッ" という "十分" 数アラーム音がその数だけ鳴り続いて、何十分経過したかを知らせる。

・これらのアラーム音をまとめると次のようになり、優先順位は下に行くほど高く、同時に発生した低い優先順位のものは無視される。

	毎 "秒" の更新ごと	　"ピッ"
	毎 "十秒" の更新ごと	　"ポッ"
	毎 "分" の更新ごと	　"ポポッ"
	毎 "十分" の更新ごと	　"ポポポポッ"、"ピポッ"（ 0 ～ 5 回 ）
	毎タイマー時間の経過ごと　"ピポッピポッピポッピポッ"、"ピポッピポッピポッピポッ"　（下記の追加機能）

・以上は、この経過時計での主役であるアラーム音についての説明であるが、毎 "分" の更新ごとには "分" アラーム音に加えて、補助的に５秒間
　だけに限り、そのときの経過時間を５桁の７セグＬＥＤで表示をする。ＬＥＤ表示を毎分５秒間に限ったのは、本機は電池駆動としたためその消
　費電流を極力抑えたいための処置である。

・ただし、毎 "分" の更新ごとに限らず DISPLAYスイッチを操作することによって、経過時計の動作中であればいつでも５秒間だけ、そのときの経
　過時間を７セグＬＥＤで表示をさせることができる。

・本機では、経過時間は "9 時 59 分 59 秒" が最大であるが、その１秒後には、再び "0 時 00 分 00 秒" の STARTスイッチの押下直後の状態に
　戻って、以上のように、アラーム音と７セグＬＥＤでの補助表示を繰り返して、時間経過のカウントを永遠にし続ける。

・このように、経過時計が動作中は時間の経過とともに１秒ごとに何らかのアラーム音が鳴り続けることになるが、場合によっては、毎 "秒" ごと
　の "秒" アラーム音が煩わしく感じる場合があり、そのようなときには SUPPRESSスイッチを操作することによって、"秒" アラーム音だけを抑止
　して鳴らないようにすることができる。

・この SUPPRESSスイッチは、STARTスイッチによる経過時計の動作の開始前後を問わずいつでも機能する。また、この SUPPRESSスイッチは押下する
　ごとにその機能のＯＮ／ＯＦＦを繰り返してトグル動作をする。

・また、STARTスイッチは上記のように、経過時計の動作の開始前には文字通り STARTスイッチとして機能するが、一方、経過時計の動作中に押下す
　ると CANCELスイッチとして機能し、経過時計の動作が停止する。このとき "ブッブー" という操作音を鳴らす。これに対して、STARTスイッチと
　しての機能のときには、特に操作音を鳴らすことはないが、この操作直後に "ポポポポッ" という "十分" アラーム音が鳴ってそれに代用をして
　いる。

・このように、通常は STARTスイッチで経過時計を動作させ、CANCELスイッチで経過時計を停止終了させるが、経過時計の動作中に PAUSEスイッチ
　を操作すると、経過時間のカウントを一時的に停止させることができる。また、再び同スイッチを押下すると CONTINUEスイッチとして機能し、
　経過時間のカウントを再び続行する。このスイッチも押下するごとに PAUSE／CONTINU の機能を繰り返すトグル動作を行う。

・上述の DISPLAYスイッチ、SUPPRESSスイッチ、PAUSE／CONTINUスイッチを操作したときには、"ブブッ" という操作音が鳴る。

・CANCELスイッチの操作で停止した経過時計も、次の STARTスイッチの操作で、再び "0 時 00 分 00 秒" から経過時計の動作が開始される。

　タイマー機能を追加
　------------------

・上記機能に加え、あらかじめ設定しておいた時間が経過するごとに、新たなアラーム音によってそれを通知するという機能を追加した。

・この追加機能を動作させるためには、まず、タイマー設定モードに移行してタイマー時間の設定をする。タイマー設定モードに移行するためには、
　経過時計の動作中はだめで必ず経過時計の動作前に、DISPLAYスイッチを押しながら STARTスイッチを押下することによる。（ここでスイッチを
　押下する順番は重要で、先に STARTスイッチを押下すると、当然ながら通常の START機能として経過時計が動作をしてしまうので注意。）

・タイマー設定モードに移行すると、現在設定されているタイマー時間（初期値は 00 分、以降は最終的に設定された時間）がＬＥＤに表示される。

・タイマー時間の指定は "分" のみで、その範囲は２桁ＬＥＤが取り得る値で 00 分 ～ 99 分 で指定をする。 00 分指定はタイマーの無指定を意
　味する。

・PAUSE / CONTINUE スイッチを押下するごとに "十分"ＬＥＤが +1 づつ更新される。　　0, 1, 2, 3, ・・・, 8, 9, 0, ・・・

・また、SUPPRESS スイッチを押下するごとに "分"ＬＥＤが +1 づつ更新される。  　　　0, 1, 2, 3, ・・・, 8, 9, 0, ・・・

・上記２個のスイッチで希望するタイマー時間の指定が済んだら、次に、DISPLAYスイッチを押下すると、タイマー設定モードから再び通常のモード
　に移行することができる。（ここで設定されたタイマー時間は、ＰＩＣのEEPROMに記録されるため、その内容は次回の設定変更まで保持される）

・この状態で STARTスイッチを押下して経過時計を動作させると、通常のアラーム音に加えて、今設定されたタイマー時間間隔でタイマーアラーム
　音が、"ピポッピポッピポッピポッ、ピポッピポッピポッピポッ" と鳴動してタイマー時間が経過したことを知らせる。

・たとえば、タイマー時間が "45分" に設定されているとすると、"45分" 間隔で、すなわち、経過時間が "0 時 45 分 00 秒"、"1 時 30 分 00 秒"、
　"2 時 15 分 00 秒"、"3 時 00 分 00 秒"、"3 時 45 分 00 秒"、・・・ という具合にタイマーアラーム音が鳴ることになる。

・また、タイマー機能をＯＦＦにしたい場合には、上記のように一旦タイマー設定モードに移行して、タイマー時間を 00 分に指定する必要がある。

・本機では、元々長時間での連続使用は想定してはいないため（乾電池駆動、時間表示用ＬＥＤも１桁）、長時間の使用では数秒の誤差が現れる
　（基準周波数の発振にクリスタル等を用いずＰＩＣの内部発振を使用）。 そのため、タイマー時間の指定も "分" のみで、"時" や "秒" の指定
　は設けてはいない。

#endif

;==========================================================================

;	PIC16F628A のピンと用途

;	 (1) RA2: 7セグLED  1M 桁出力			(18) RA1: 7セグLED 10S 桁出力
;	 (2) RA3: 7セグLED 10M 桁出力			(17) RA0: 7セグLED  1S 桁出力
;	 (3) RA4: 7セグLED  1H 桁出力			(16) RA7: アラーム音出力
;	 (4) RA5: 未使用				(15) RA6: /BUSY 信号(debug用)
;	 (5) VSS: 電源 GND				(14) VDD: 電源 +5V DC
;	 (6) RB0: a 出力 / START/CANCELスイッチ入力	(13) RB7: dp 出力
;	 (7) RB1: b 出力 / PAUSE/CONTINUEスイッチ入力	(12) RB6: g 出力
;	 (8) RB2: c 出力 / SUPPRESSスイッチ入力		(11) RB5: f 出力
;	 (9) RB3: d 出力 / LED DISPLAYスイッチ入力	(10) RB4: e 出力 / 予備スイッチ入力

;	*注.  RA4 の出力はオープンドレインのため、外部抵抗でプルアップしないと、High が出力されない。
;	      RA5 は入力専用で、出力ポートには使えない。

;==========================================================================

	list		p=pic16f628a		;デバイス情報
	include		p16f628a.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

		__config 	 h'3f10'

;		  _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF
;		& _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT

;==========================================================================
;		変数、定数の定義とレジスタ割付け
;==========================================================================

		radix	dec

xx		equ	16			;補正値-1
tm0_h_val	equ	256 - 200 + xx		;ハードタイマー０カウント値 (4 / 4MHz * 200 = 200μS)
yy		equ	0			;補正値-2
tm0_s_val	equ	5000 + yy		;ソフトタイマー０のカウント値

stsw		equ	0			;RB0: START(CANCEL) スイッチ
paussw		equ	1			;RB1: PAUSE(CONTINUE) スイッチ
suppsw		equ	2			;RB2: SUPPRESS スイッチ
dispsw		equ	3			;RB3: LED DISPLAY スイッチ
resvsw		equ	4			;RB4: 予備 スイッチ
ra0		equ	0			;RA0: LED 秒の桁
ra1		equ	1			;RA1: LED 十秒の桁
ra2		equ	2			;RA2: LED 分の桁
ra3		equ	3			;RA3: LED 十分の桁
ra4		equ	4			;RA4: LED 時の桁
ra6		equ	6			;RA6: /BUSY 信号(debug用)
buzzer		equ	7			;RA7: アラーム音 出力

f_doh		equ	65536 -  956		;ド (523.26 Hz)  at 4MHz
f_so		equ	65536 - 1276		;ソ (392.00 Hz)
f_mi		equ	65536 - 1517		;ミ (329.63 Hz)
f_do		equ	65536 - 1911		;ド (261.63 Hz)
po_tim		equ	100			;音長(ms)
pi_tim		equ	100			;音長
bu_tim		equ	100			;音長
buu_tim		equ	250			;音長
dms_tim		equ	200			;音長

seg7_0		equ     b'11000000'		;-gfedcba Pattern 0
seg7_1		equ     b'11111001'		;         Pattern 1
seg7_2		equ     b'10100100'		;         Pattern 2
seg7_3		equ     b'10110000'		;         Pattern 3
seg7_4		equ     b'10011001'		;         Pattern 4
seg7_5		equ     b'10010010'		;         Pattern 5
seg7_6		equ     b'10000010'		;         Pattern 6
seg7_7		equ     b'11111000'		;         Pattern 7
seg7_8		equ     b'10000000'		;         Pattern 8
seg7_9		equ     b'10010000'		;         Pattern 9
seg7_d		equ     b'11110111'		;         d-seg
seg7_off	equ     b'11111111'		;         LED off


		cblock	h'40'
tm0_cnt_h					;ソフトタイマー０の high カウンタ
tm0_cnt_l					;ソフトタイマー０の low  カウンタ
const_high					;音階用分周定数 high の保存
const_low					;音階用分周定数 low の保存
sw_stat						;全スイッチの入力状態を一時保存
start_flg					;START フラグ（カウント中表示）
alm_flg						;アラームフラグ
cnt_alm_m10					;"十分"数アラームカウンタ
supp_flg					;"秒"アラーム音抑止フラグ
dsplc						;時間表示ループカウンタ
disp_cnt					;LED表示カウンタ
cnt_hou01					;経過"時"カウンタ
cnt_min10					;経過"十分"カウンタ
cnt_min01					;経過"分"カウンタ
cnt_sec10					;経過"十秒"カウンタ
cnt_sec01					;経過"秒"カウンタ
count_bin2					;経過カウンタのバイナリ変換値2
count_bin					;経過カウンタのバイナリ変換値
tim_min10					;タイマー"十分"カウンタ
tim_min01					;タイマー"分"カウンタ
timer_bin					;タイマーカウンタのバイナリ変換値
cnv_cnt						;変換カウンタ
set_mode					;タイマー設定モードフラグ
eep_cnt						;記録データ数
led_digit					;LED デモ表示桁
led_cnt						;LED デモ表示用カウンタ
wt1cnt						;ウェイト用ループカウンタ
wt2cnt						;ウェイト用ループカウンタ
wt3cnt						;ウェイト用ループカウンタ
		endc

		cblock	h'70'
w_save						;W レジスタの退避用
s_save						;STATUS レジスタの退避用
		endc

;==========================================================================
;		マクロ命令定義
;==========================================================================

;		Sound_M マクロ

Sound_M		macro	@scale,@time
		movlw	high @scale	;出力音階
		movwf	const_high
		movlw	low @scale
		movwf	const_low
		movlw	@time		;出力時間(ms)
		call	buzzer_control	;ブザー音出力コントロール
		endm


;==========================================================================
;		プログラム開始
;==========================================================================

		org	h'0000'		;リセットベクタ
		goto	start

		org	h'0004'		;割り込みベクタ
		goto	interrupt

;==========================================================================
;		W に指定された 0～9 の数字を 表示パターンに変換
;	（PCL を操作する場合はプログラムを配置する位置に配慮すること）
;==========================================================================

ptn_set
		addwf	PCL,F		;プログラム・カウンタに加算

		retlw	seg7_0		;0
		retlw	seg7_1		;1
		retlw	seg7_2		;2
		retlw	seg7_3		;3
		retlw	seg7_4		;4
		retlw	seg7_5		;5
		retlw	seg7_6		;6
		retlw	seg7_7		;7
		retlw	seg7_8		;8
		retlw	seg7_9		;9

;==========================================================================
;		初期化処理
;==========================================================================

start
		bcf	STATUS,RP1
		bcf	STATUS,RP0	;バンク 0
		clrf	PORTA		;
		movlw	b'00000111'	;RA3-0 を Digital I/O
		movwf	CMCON		;CMCON に設定

		bsf	STATUS,RP0	;バンク 1
		movlw	b'00100000'
		movwf	TRISA		;ポートA の I/0 設定
		movlw	b'00000000'
		movwf	TRISB		;ポートB の I/0 設定

		movlw	b'00001010'	;bit7-4: 使われていない
					;bit3=1: 内部発振周波数は 4MHz
					;bit2:   使われていない
					;bit1=1: パワーオンリセットする
					;bit0=0: ブラウンアウトリセットしない
		movwf	PCON    	;PCON に設定

		movlw	b'10001000'	;bit7=1: PORTB は PULL-UP しない
					;bit6=0: GP2 の割込みは立下りエッジ
					;bit5=0: TMR0 クロックは内部供給
					;bit4=0: TMR0 L から H でカウント
					;bit3=1: TMR0 にプリスケーラを使用しない
					;bit2-0=000: プリスケーラ比
		movwf	OPTION_REG	;OPTION_REG に設定

		bcf	PIE1,TMR1IE	;TMR1IE: タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		bcf	INTCON,T0IE	;T0IE: タイマー０割り込みを禁止

		movlw	b'00000001'	;bit7-6: 未使用
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON に設定

		bsf	PORTA,ra6	;/BUSY 信号(debug用)の出力停止
		bsf	INTCON,PEIE	;PEIE: 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE: グローバル割り込み許可

		; 各変数の初期設定

		clrf	alm_flg		;アラームフラグの初期設定
		clrf	disp_cnt	;LED表示カウンタの初期設定
		clrf	supp_flg	;"秒"アラーム音抑止フラグの初期設定
		clrf	start_flg	;START フラグの初期設定
		clrf	set_mode	;タイマー設定モードの初期設定

		call	led_demo	;LED 点滅デモ
		call	dl_mi_so_dh	;"ドミソド" ブザー音出力

;==========================================================================
;		メイン・ルーチン
;==========================================================================

;		・START スイッチは、CANCEL スイッチも兼ねている
;		　 カウント動作前に ON すると START スイッチとして機能
;		　 カウント動作中に ON すると CANCEL スイッチとして機能

;		・PAUSE スイッチは、カウント動作を一時的に停止するもので、押すごとに
;		　CONTINUE スイッチとトグル動作

;		・SUPPRESS スイッチは、"秒"アラーム音を抑止するもので押すごとにトグル動作

;		・LED DISPLAY スイッチは、カウント動作中であればいつでも、押すごとに
;		　約５秒間 経過時間（7セグ LED）を表示する

		; スイッチの入力状態の読み取り

main		bsf	STATUS,RP0	;バンク 1
		movlw	b'00011111'
		movwf	TRISB		;ポートB の I/0 設定: RB0～RB4入力
		bcf	STATUS,RP0	;バンク 0

		movf	PORTB,W		;全スイッチの入力状態を
		andlw	b'00011111'	;一度に読み取り
		xorlw	b'00011111'	;'0'→'1'に反転して
		movwf	sw_stat		;一時保存する

		bsf	STATUS,RP0	;バンク 1
		clrf	TRISB		;ポートB の I/0 設定: すべて出力
		bcf	STATUS,RP0	;バンク 0
;
		btfss	sw_stat,suppsw	;SUPPRESS スイッチ = ON か？
		goto	m01		;No

		movlw	b'00000001'
		xorwf	supp_flg,F	;"秒"アラーム音抑止フラグをセット／リセット
		call	buzzer_bubu	;"ブブッ" ブザー音出力 (230 mS)
		call	wait_200ms

m01		btfsc	start_flg,0	;START フラグ = ON （カウント中）か？
		goto	m02		;Yes

		btfss	sw_stat,stsw	;START スイッチ = ON か？
		goto	main		;No

		call	eep_rd		;EEPROM データの読み出し

		btfsc	sw_stat,dispsw	;LED DISPLAY スイッチ = ON か？
		goto	time_set	;Yes.	追加機能（タイマー設定モード）へ

		; START スイッチ = ON の処理

		bcf	PORTA,ra6	;/BUSY 信号(debug用)の出力

		call	bin_cnv_time	;タイマーカウンタのバイナリ変換

		clrf	cnt_hou01	;経過"時"カウンタの初期設定
		clrf	cnt_min10	;経過"十分"カウンタの初期設定
		clrf	cnt_min01	;経過"分"カウンタの初期設定
		clrf	cnt_sec10	;経過"十秒"カウンタの初期設定
		clrf	cnt_sec01	;経過"秒"カウンタの初期設定
		bsf	alm_flg,0	;bit0: "秒"カウンタ更新フラグ = 1
		clrf	cnt_alm_m10	;"十分"数アラームカウンタの初期設定
		movlw	5
		movwf	disp_cnt	;LED表示カウンタにセット
		bsf	start_flg,0	;START フラグをセット（カウント中表示）

		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		goto	m07

		; カウント中の処理

m02		btfsc	sw_stat,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m16		;Yes. 終了

		btfss	sw_stat,paussw	;PAUSE スイッチ = ON か？
		goto	m03		;No

		movlw	1 << T0IE
		xorwf	INTCON,F	;タイマー０割り込みを禁止／許可
		goto	m04

m03		btfss	sw_stat,dispsw	;LED DISPLAY スイッチ = ON か？
		goto	m05		;No

		movlw	5 + 1
		movwf	disp_cnt	;LED表示カウンタにセット

m04		call	buzzer_bubu	;"ブブッ" ブザー音出力 (230 mS)
		call	wait_200ms
		goto	main

		; 経過時間（7セグ LED）の表示制御

m05		movf	disp_cnt,W	;LED表示カウンタ = 0 か？
		btfsc	STATUS,Z
		goto	m06		;Yes

		movlw	3		;時間表示ループカウンタ値
		call	time_disp	;

m06		btfss	alm_flg,0	;bit0: "秒"カウンタ更新フラグ = 1 か？
		goto	main		;No

		movf	disp_cnt,W	;LED表示カウンタ = 0 か？
		btfss	STATUS,Z
		decf	disp_cnt,F	;No. disp_cnt - 1

		movf	cnt_sec01,W	;経過"秒"カウンタ = 0 か？
		btfss	STATUS,Z
		goto	m07		;No

		movf	cnt_sec10,W	;経過"十秒"カウンタ = 0 か？
		btfss	STATUS,Z
		goto	m07		;No

;		movf	cnt_min01,W	;経過"分"カウンタ = 0 か？
;		btfss	STATUS,Z
;		goto	m07		;No

		movlw	5
		movwf	disp_cnt	;LED表示カウンタにセット

		; アラームフラグの設定

;		　　　　　　　　┌─── "秒"カウンタ更新フラグ（割り込み処理内でセットされる）
;		　　　　　　　　│
;		０００ｘ．ｘｘｘｘ	;alm_flg: アラームフラグ		;cnt_alm_m10: "十分"数アラーム
;		　　　│　││││
;		　　　│　│││└─── "秒"アラームフラグ	;"ピッ"
;		　　　│　││└──── "十秒"アラームフラグ	;"ポッ"
;		　　　│　│└───── "分"アラームフラグ	;"ポポッ"
;		　　　│　└────── "十分"アラームフラグ	;"ポポポポッ"	;"ピポッ"
;		　　　└──────── タイマーアラームフラグ	;"ピポッピポッピポッピポッ","ピポッピポッピポッピポッ"

m07		movf	cnt_sec01,W
		btfss	STATUS,Z	;経過"秒"カウンタ = 0 か？
		goto	m08		;No

		bcf	STATUS,C
		rlf	alm_flg,F	;bit1: "十秒"アラームフラグ = 1

		movf	cnt_sec10,W
		btfss	STATUS,Z	;経過"十秒"カウンタ = 0 か？
		goto	m08		;No

		rlf	alm_flg,F	;bit2: "分"アラームフラグ = 1

		call	bin_cnv_count	;経過カウンタのバイナリ変換
		call	tim_alm_set	;タイマーアラームフラグの設定
		btfsc	alm_flg,4	;タイマーアラームフラグの設定した か？
		goto	m08		;Yes

		movf	cnt_min01,W
		btfss	STATUS,Z	;経過"分"カウンタ = 0 か？
		goto	m08		;No

		bcf	STATUS,C
		rlf	alm_flg,F	;bit3: "十分"アラームフラグ = 1

		; アラーム音の出力

m08		movf	cnt_alm_m10,W
		btfsc	STATUS,Z	;"十分"数アラームカウンタ = 0 か？
		goto	m10		;Yes

m09		;call	alm_min10s	;"十分"数アラーム音の出力
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		movlw	250
		call	wait_w1ms

		decfsz	cnt_alm_m10,F	;cnt_alm_m10 - 1
		goto	m09
		goto	m15

m10		rrf	alm_flg,F	;"秒"アラームフラグ = 1 か？
		btfss	STATUS,C
		goto	m11		;No

		btfss	supp_flg,0	;"秒"アラーム音抑止フラグ = ON か？
		;call	alm_sec01	;No. "秒"アラーム音の出力
		call	buzzer_pi	;"ピッ" ブザー音出力
		goto	m15

m11		rrf	alm_flg,F	;"十秒"アラームフラグ = 1 か？
		btfss	STATUS,C
		goto	m12		;No

		;call	alm_sec10	;"十秒"アラーム音の出力
		call	buzzer_po	;"ポッ" ブザー音出力
		goto	m15

m12		rrf	alm_flg,F	;"分"アラームフラグ = 1 か？
		btfss	STATUS,C
		goto	m13		;No

		;call	alm_min01	;"分"アラーム音の出力
		call	buzzer_popo	;"ポポッ" ブザー音出力
		goto	m15

m13		rrf	alm_flg,F	;"十分"アラームフラグ = 1 か？
		btfss	STATUS,C
		goto	m14		;No

		;call	alm_min10	;"十分"アラーム音の出力
		call	buzzer_popopopo	;"ポポポポッ" ブザー音出力 (490 mS)

		movf	cnt_min10,W	;アラーム数を
		movwf	cnt_alm_m10	;"十分"数アラームカウンタにセット
		goto	m15

m14		call	buzzer_pipo4	;"ピポッピポッピポッピポッ" ブザー音出力
		call	wait_200ms
		call	buzzer_pipo4	;"ピポッピポッピポッピポッ" ブザー音出力

m15		clrf	alm_flg		;アラームフラグをクリア
		goto	main

		; 終了処理

m16		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		clrf	start_flg	;START フラグをクリア
		movlw	b'11011111'	;LED すべてを消灯
		movwf	PORTA		;
;		bsf	PORTA,ra6	;/BUSY 信号(debug用)の出力停止

		call	buzzer_bubuu	;"ブッブー" ブザー音出力 (450 mS)
		goto	main

;==========================================================================

		; タイマーアラームフラグの設定
tim_alm_set
		movf	count_bin2,F	;経過カウンタ2 のバイナリ変換値

tas01		btfsc	STATUS,Z	;count_bin2 = 0 か？
		goto	tas03		;Yes

		movf	timer_bin,W	;タイマーカウンタのバイナリ変換値

tas02		subwf	count_bin,F
		btfsc	STATUS,C	;経過カウンタ < タイマーカウンタ か？
		goto	tas02		;No

		decf	count_bin2,F	;count_bin2 - 1
		goto	tas01

tas03		movf	timer_bin,W	;タイマーカウンタのバイナリ変換値

tas04		subwf	count_bin,F
		btfss	STATUS,C	;経過カウンタ >= タイマーカウンタ か？
		goto	tas05		;No

		btfss	STATUS,Z	;経過カウンタ = タイマーカウンタ か？
		goto	tas04		;No

		movlw	h'10'
		movwf	alm_flg		;タイマーアラームフラグの設定

tas05		return

		; タイマーカウンタのバイナリ変換
bin_cnv_time
		movf	tim_min01,W	;タイマー"分"カウンタ
		movwf	timer_bin	;バイナリ変換値
		movf	tim_min10,W	;タイマー"十分"カウンタ
		btfsc	STATUS,Z
		goto	bct02

		movwf	cnv_cnt		;変換カウンタ

bct01		movlw	10
		addwf	timer_bin,F	;バイナリ変換値
		decfsz	cnv_cnt,F	;変換カウンタ - 1 = 0 か？
		goto	bct01		;No

bct02		return

		; 経過カウンタのバイナリ変換
bin_cnv_count
		clrf	count_bin2	;経過カウンタ2 のバイナリ変換値
		movf	cnt_min01,W	;経過"分"カウンタ
		movwf	count_bin	;バイナリ変換値
		movf	cnt_min10,W	;経過"十分"カウンタ
		btfsc	STATUS,Z
		goto	bcc02

		movwf	cnv_cnt		;変換カウンタ

bcc01		movlw	10
		addwf	count_bin,F	;バイナリ変換値
		decfsz	cnv_cnt,F	;変換カウンタ - 1 = 0 か？
		goto	bcc01		;No

bcc02		movf	cnt_hou01,W	;経過"時"カウンタ
		btfsc	STATUS,Z
		goto	bcc04

		movwf	cnv_cnt		;変換カウンタ

bcc03		movlw	60
		addwf	count_bin,F	;バイナリ変換値
		btfsc	STATUS,C	;オーバーフローした か？
		incf	count_bin2,F	;Yes. count_bin2 + 1
		decfsz	cnv_cnt,F	;変換カウンタ - 1 = 0 か？
		goto	bcc03		;No

bcc04		return

;==========================================================================
;		タイマー設定モード
;==========================================================================
; SW4: LED DISPLAY スイッチを押しながら SW1: START / CANCEL スイッチを押したとき

; 	SW2: PAUSE / CONTINUE スイッチ: "十分"カウンタの +1 更新
; 	SW3: SUPPRESS スイッチ:         "分"カウンタの +1 更新
; 	SW4: LED DISPLAY スイッチ:      タイマー設定モードから抜け出る

time_set
		call	buzzer_bubu	;"ブブッ" ブザー音出力 (230 mS)
		call	wait_200ms
		call	wait_200ms
		bsf	set_mode,0	;タイマー設定モード = ON

tset01		movlw	3
		call	time_disp	;設定時間（＿ ＸＸ ＿＿）の表示

		bsf	STATUS,RP0	;バンク 1
		movlw	b'00011111'
		movwf	TRISB		;ポートB の I/0 設定: RB0～RB4入力
		bcf	STATUS,RP0	;バンク 0

		movf	PORTB,W		;全スイッチの入力状態を
		andlw	b'00011111'	;一度に読み取り
		xorlw	b'00011111'	;'0'→'1'に反転して
		movwf	sw_stat		;一時保存する

		bsf	STATUS,RP0	;バンク 1
		clrf	TRISB		;ポートB の I/0 設定: すべて出力
		bcf	STATUS,RP0	;バンク 0

		btfsc	sw_stat,paussw	;PAUSE スイッチ = ON か？
		call	sw2_on		;Yes

		btfsc	sw_stat,suppsw	;SUPPRESS スイッチ = ON か？
		call	sw3_on		;Yes

		btfss	sw_stat,dispsw	;LED DISPLAY スイッチ = ON か？
		goto	tset01		;No

		call	eep_wr		;EEPROM データの書き込み
		call	buzzer_bubu	;"ブブッ" ブザー音出力 (230 mS)
		call	wait_200ms
		clrf	set_mode	;タイマー設定モード = OFF
		goto	main

;==========================================================================

		; SW2: PAUSE / CONTINUE スイッチ = ON の処理

sw2_on		incf	tim_min10,F	;タイマー"十分"カウンタの +1 更新
		movlw	10
		subwf	tim_min10,W	;タイマー"十分"カウンタ >= 10 か？
		btfsc	STATUS,C
		clrf	tim_min10	;Yes. タイマー"十分"カウンタ = 0 に設定

		call	wait_200ms
		return

		; SW3: SUPPRESS スイッチ = ON の処理

sw3_on
		incf	tim_min01,F	;タイマー"分"カウンタの +1 更新
		movlw	10
		subwf	tim_min01,W	;タイマー"分"カウンタ >= 10 か？
		btfsc	STATUS,C
		clrf	tim_min01	;Yes. タイマー"分"カウンタ = 0 に設定

		call	wait_200ms
		return

;==========================================================================

		; EEPROM データの読み出し

eep_rd		bsf	STATUS,RP0	;バンク1
		movlw	eep_size
		movwf	EEADR		;EEPROM の記録アドレスを設定
		bcf	STATUS,RP0	;バンク0

		movlw	tim_min10	;タイマー"十分"カウンタの先頭アドレスを
		movwf	FSR		;間接アドレスに設定

		movlw	2
		movwf	eep_cnt		;記録データ数

epr01		bsf	STATUS,RP0	;バンク1
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し

		incf	EEADR,F		;記録アドレスの更新
		bcf	STATUS,RP0	;バンク0

		movwf	INDF		;カウンタデータへ書き込み

		incf	FSR,F		;間接アドレスの更新
		decfsz	eep_cnt,F	;記録データ数 - 1 = 0 か？
		goto	epr01		;No

		return

		; EEPROM データの書き込み

eep_wr		bsf	STATUS,RP0	;バンク1
		movlw	eep_size
		movwf	EEADR		;EEPROM の記録アドレスを設定
		bcf	STATUS,RP0	;バンク0

		movlw	tim_min10	;タイマー"十分"カウンタの先頭アドレスを
		movwf	FSR		;間接アドレスに設定

		movlw	2
		movwf	eep_cnt		;記録データ数

epw01		movf	INDF,W		;カウンタデータの読み出し

		bsf	STATUS,RP0	;バンク1
		movwf	EEDATA		;書き込みデータを設定
		bsf	EECON1,WREN	;書き込みイネーブル = ON
		movlw	h'55'
		movwf	EECON2		;h'55' を EECON2 に書き込む
		movlw	h'aa'
		movwf	EECON2		;h'aa' を EECON2 に書き込む
		bsf	EECON1,WR	;書き込み開始
		btfsc	EECON1,WR	;書き込み 終了か?
		goto	$-1		;No

		incf	EEADR,F		;記録アドレスの更新
		bcf	STATUS,RP0	;バンク0

		incf	FSR,F		;間接アドレスの更新
		decfsz	eep_cnt,F	;記録データ数 - 1 = 0 か？
		goto	epw01		;No

		return

;==========================================================================
;    経過時間（Ｘ.ＸＸ.ＸＸ）／タイマー設定時間（＿ ＸＸ ＿＿）の表示
;==========================================================================

time_disp
		movwf	dsplc		;時間表示ループカウンタの設定

		; 時の桁の表示

tdsp01		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra0	;秒の桁を消灯

		movlw	seg7_d
		btfsc	set_mode,0	;タイマー設定モードフラグ = OFF か？
		goto	tdsp02		;No

		movf	cnt_hou01,W
		call	ptn_set		;cnt_hou01を表示パターンに変換
		andlw	h'7f'		;(dp)を点灯

tdsp02		movwf	PORTB
		bcf	PORTA,ra4	;時の桁を点灯
		call	wait_300us	;１桁の表示時間

		; 十分の桁の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra4	;時の桁を消灯

		movf	cnt_min10,W
		btfsc	set_mode,0	;タイマー設定モードフラグ = OFF か？
		movf	tim_min10,W	;No
		call	ptn_set		;cnt_min10を表示パターンに変換
		movwf	PORTB
		bcf	PORTA,ra3	;十分の桁を点灯
		call	wait_300us	;１桁の表示時間

		; 分の桁の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra3	;十分の桁を消灯

		movf	cnt_min01,W
		btfsc	set_mode,0	;タイマー設定モードフラグ = OFF か？
		movf	tim_min01,W	;No
		call	ptn_set		;cnt_min01を表示パターンに変換
		btfss	set_mode,0	;タイマー設定モードフラグ = ON か？
		andlw	h'7f'		;No. (dp)を点灯
		movwf	PORTB
		bcf	PORTA,ra2	;分の桁を点灯
		call	wait_300us	;１桁の表示時間

		; 十秒の桁の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra2	;分の桁を消灯

		movlw	seg7_d
		btfsc	set_mode,0	;タイマー設定モードフラグ = OFF か？
		goto	tdsp03		;No

		movf	cnt_sec10,W
		call	ptn_set		;cnt_sec10を表示パターンに変換

tdsp03		movwf	PORTB
		bcf	PORTA,ra1	;十秒の桁を点灯
		call	wait_300us	;１桁の表示時間

		; 秒の桁の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra1	;十秒の桁を消灯

		movlw	seg7_d
		btfsc	set_mode,0	;タイマー設定モードフラグ = OFF か？
		goto	tdsp04		;No

		movf	cnt_sec01,W
		call	ptn_set		;cnt_sec01を表示パターンに変換

tdsp04		movwf	PORTB
		bcf	PORTA,ra0	;秒の桁を点灯
		call	wait_300us	;１桁の表示時間

		decfsz	dsplc,F		;時間表示ループカウンタ - 1 = 0 か？
		goto	tdsp01		;No

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra0	;秒の桁を消灯

		return

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; "ピッ" ブザー音出力
buzzer_pi
		Sound_M		f_so, pi_tim
		return

		; "ポッ" ブザー音出力
buzzer_po
		Sound_M		f_doh, po_tim
		return

		; "ピポッ" ブザー音出力 (230 mS)
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_30ms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ピポッピポッピポッピポッ" ブザー音出力 (1010 mS)
buzzer_pipo4
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_30ms
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_30ms
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_30ms
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		return

		; "ポポポポッ" ブザー音出力 (490 mS)
buzzer_popopopo
		call	buzzer_popo	;"ポポッ" ブザー音出力
		call	wait_30ms

		; "ポポッ" ブザー音出力 (230 mS)
buzzer_popo
		call	buzzer_po	;"ポッ" ブザー音出力
		call	wait_30ms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ブッ" ブザー音出力
buzzer_bu
		Sound_M		f_do, bu_tim
		return

		; "ブブッ" ブザー音出力 (230 mS)
buzzer_bubu
		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_30ms
		call	buzzer_bu	;"ブッ" ブザー音出力
		return

		; "ブー" ブザー音出力
buzzer_buu
		Sound_M		f_do, buu_tim
		return

		; "ブッブー" ブザー音出力 (450 mS)
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_100ms
		call	buzzer_buu	;"ブー" ブザー音出力
		return

		; "ドミソド" ブザー音出力 (1,150 mS)
dl_mi_so_dh
		Sound_M		f_do, dms_tim
		call	wait_50ms

		Sound_M		f_mi, dms_tim
		call	wait_50ms

		Sound_M		f_so, dms_tim
		call	wait_50ms

		Sound_M		f_doh, dms_tim
		Sound_M		f_doh, dms_tim
		return

		; ブザー音出力コントロール
buzzer_control
		bsf	STATUS,RP0	;バンク 1
		bsf	PIE1,TMR1IE	;タイマー１割り込みを許可
		bcf	STATUS,RP0	;バンク 0

		call	wait_w1ms	;入力 W: 音長（ループカウンタ）

		bsf	STATUS,RP0	;バンク 1
		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		ウェイト・ルーチン (at 4 MHz)
;==========================================================================

		; 7セグ LED１桁の表示時間
wait_300us
		movlw	100		;1
		movwf	wt3cnt		;1

w3u01		decfsz	wt3cnt,F	;1,2
		goto	w3u01		;2,0	1+1+(1+2)*99+(2+0)=301

		return			;2	301+2=303
					;Total	303/4MHz*4 = 303 μS

		; 1m 秒 x W ウェイトルーチン
wait_w1ms
		movwf	wt2cnt		;1

w1m01		movlw	110		;1
		movwf	wt1cnt		;1

w1m02		goto	$ + 1		;2
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt1cnt,F	;1,2
		goto	w1m02		;2,0	(2+2+2+1+2)*109+(2+2+2+2+0)=989

		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+989+2+2+1+2)*(W-1)+(1+1+989+2+2+2+0)=998*W-1

		return			;2	1+(998*W-1)+2=998*W+2
					;Total	(998*W+2)/4MHz*4 = (998*W + 2) μS

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*30+5)/4MHz*4 = 29.945 mS

		; 50m 秒 ウェイトルーチン
wait_50ms
		movlw	50		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*50+5)/4MHz*4 = 49.905 mS

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*100+5)/4MHz*4 = 99.805 mS

		; 200m 秒 ウェイトルーチン
wait_200ms
		movlw	200		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*200+5)/4MHz*4 = 199.605 mS

;==========================================================================
;		LED 点滅デモ・ルーチン
;==========================================================================

		; LED 点滅デモ
led_demo
		call	led_demo1
		call	led_demo2
		call	led_demo1
		call	led_demo2
		call	led_demo1
		return

		; (S00) → (S10) → (M00) → (M10) → (H00) 
led_demo1
		movlw	5
		movwf	led_cnt		;LED デモ表示用カウンタ
		movlw	b'01111111'
		movwf	PORTB		;(dp) を点灯
		movlw	b'00000001'
		movwf	led_digit

ldm1_01		comf	led_digit,W	;ビットを反転する
		movwf	PORTA		;LED (S00) ～ (H00) を順に点灯
		bcf	STATUS,C
		rlf	led_digit,F
		call	wait_100ms
		movlw	b'11011111'
		movwf	PORTA		;LED すべてを消灯
		call	wait_50ms
		decfsz	led_cnt,F	;led_cnt - 1
		goto	ldm1_01

		return

		; (H00) → (M10) → (M00) → (S10) → (S00) 
led_demo2
		movlw	5
		movwf	led_cnt		;LED デモ表示用カウンタ
		movlw	b'01111111'
		movwf	PORTB		;(dp) を点灯
		movlw	b'00010000'
		movwf	led_digit

ldm2_01		comf	led_digit,W	;ビットを反転する
		movwf	PORTA		;LED (H00) ～ (S00) を順に点灯
		bcf	STATUS,C
		rrf	led_digit,F
		call	wait_100ms
		movlw	b'11011111'
		movwf	PORTA		;LED すべてを消灯
		call	wait_50ms
		decfsz	led_cnt,F	;led_cnt - 1
		goto	ldm2_01

		return

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		btfsc	INTCON,T0IF	;タイマー０割り込み か？
		goto	int_t0		;Yes

		btfsc	PIR1,TMR1IF	;タイマー１割り込み か？
		goto	int_t1		;Yes
		goto	int_end		;(Illegal interrupt)

		; タイマー０割り込み処理

int_t0		bcf	INTCON,T0IF	;タイマー０割込みフラグをクリア

		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定

		movlw	1
		subwf	tm0_cnt_l,F	;ソフトタイマー０の low  カウンタ - 1
		btfsc	STATUS,Z	;ソフトタイマー０の low  カウンタ = 0 か？
		goto	int01		;Yes

		btfsc	STATUS,C	;ソフトタイマー０の low  カウンタ > 0 か？
		goto	int_end		;Yes

		subwf	tm0_cnt_h,F	;ソフトタイマー０の high カウンタ - 1
		goto	int_end	

int01		movf	tm0_cnt_h,F
		btfss	STATUS,Z	;ソフトタイマー０の high カウンタ = 0 か？
		goto	int_end		;No

		movlw	high tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
;
		bsf	alm_flg,0	;bit0: "秒"カウンタ更新フラグ = 1

		incf	cnt_sec01,F	;秒カウンタ + 1
		movlw	10
		subwf	cnt_sec01,W
		btfss	STATUS,C	;秒カウンタ >= 10 か？
		goto	int_end		;No

		clrf	cnt_sec01	;秒カウンタ = 0

		incf	cnt_sec10,F	;十秒カウンタ + 1
		movlw	6
		subwf	cnt_sec10,W
		btfss	STATUS,C	;十秒カウンタ >= 6 か？
		goto	int_end		;No

		clrf	cnt_sec10	;十秒カウンタ = 0

		incf	cnt_min01,F	;分カウンタ + 1
		movlw	10
		subwf	cnt_min01,W
		btfss	STATUS,C	;分カウンタ >= 10 か？
		goto	int_end		;No

		clrf	cnt_min01	;分カウンタ = 0

		incf	cnt_min10,F	;十分カウンタ + 1
		movlw	6
		subwf	cnt_min10,W
		btfss	STATUS,C	;十分カウンタ >= 6 か？
		goto	int_end		;No

		clrf	cnt_min10	;十分カウンタ = 0

		incf	cnt_hou01,F	;時カウンタ + 1
		movlw	10
		subwf	cnt_hou01,W
		btfss	STATUS,C	;時カウンタ >= 10 か？
		goto	int_end		;No

		clrf	cnt_hou01	;時カウンタ = 0
		goto	int_end

		; タイマー１割り込み処理

int_t1		bcf	PIR1,TMR1IF	;タイマー１割込みフラグをクリア

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

		movlw	1 << buzzer	;対象ビットをセット
		xorwf	PORTA,F		;出力をビット反転
;		goto	int_end

		; レジスタの復帰

int_end		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2016-2017 by M.Yamamoto"

		de	h'ff'

eep_size	equ	$ - eep_st	;EEPROM データサイズ

;		de	h'ff'		;タイマー設定値の記録位置

		de	h'00',h'00'	;"十分","分"

;==========================================================================

		end			;プログラムの終了
