;***** RamenTimerIII.asm **************************************************
;
;	ラーメン・タイマー III
;
;	Copyright (C) 2019-2020   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2019/10/29  by M.Yamamoto )
;	coding:  Ver. 1.00   2019/10/31  初期バージョン
;	update:  Ver. 1.01   2019/11/08  電池セット時のもたつき改善、省電力化の試み等
;	update:  Ver. 1.02   2019/11/11  タイマー時間の設定値の拡張
;	update:  Ver. 1.03   2020/12/07  アップカウンタ機能の追加
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0249 ******

;	Device: PIC16F684	Clock: 4MHz (Internal OSC)

#ifdef comment

 <機能概要>

・まず初めに、本機に電池をセットした後に２つあるスイッチのどちらかを押すと、開始音としての "ピポッ" ブザー音が出力され、その後、タ
　イマー時間ＬＥＤ (1) ～ (8) が約 3.5 秒間左右に点滅移動を繰り返す。

・その次に、EEPROM にバックアップが取られているタイマーデータ（分）を読み出して、その内容をＬＥＤ (1) ～ (8) のどれかに点灯表示をす
　る。（プログラムの作成直後のタイマーデータには、３分が設定されている。）

・その後本機は、２つあるスイッチの操作待ち状態となって、ユーザのスイッチ操作を待ち続ける。

・ユーザは、現在点灯されているＬＥＤ (x) のタイマー時間でよければ、次に START スイッチを押すことによって、タイマー機能が開始される。

・タイマー時間の変更をする場合には、SELECTOR スイッチを押すことによって行われ、押すごとにタイマー時間が＋１されてＬＥＤ (1) ～ (8) 
　に点灯表示がされる。 (1) → (2) → (3) → (4) → (5) → (6) → (7) → (8) → (1) → ・・・ の順に変更がされて行く。（*注）

・このように本機ではラーメン・タイマー用（短時間）を想定していて、タイマー時間には最低１分から最大８分までを変更範囲としている。（*注）

　上２つの （*注）については、下のタイマーデータ（分）の設定範囲の拡張 を参照のこと。

・時間設定の次に START スイッチが押されると、"ピピッ" ブザー音と共にタイマー機能が開始され、設定をしたタイマー時間からカウントダウ
　ンが始まる。

・カウントダウンが始まると、それまで点灯されていたタイマー時間ＬＥＤ (x) は一旦消灯するが、次からは刻々と変化をして行く残りのタイマ
　ー時間を表現するために、毎秒ごとに一瞬（約 15 ミリ秒）だけ点灯表示を繰り返すようになる。

・そして、タイマー時間が１分を経過するごとに、それまで瞬間点灯をしていたＬＥＤ (x) が下位のＬＥＤ (x-1) に切り替わって、同様な表示
　を繰り返す。例えば (3) → (2) → (1) のように切り替わって行く。

・この残りのタイマー時間ＬＥＤ (x) が切り替わったときには、それをユーザに知らせるためにその都度 "ピピッ" ブザー音を出力する。

・また、タイマー時間が残り１分を切って最終の 10 秒前になると、それまでのＬＥＤ (1) の瞬間点灯に加えて、毎秒ごとに "ピッ" ブザー音を
　出力するようになり、もうすぐ終了することを知らせる。

・やがて、設定をしたタイマー時間がゼロとなってタイムアウトになると、まず、そのときまで瞬間点灯をしていたＬＥＤ (1) が消灯したままに
　なる。そして、このときに設定されていた タイマー時間と EEPROM にバックアップされているタイマー時間が比較され、異なる場合にだけ、そ
　のときのタイマー時間で EEPROM のバックアップの更新をする。

・続いて本機では、ジャンパースイッチ ALARM が OFF のときには "チャルメラ" ブザー音を２回、または ON のときには "ピポッピポッ" ブザ
　ー音を５回出力することで、タイマーが正常に終了したことをユーザに知らせる。

・また、タイマー時間のカウントダウン中に、ユーザの何らかの理由によってカウントダウンを中断したい場合には、START（CANCEL）スイッチを
　押すことによってカウントダウンは中断終了をする。このように、カウントダウン中には START スイッチは CANCEL スイッチとして機能をする。

・このときには、中断終了であることを表すために "ブッブー" ブザー音を出力する。もちろん EEPROM のバックアップの更新はない。

・タイムアウトによる正常終了、CANCEL スイッチによる中断終了のどちらの場合にも、そのときに設定されていたタイマー時間のＬＥＤ (x) を
　再び点灯表示をして、ユーザの次のスイッチ操作を待つためにプログラムのメインに戻る。

・なお、"チャルメラ" ブザー音、または "ピポッピポッ" ブザー音の出力中において、START（CANCEL）スイッチを押すことによって、そのブザ
　ー音の出力を中断することもできる。

・電池をセットした直後や、カウントダウンが終了してユーザの次のスイッチ操作を待つためにプログラムのメインに戻った後、30 秒以上スイッ
　チ操作がなかった場合には タイマー時間のＬＥＤ (x) を消灯して、毎秒ごとに "ブッ" ブザー音の出力を繰り返してユーザの注意を喚起する。

・このときの "ブッ" ブザー音の注意喚起は 5 秒間だけで、それ以降もユーザのスイッチ操作がなかった場合には、"ブッブー" ブザー音を出力
　した後スリープモードに入る。

・これら "ブッ" ブザー音の出力中、またはスリープモードのときに、２つのスイッチの内のどちらかを押すことによって、再びタイマー時間の
　ＬＥＤ (x) を点灯表示をして、ユーザの次のスイッチ操作待ちに戻すことができる。

 タイマーデータ（分）の設定範囲の拡張
 ------------------------------------

　本機では、最低１分から最大８分までの設定範囲を有するため、ラーメン・タイマーとしては十分だとは思うが、最大値をもう少し拡張をして
　みた。最大 15 分までの拡張をし、LED は８個しかないため、９分以降は LED (8) との２個の組み合わせで表現をしてる。

　また、設定範囲の拡張をしたことによって、その設定値を変更するための SELECTOR スイッチの操作方法にも拡張を持たせた。従来通りにチョ
　イ押し（約 0.25 秒未満）をした場合には、その都度 ＋１されて 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 → 13 → 
　14 → 15 → 1 → ・・・ の順に変更がされる。

　これに対して、長押し（約 0.25 秒以上 0.5 秒未満）をした場合には、その都度 －１されて 15 → 14 → 13 → 12 → 11 → 10 → 9 → 8 
　→ 7 → 6 → 5 → 4 → 3 → 2 → 1 → 15 ・・・ の順に変更がされる。そして、連続で押していると約 0.5 秒間隔で －１ずつ変更がされる。

　これらの時間設定の操作はかなり微妙だが、何回か試してみて感覚をつかんでみると良い。従来はインクリメント（増加）だけの一方向であっ
　たが、拡張後はデクリメント（減少）も合わせた両方向に対応しているので、 たとえ自分の意志とは異なった操作結果となっても、すぐに修正
　操作をすることが可能である。

 アップカウンタ機能の追加
 ------------------------

・SELECTOR スイッチ を押すことによってタイマー時間の変更をする場合に、従来（アップカウンタ機能を追加する以前）は上述したように、 
　・・・ → 13 → 14 → 15 → 1 → 2 → 3 → ・・・ 、または ・・・ → 3 → 2 → 1 → 15 → 14 → 13 → ・・・ の順に変更がされるこ
　とを述べたが、これを ・・・ → 13 → 14 → 15 → 0 → 1 → 2 → 3 → ・・・ 、または ・・・ → 3 → 2 → 1 → 0 → 15 → 14 → 13 
　→ ・・・のように改めた。

・このように、15 と 1 の間には必ず 0 の状態が設定されるように変更をし、このときにはタイマー時間の範囲外で、LED (x) はどれも点灯する
　ことはない。そして、この 0 の状態のとき（LED (x) が全消灯のとき）に START スイッチ が押されると、"ピピピッ" ブザー音と共にアップ
　カウンタ機能が開始され、00 分 00 秒からカウントアップが始まる。

・そして、初めの１分間に限り LED (x) が全消灯のままで、その代わりに 5 秒ごとに "ピッ" ブザー音で経過を知らせる。１分が経過をすると、
　再び "ピピピッ" ブザー音と共に LED (1) が一瞬（約 15 ミリ秒）だけ点灯表示をする。その後は、5 秒ごとのブザー音はないが、5 秒ごとに
　一瞬（約 15 ミリ秒）だけ LED (1) の点灯表示を繰り返すようになる。

・２分が経過以降は、毎分 00 秒になったごとに "ピピピッ" ブザー音でそれを知らせ、LED (x) が上位のＬＥＤ (x+1) に切り替わって、同様に
　毎 5 秒ごとの一瞬点灯表示を繰り返す。 

・やがて、15 分（正確には 16 分）が経過した後は LED の点灯表示が、再び LED (1) に戻って以上の点灯表示を繰り返すが、毎分 00 秒ごとの 
　"ピピピッ" ブザー音の直後に、"ピッ" ブザー音を数回ずつ付け加えて、15 分単位が何回あったか（ LED (1) に戻った回数）を知らせる。

・すなわち、最初の 15 分間（正確には 16 分間）は 0 回なので "ピッ" ブザー音は付け加えないが、次の 15 分間は 1 回、その次の 15 分間
　は 2 回、・・・ のように "ピッ" ブザー音を付け加えて、この "ピッ" ブザー音の回数と LED (x) の一瞬点灯表示で、 カウント開始以降に
　何分が経過したかを知らせるようになる。 （ 15 分 x "ピッ" ブザー音の回数 + LED (x) ）

・本機能のカウントアップ中に、ユーザの都合でカウントアップを中断したくなった場合には、START（CANCEL）スイッチ を押すことによってカ
　ウントアップは中断終了をする。

・また、カウントアップの最大の上限は２時間（正確には２時間１分）までと設定がされていて、この上限を超えたときにはカウントアップは強
　制終了をする。これらの中断終了、強制終了のどちらのときにも、"ブッブー" ブザー音でそれを知らせた後、 ユーザの次のスイッチ操作を待
　つためにプログラムのメインに戻る。

・このとき、タイマー時間の設定が 0 の状態のままでは LED (x) が全消灯となるため、スリープモード中と紛らわしいので、必ず、前回の EEP
　ROM にバックアップが取られているタイマー時間に戻している。したがって、アップカウンタ機能のときには、0 というタイマー時間の設定値
　は EEPROM にバックアップが取られることはない。

#endif

;==========================================================================

;	PIC16F684 のピンと用途

;		(1) Vdd: 電源 +3V DC		(14) Vss: 電源 GND
;		(2) RA5: LED-8 出力		(13) RA0: ブザー音 出力
;		(3) RA4: LED-7 出力		(12) RA1: STA/CAN スイッチ 入力
;		(4) RA3: ALM スイッチ 入力	(11) RA2: SEL スイッチ 入力
;		(5) RC5: LED-6 出力		(10) RC0: LED-1 出力
;		(6) RC4: LED-5 出力		 (9) RC1: LED-2 出力
;		(7) RC3: LED-4 出力		 (8) RC2: LED-3 出力

;	*注.  RA3 は入力専用で、出力ポートには使えない。

;==========================================================================

		list		p=pic16f684		;デバイス情報
		include		p16f684.inc		;インクルードファイル
		errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config 	_CP_OFF & _CPD_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

;==========================================================================
;		定数の定義と変数のレジスタ割付け
;==========================================================================

;#define 	xx_debug			;TMR0 基準時間の調整中: 補正値(xx)

		radix	dec

tm0_h_val	equ	256 - 200		;ハードタイマー０カウント値 (4 / 4MHz * 200 = 200μS)
xx		equ	-353			;補正値
tm0_s_val	equ	5000 + xx		;ソフトタイマー０のカウント値
buzzer		equ	0			;RA0: ブザー音 出力
stsw		equ	1			;RA1: START(CANCEL) スイッチ
selsw		equ	2			;RA2: SELECTOR スイッチ
almsw		equ	3			;RA3: ALARM スイッチ

Do		equ	28			;ド
Do_		equ	29			;ド＃
Re		equ	30			;レ
Re_		equ	31			;レ＃
Mi		equ	32			;ミ
Fa		equ	33			;ファ
Fa_		equ	34			;ファ＃
So		equ	35			;ソ
So_		equ	36			;ソ＃
Ra		equ	37			;ラ
Ra_		equ	38			;ラ＃
Si		equ	39			;シ

Half		equ	1			;半音
Oct1		equ	12			;1 オクターブ
Nn		equ	h'80'			;休止符
Xx		equ	h'c0'			;テンポ
Rep		equ	h'c1'			;繰り返し

L1		equ	64			;1/1   64 x 1 x tempo = 64 mS x tempo
L2		equ	32			;1/2   32 x 1 x tempo = 32 mS x tempo
L4		equ	16			;1/4   16 x 1 x tempo = 16 mS x tempo
L8		equ	8			;1/8	8 x 1 x tempo =  8 mS x tempo
L16		equ	4			;1/16	4 x 1 x tempo =  4 mS x tempo
L32		equ	2			;1/32	2 x 1 x tempo =  2 mS x tempo
Lx		equ	1			;	1 x 1 x tempo =  1 mS x tempo

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			;音長

		cblock	h'20'
tm0_cnt_h					;ソフトタイマー０の high カウンタ
tm0_cnt_l					;ソフトタイマー０の low  カウンタ
const_high					;音階用分周定数 high の保存
const_low					;音階用分周定数 low の保存
mon_flg						;監視フラグ
sec_flg						;"秒"カウンタ更新フラグ
eep_min						;"分"EEPROMバックアップ値
sel_min						;"分"選択値
min_cnt						;"分"カウンタ
sec_cnt						;"秒"カウンタ
min15_cnt					;"15分"カウンタ
on_led						;PORTA/PORTB の LED (x) 位置
glp_cnt						;汎用繰り返しカウンタ
wt1cnt						;ウェイト用ループカウンタ
wt2cnt						;ウェイト用ループカウンタ

scale						;音階コードの保存
length						;音長の保存
tempo						;テンポ指定
repeat						;繰り返し指定
addr_high					;読み出す曲データの high アドレス
addr_low					;読み出す曲データの low アドレス
rep_addr_high					;繰り返し曲データの high アドレス
rep_addr_low					;繰り返し曲データの low アドレス
lp_cnt						;繰り返しカウンタ
work						;ワーク
		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

;==========================================================================
;		音階用分周定数を取得(一部だけの省略設定)  at 4MHz
;==========================================================================

get_scale
		movwf	work
		movlw	high $		;;
		movwf	PCLATH		;;

		movlw	Do << 1
		subwf	work,W			;work - (28 * 2)
		addwf	PCL,F			;PC = PC + W

		retlw	high (65536 - 1911)	;28: ド    (261.63Hz)
		retlw	low  (65536 - 1977)
		retlw	high (65536 - 1804)	;29: ド＃  (277.18Hz)
		retlw	low  (65536 - 1804)
		retlw	high (65536 - 1703)	;30: レ    (293.66Hz)
		retlw	low  (65536 - 1703)
		retlw	high (65536 - 1607)	;31: レ＃  (311.13Hz)
		retlw	low  (65536 - 1607)
		retlw	high (65536 - 1517)	;32: ミ    (329.63Hz)
		retlw	low  (65536 - 1517)
		retlw	high (65536 - 1432)	;33: ファ  (349.23Hz)
		retlw	low  (65536 - 1432)
		retlw	high (65536 - 1351)	;34: ファ＃(369.99Hz)
		retlw	low  (65536 - 1351)
		retlw	high (65536 - 1276)	;35: ソ    (392.00Hz)
		retlw	low  (65536 - 1276)
		retlw	high (65536 - 1204)	;36: ソ＃  (415.30Hz)
		retlw	low  (65536 - 1204)
		retlw	high (65536 - 1136)	;37: ラ    (440.00Hz)
		retlw	low  (65536 - 1136)
		retlw	high (65536 - 1073)	;38: ラ＃  (466.16Hz)
		retlw	low  (65536 - 1073)
		retlw	high (65536 - 1012)	;39: シ    (493.88Hz)
		retlw	low  (65536 - 1012)
		retlw	high (65536 -  956)	;40: ド    (523.26Hz)
		retlw	low  (65536 -  956)

;==========================================================================
;		初期化処理
;==========================================================================

start
		clrf	STATUS		;STATUS クリア
	 	clrf	INTCON		;INTCON クリア
		bcf	STATUS,RP1
		bcf	STATUS,RP0	;バンク 0

		; PORTA,PORTB をデジタルI/O に設定

		clrf	PORTA		;
		clrf	PORTC		;
		movlw	b'00000111'	;Digital I/O
		movwf	CMCON0		;CMCON0 に設定

		bsf	STATUS,RP0	;バンク 1
		clrf	ANSEL		;Digital I/O
		movlw	b'00001110'
		movwf	TRISA		;ポートA の I/0 設定
		movlw	b'00000000'
		movwf	TRISC		;ポートC の I/0 設定

		; 内部クロックを 4 MHz(default) に設定

	;	movlw	b'01101000'
	;	movwf	OSCCON    	;OSCCON に設定

		; OPTION_REG の設定

		movlw	b'00001000'	;*bit7=0: PORTA を PULL-UP する
					; bit6=0: RA2/INT 割込みは立下りエッジ
					; 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 に設定
;
		clrf	PORTC		;PORTC の初期設定
		clrf	PORTA		;PORTA の初期設定
		bsf	INTCON,PEIE	;PEIE: 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE: グローバル割り込み許可
		call	wait_1s		;1 秒 ウェイト

;--------------------------------------------------------------------------

#ifndef xx_debug
		; 電池セット時のもたつきを改善

sta_01		movf	PORTA,W
		andlw	h'06'		;スイッチ入力を
		xorlw	h'06'		;反転
		btfsc	STATUS,Z	;スイッチ操作 = あり か？
		goto	sta_01		;No

		call	wait_50ms

sta_02		movf	PORTA,W
		andlw	h'06'		;スイッチ入力を
		xorlw	h'06'		;反転
		btfss	STATUS,Z	;スイッチ操作 = なし か？
		goto	sta_02		;No

		call	wait_50ms

		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	led_demo	;LED 点滅デモ
		call	wait_250ms	;250m 秒 ウェイト

		; EEPROM データの読み出し

		bsf	STATUS,RP0	;バンク 1
		movlw	backup - eep_st
		movwf	EEADR		;EEPROM の記録アドレスを設定
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し

		bcf	STATUS,RP0	;バンク 0
		movwf	eep_min		;"分"EEPROMバックアップ値
		movwf	sel_min		;"分"選択値にも読み出しデータを設定

		; 各変数の初期設定

		clrf	mon_flg		;監視フラグの初期設定
		clrf	sec_flg		;"秒"カウンタ更新フラグの初期設定

		movf	sel_min,W
		call	sel_to_led	;"分"LED 点灯
		goto	main
#else
;==========================================================================
;		TMR0 基準時間の調整支援
;==========================================================================

;		待機中			T.ADJ (buzzer) = "H", LED(1) 点灯
;		START スイッチでカウント開始
;		カウント中		T.ADJ (buzzer) = "L", LED(8) 点滅
;		タイムアウトで再び待機中に戻る

tmr0_adj
		movlw	1
		movwf	PORTA		;T.ADJ (buzzer) = "H"
		movwf	PORTC		;LED(1) 点灯

		btfsc	PORTA,stsw	;START スイッチ = ON か？
		goto	$ - 1		;No

		movlw	8
		movwf	min_cnt		;"分"カウンタの設定
		movlw	60
		movwf	sec_cnt		;"秒"カウンタの設定
		call	tm0_proc	;タイマー０割り込みの手続き

		clrf	PORTC		;LED(1) 消灯
		clrf	PORTA		;T.ADJ (buzzer) = "L"
		bsf	sec_flg,0	;"秒"カウンタ更新フラグ = ON

tm0a1		btfss	sec_flg,0	;"秒"カウンタ更新フラグ = ON か？
		goto	tm0a2		;No

		bsf	PORTA,5		;LED(8) 点灯
		call	wait_15ms	;15m 秒 ウェイトルーチン
		bcf	PORTA,5		;LED(8) 消灯
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF

tm0a2		movf	min_cnt,W
		btfss	STATUS,Z	;"分"カウンタ = 0 か？
		goto	tm0a1		;No

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		goto	tmr0_adj
#endif

;==========================================================================
;		LED 点滅デモ・ルーチン
;==========================================================================

		; LED 点滅デモ
led_demo
		call	led_demo1
		call	led_demo2
		call	led_demo1
		call	led_demo2
		call	led_demo1
		return

;--------------------------------------------------------------------------

	;   LED =  (1) → (2) → (3) → (4) → (5) → (6) → (7) → (8)
	;   cnt =   6      5      4      3      2      1      2      1
	; RA/RC =  RC0    RC1    RC2    RC3    RC4    RC5    RA4    RA5

led_demo1
		movlw	6 + 1
		movwf	glp_cnt		;LED デモ表示用カウンタ
		movlw	1
		movwf	on_led		;LED (x) = (1) に初期設定

ldm1_01		decf	glp_cnt,F	;glp_cnt -1 更新
		btfsc	STATUS,Z	;glp_cnt = 0 か？
		goto	ldm1_02		;Yes

		movf	on_led,W	;LED (x) を PORTC に
		movwf	PORTC		;LED (1) ～ (6) を順に点灯
		call	wait_15ms
		clrf	PORTC		;LED (x) を消灯
		call	wait_85ms

		bcf	STATUS,C
		rlf	on_led,F	;LED (x) +1 更新
		goto	ldm1_01

ldm1_02		movlw	2 + 1
		movwf	glp_cnt		;LED デモ表示用カウンタ
		movlw	16
		movwf	on_led		;LED (x) = (7) に初期設定

ldm1_03		decf	glp_cnt,F	;glp_cnt -1 更新
		btfsc	STATUS,Z	;glp_cnt = 0 か？
		goto	ldm1_04		;Yes

		movf	on_led,W	;LED (x) を PORTA に
		movwf	PORTA		;LED (7) ～ (8) を順に点灯
		call	wait_15ms
		clrf	PORTA		;LED (x) を消灯
		call	wait_85ms

		bcf	STATUS,C
		rlf	on_led,F	;LED (x) +1 更新
		goto	ldm1_03

ldm1_04		return

;--------------------------------------------------------------------------

	;;  LED =  (8) → (7) → (6) → (5) → (4) → (3) → (2) → (1)
	;;  cnt =   2      1      6      5      4      3      2      1
	;;RA/RC =  RA5    RA4    RC5    RC4    RC3    RC2    RC1    RC0

	;   LED =  (7) → (6) → (5) → (4) → (3) → (2)
	;   cnt =   1      5      4      3      2      1
	; RA/RC =  RA4    RC5    RC4    RC3    RC2    RC1

led_demo2
		movlw	1 + 1						;;2 + 1
		movwf	glp_cnt		;LED デモ表示用カウンタ
		movlw	16						;;32
		movwf	on_led		;LED (x) = (7) に初期設定

ldm2_01		decf	glp_cnt,F	;glp_cnt -1 更新
		btfsc	STATUS,Z	;glp_cnt = 0 か？
		goto	ldm2_02		;Yes

		movf	on_led,W	;LED (x) を PORTA に
		movwf	PORTA		;LED (7) を点灯			;;(8) ～ (7)
		call	wait_15ms
		clrf	PORTA		;LED (x) を消灯
		call	wait_85ms

		bcf	STATUS,C
		rrf	on_led,F	;LED (x) -1 更新
		goto	ldm2_01

ldm2_02		movlw	5 + 1						;;6 + 1
		movwf	glp_cnt		;LED デモ表示用カウンタ
		movlw	32
		movwf	on_led		;LED (x) = (6) に初期設定

ldm2_03		decf	glp_cnt,F	;glp_cnt -1 更新
		btfsc	STATUS,Z	;glp_cnt = 0 か？
		goto	ldm2_04		;Yes

		movf	on_led,W	;LED (x) を PORTC に
		movwf	PORTC		;LED (6) ～ (2) を順に点灯	;;(6) ～ (1)
		call	wait_15ms
		clrf	PORTC		;LED (x) を消灯
		call	wait_85ms

		bcf	STATUS,C
		rrf	on_led,F	;LED (x) -1 更新
		goto	ldm2_03

ldm2_04		return

;==========================================================================
;		"分"選択値から LED (x) 点灯へ変換
;==========================================================================

	;   LED =  (1) → (2) → (3) → (4) → (5) → (6) → (7) → (8)
	;   cnt =   1      2      3      4      5      6      7      8
	;   cnt =   9     10     11     12     13     14     15	
	; RA/RC =  RC0    RC1    RC2    RC3    RC4    RC5    RA4    RA5

	; 入力  W reg: "分"選択値

sel_to_led
		clrf	PORTC		;LED (x) を消灯
		clrf	PORTA		;LED (x) を消灯

		call	led_table	;カウンタ値から LED 点灯パタンに変換
		movwf	on_led		;ワーク
		andlw	h'3f'		;下位 6 ビットを取り出す
		movwf	PORTC		;RC ポートの LED (x) を点灯

		rrf	on_led,F	;2 ビット右にシフト
		rrf	on_led,W	;
		andlw	h'30'		;上位 2 ビットを取り出す
		movwf	PORTA		;RA ポートの LED (x) を点灯
		return

		; カウンタ値から LED 点灯パタンに変換
led_table
		movwf	work
		movlw	high $		;;
		movwf	PCLATH		;;
		movf	work,W
		addwf	PCL,F		;PC = PC + W

		retlw	b'00000000'	;cnt= 0: dummy

		retlw	b'00000001'	;cnt= 1: (1)
		retlw	b'00000010'	;cnt= 2: (2)
		retlw	b'00000100'	;cnt= 3: (3)
		retlw	b'00001000'	;cnt= 4: (4)
		retlw	b'00010000'	;cnt= 5: (5)
		retlw	b'00100000'	;cnt= 6: (6)
		retlw	b'01000000'	;cnt= 7: (7)
		retlw	b'10000000'	;cnt= 8: (8)

		retlw	b'10000001'	;cnt= 9: (8) + (1)
		retlw	b'10000010'	;cnt=10: (8) + (2)
		retlw	b'10000100'	;cnt=11: (8) + (3)
		retlw	b'10001000'	;cnt=12: (8) + (4)
		retlw	b'10010000'	;cnt=13: (8) + (5)
		retlw	b'10100000'	;cnt=14: (8) + (6)
		retlw	b'11000000'	;cnt=15: (8) + (7)

;==========================================================================
;		メイン・ルーチン
;==========================================================================

;		START スイッチは CANCEL スイッチも兼ねている
;		カウント動作前に ON すると START スイッチとして機能
;		カウント動作中に ON すると CANCEL スイッチとして機能

;		SELECTOR スイッチは タイマー時間（分）を選択するもの

main

;---------------- カウントダウン／アップ開始前の処理 ----------------------

		; SELECTOR スイッチのチェック
		btfsc	PORTA,selsw	;SELECTOR スイッチ = ON か？
		goto	m004		;No

		; SELECTOR スイッチの処理
		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		bcf	mon_flg,0	;監視フラグ = OFF

		call	wait_30ms
		movlw	220		;30ms + 1ms x 220 = 250 = 0.25 秒間 ON を監視
		movwf	glp_cnt		;ループカウンタ

m001		movlw	1
		call	wait_w1ms	;
		btfsc	PORTA,selsw	;SELECTOR スイッチ = OFF か？
		goto	m002		;Yes. 監視を中断

		decfsz	glp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	m001		;No

		;（デクリメント）
		decf	sel_min,F	;"分"選択値 -1 更新
		incf	sel_min,W	;;
		movlw	15
		btfsc	STATUS,Z	;"分"選択値 = -1 か？
		movwf	sel_min		;Yes. "分"選択値 = 15
		goto	m003

		;（インクリメント）
m002		incf	sel_min,F	;"分"選択値 +1 更新
		movf	sel_min,W
		sublw	16
		btfsc	STATUS,Z	;"分"選択値 = 16 か？
		clrf	sel_min		;Yes. "分"選択値 = 0

m003		movf	sel_min,W
		call	sel_to_led	;"分"LED 点灯更新
		call	wait_250ms	;チャタリング吸収
		goto	main

		; START スイッチのチェック
m004		btfss	PORTA,stsw	;START スイッチ = ON か？
		goto	m100		;Yes

		btfsc	mon_flg,0	;監視フラグ = ON か？
		goto	m005		;Yes

;-------------- ; スイッチ操作なしの監視（30秒間）を開始

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		bsf	mon_flg,0	;監視フラグ = ON
		movlw	1
		movwf	min_cnt		;"分"カウンタの設定
		movlw	30
		movwf	sec_cnt		;"秒"カウンタの設定
		call	tm0_proc	;タイマー０割り込みの手続き
		goto	main

		; スイッチ操作なしの監視中
m005		movf	min_cnt,W
		btfss	STATUS,Z	;"分"カウンタ = 0 か？
		goto	main		;No

		; スイッチ操作なしの監視終了
		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		bcf	mon_flg,0	;監視フラグ = OFF
		clrf	PORTC		;"分"LED を消灯
		clrf	PORTA		;"分"LED を消灯

		movf	sel_min,W
		btfss	STATUS,Z	;"分"選択値 = 0（カウントアップ）か？
		goto	m006		;No

		movf	eep_min,W	;"分"EEPROMバックアップ値
		movwf	sel_min		;"分"選択値

m006		movlw	1
		movwf	min_cnt		;"分"カウンタの設定
		movlw	5 + 1
		movwf	sec_cnt		;"秒"カウンタの設定
		call	tm0_proc	;タイマー０割り込みの手続き
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF

		; 警告音の出力（5秒間）と解除スイッチ操作
m007		movf	min_cnt,W
		btfsc	STATUS,Z	;"分"カウンタ = 0 か？
		goto	m009		;Yes

		btfsc	sec_flg,0	;"秒"カウンタ更新フラグ = ON か？
		call	buzzer_bu	;Yes. "ブッ" ブザー音出力
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF

		movf	PORTA,W
		andlw	h'06'		;スイッチ入力を
		xorlw	h'06'		;反転
		btfsc	STATUS,Z	;スイッチ操作 = あり か？
		goto	m007		;No

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		call	wait_50ms

m008		movf	PORTA,W
		andlw	h'06'		;スイッチ入力を
		xorlw	h'06'		;反転
		btfss	STATUS,Z	;スイッチ操作 = なし か？
		goto	m008		;No

		call	wait_50ms
		movf	sel_min,W
		call	sel_to_led	;"分"LED 点灯
		goto	main

		; スリープ状態に突入
m009		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		call	buzzer_buu
		clrf	PORTC		;"分"LED を消灯
		clrf	PORTA		;"分"LED を消灯

m010		bsf	STATUS,RP0	;バンク 1
		movlw	b'00000110'	;RA2,RA1
		movwf	IOCA		;ポート変化割り込みbit の設定
		bcf	STATUS,RP0	;バンク 0

		bsf	INTCON,RAIE	;RAポート変化割り込みを許可
		sleep			;おやすみなさい
		;
		;			;wake up
		movf	PORTA,W
		andlw	h'06'		;スイッチ入力を
		xorlw	h'06'		;反転
		btfsc	STATUS,Z	;スイッチ操作 = なし か？
		goto	m010		;Yes. 再度 sleep
		;
		call	wait_50ms
		goto	m008

;---------------- カウントダウンの開始 ------------------------------------

m100		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		movf	sel_min,W
		btfsc	STATUS,Z	;"分"選択値 = 0 か？
		goto	m200		;Yes. カウントアップ

		movwf	min_cnt		;"分"カウンタの設定
		movlw	60
		movwf	sec_cnt		;"秒"カウンタの設定
		call	tm0_proc	;タイマー０割り込みの手続き

		clrf	PORTC		;"分"LED を消灯
		clrf	PORTA		;"分"LED を消灯
		bsf	sec_flg,0	;"秒"カウンタ更新フラグ = ON

;-------------- ; カウントダウン中の処理

m101		btfss	sec_flg,0	;"秒"カウンタ更新フラグ = ON か？
		goto	m102		;No

		movf	min_cnt,W
		call	sel_to_led	;"分"LED 点灯
		call	wait_15ms	;15m 秒 ウェイトルーチン
		clrf	PORTC		;"分"LED を消灯
		clrf	PORTA		;"分"LED を消灯
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF

		movf	sec_cnt,W
		sublw	60
		btfsc	STATUS,Z	;"秒"カウンタ = 60 か？
		call	buzzer_pipi	;Yes. "ピピッ" ブザー音出力

		decfsz	min_cnt,W	;"分"カウンタ = 1 か？
		goto	m102		;No

		movf	sec_cnt,W
		sublw	10
		btfsc	STATUS,C	;"秒"カウンタ =< 10 か？
		call	buzzer_pi	;Yes. "ピッ" ブザー音出力

		decfsz	sec_cnt,W	;"秒"カウンタ = 1 か？
		goto	m102		;No

		call	wait_500ms
		goto	m103		;Yes

m102		btfsc	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m101		;No

		clrf	mon_flg		;監視フラグをクリア

;-------------- ; カウントダウンの終了処理

m103		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		clrf	PORTC		;"分"LED 消灯
		clrf	PORTA		;"分"LED 消灯

		btfsc	mon_flg,0	;キャンセル操作 か？
		goto	m104		;No

		; 中断終了
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		call	wait_1s		;1 秒 ウェイト
		goto	m109

		; 正常タイムアウト
m104		clrf	mon_flg		;監視フラグをクリア

		movf	sel_min,W	;"分"選択値
		subwf	eep_min,W	;"分"EEPROMバックアップ値
		btfsc	STATUS,Z	;両者は等しい か？
		goto	m105		;Yes

		; EEPROM への書き込み（バックアップ）
		bsf	STATUS,RP0	;バンク1
		movlw	backup - eep_st
		movwf	EEADR		;EEPROM の記録アドレスを設定

		bcf	STATUS,RP0	;バンク0
		movf	sel_min,W	;"分"選択値
		movwf	eep_min		;"分"EEPROMバックアップ値

		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

		bcf	STATUS,RP0	;バンク0

m105		btfsc	PORTA,almsw	;ALARM スイッチ = ON か？
		goto	m107		;No

		; "ピポッピポッ" x 5 ブザー音出力

		movlw	5
		movwf	glp_cnt		;繰り返しカウンタ

m106		call	buzzer_pipo	;"ピポッ" ブザー音出力
		btfss	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m109		;Yes

		call	wait_30ms
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		btfss	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m109		;Yes

		call	wait_250ms
		decfsz	glp_cnt,F	;glp_cnt - 1 = 0 か？
		goto	m106		;No
		goto	m109

		; チャルメラ x 2 ブザー音出力
m107		movlw	2
		movwf	glp_cnt		;繰り返しカウンタ

m108		btfss	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m109		;Yes

		movlw	high charamela
		movwf	addr_high	;読み出す曲データの high アドレスを設定
		movlw	low  charamela
		movwf	addr_low	;読み出す曲データの low  アドレスを設定
		call	play_back	;曲データの再生
		btfss	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m109		;Yes

		call	wait_1s		;1 秒 ウェイト
		decfsz	glp_cnt,F	;glp_cnt - 1 = 0 か？
		goto	m108		;No

m109		movf	sel_min,W
		call	sel_to_led	;"分"LED 点灯
		call	wait_500ms
		goto	main

;---------------- カウントアップの開始 ------------------------------------

m200		clrf	mon_flg		;監視フラグをクリア
		clrf	sec_cnt		;"秒"カウンタの設定
		clrf	min_cnt		;"分"カウンタの設定
		clrf	min15_cnt	;"15分"カウンタの設定
		call	tm0_proc	;タイマー０割り込みの手続き
		bsf	sec_flg,0	;"秒"カウンタ更新フラグ = ON

;-------------- ; カウントアップ中の処理

m201		btfss	sec_flg,0	;"秒"カウンタ更新フラグ = ON か？
		goto	m208		;No

		; 毎分１秒のチェック
		clrf	sec_flg		;"秒"カウンタ更新フラグ = OFF
		decf	sec_cnt,W
		btfss	STATUS,Z	;"秒"カウンタ = 1 か？
		goto	m203		;No

		movf	min15_cnt,W	;"15分"カウンタ
		movwf	work

m202		movf	work,F
		btfsc	STATUS,Z	;work"15分"カウンタ = 0 か？
		goto	m208		;Yes

		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_100ms
		call	wait_100ms
		decf	work,F		;work"15分"カウンタ - 1
		btfsc	sec_flg,0	;"秒"カウンタ更新フラグ = ON か？
		clrf	sec_flg		;Yes. "秒"カウンタ更新フラグ = OFF
		goto	m202

		; ５秒毎のチェック
m203		movf	sec_cnt,W
		btfsc	STATUS,Z	;"秒"カウンタ = 0 か？
		goto	m205		;Yes

		movwf	work

m204		movlw	5
		subwf	work,F
		btfsc	STATUS,Z	;"秒"カウンタ - 5 = 0 か？
		goto	m205		;Yes

		btfsc	STATUS,C	;"秒"カウンタ - 5 > 0 か？
		goto	m204		;Yes
		goto	m208		;No

m205		movf	min_cnt,W
		btfss	STATUS,Z	;"分"カウンタ = 0 か？
		goto	m206		;No

		; １分経過以前
		call	buzzer_pi	;Yes. "ピッ" ブザー音出力
		movf	sec_cnt,W
		btfsc	STATUS,Z	;"秒"カウンタ = 0 か？
		goto	m207		;Yes
		goto	m208

		; １分経過以降
m206		call	sel_to_led	;"分"LED 点灯
		call	wait_15ms	;15m 秒 ウェイトルーチン
		clrf	PORTC		;"分"LED を消灯
		clrf	PORTA		;"分"LED を消灯

		movf	sec_cnt,W
		btfss	STATUS,Z	;"秒"カウンタ = 0 か？
		goto	m208		;No

		call	buzzer_pi	;Yes. "ピッ" ブザー音出力

m207		call	wait_15ms
		call	buzzer_pipi	;Yes. "ピピッ" ブザー音出力

m208		movlw	8
		subwf	min15_cnt,W
		btfsc	STATUS,Z	;"15分"カウンタ = 8 （２時間１分経過）か？
		goto	m209		;Yes. 強制終了

		btfsc	PORTA,stsw	;START スイッチ = ON （キャンセル操作）か？
		goto	m201		;No

		; 中断終了
m209		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		call	wait_500ms
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		movf	eep_min,W	;"分"EEPROMバックアップ値
		movwf	sel_min		;"分"選択値
		call	sel_to_led	;"分"LED 点灯
		call	wait_500ms
		goto	main

;==========================================================================

;		タイマー０割り込みの手続き

tm0_proc
		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high tm0_s_val	;ソフトタイマー０の high カウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low tm0_s_val	;ソフトタイマー０の low  カウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		return

;==========================================================================
;		曲データの再生
;		入力: addr_high: 読み出す曲データの high アドレス
;		      addr_low:  読み出す曲データの low  アドレス
;==========================================================================

play_back
		movlw	1
		movwf	repeat		;繰り返し指定の初期設定

		; 曲データの読み出し

ply01		call	kdt_read	;曲データ1 を読み出す
		movwf	scale	       ;;音階コードに保存

		movf	scale,W
		btfsc	STATUS,Z	;読み出しデータ 終了か?
		goto	ply07		;Yes

		call	kdt_read	;曲データ2 を読み出す
		movwf	length	       ;;音長に保存

		; 音階コードの分析

		movlw	Nn		;音階コードが (Nn) の時は休止符
		subwf	scale,W
		btfsc	STATUS,Z	;音階コード = (Nn) か？
		goto	ply04		;Yes

		movlw	Xx		;音階コードが (Xx) の時は テンポ指定
		subwf	scale,W
		btfss	STATUS,Z	;音階コード = (Xx) か？
		goto	ply02		;No

		movf	length,W	;テンポを取り出す
		movwf	tempo		;テンポ指定を設定
		goto	ply06

ply02		movlw	Rep		;音階コードが (Rep) の時は 繰り返し指定
		subwf	scale,W
		btfss	STATUS,Z	;音階コード = (Rep) か？
		goto	ply03		;No

		movf	addr_high,W
		movwf	rep_addr_high	;繰り返し曲データの high アドレスを保存
		movf	addr_low,W
		movwf	rep_addr_low	;繰り返し曲データの low アドレスを保存

		movf	length,W	;繰り返しを取り出す
		movwf	repeat		;繰り返し指定を設定
		goto	ply06

		; 音符, 休符の再生

ply03	;;	decf	scale,F		;音階コード -1
		bcf	STATUS,C
		rlf	scale,W		;音階コードを 2 倍する
		call	get_scale	;音階用分周定数を取得
		movwf	const_high     ;;high に保存する
		bsf	STATUS,C
		rlf	scale,W		;音階コードを 2 倍して +1 する
		call	get_scale	;音階用分周定数を取得
		movwf	const_low      ;;low に保存する

		bsf	STATUS,RP0	;バンク1 を選択
		bsf	PIE1,TMR1IE	;タイマー１割り込みを許可
		bcf	STATUS,RP0	;バンク0 を選択

ply04		movf	tempo,W
		movwf	lp_cnt		;ループカウンタを設定

ply05		movlw	1
		call	wait_w1ms	;音長を (tempo * length) 倍で再生
		decfsz	lp_cnt,F	;ループ終了 か?
		goto	ply05		;No

		decfsz	length,F	;音長 = 0 か？
		goto	ply04		;No

		bsf	STATUS,RP0	;バンク1 を選択
		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク0 を選択

		; 再生中断の監視と繰り返し処理

ply06		btfsc	PORTA,stsw	;START（CANCEL）スイッチ = ON か？
		goto	ply01		;No
		goto	ply09		;Yes

ply07		decfsz	repeat,F	;繰り返し終了 か?
		goto	ply08		;No
		goto	ply09		;Yes

ply08		movf	rep_addr_high,W
		movwf	addr_high	;繰り返し曲データの high アドレスを復帰
		movf	rep_addr_low,W
		movwf	addr_low	;繰り返し曲データの low アドレスを復帰
		goto	ply01

		; 再生の終了

ply09		return

		; 曲データの読み出し
kdt_read
		call	kdt_read_0	;テーブルデータの読み出し
		incf	addr_low,F	;曲データの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;曲データの high アドレスの更新
		return

kdt_read_0	movf	addr_high,W	;読み出す曲データの high アドレス
		movwf	PCLATH
		movf	addr_low,W	;読み出す曲データの low アドレス
		movwf	PCL

;==========================================================================

		; チャルメラ音出力データ
charamela
		retlw	Xx		;テンポ
		retlw	35

;		retlw	Nn
;		retlw	L2
;		retlw	Nn
;		retlw	L4
		retlw	Nn
		retlw	L8
		retlw	So
		retlw	L16
		retlw	Ra
		retlw	L16

		retlw	Si
		retlw	L4 + L8
		retlw	Ra
		retlw	L16
		retlw	So
		retlw	L16
		retlw	Nn
		retlw	L8 + L16
		retlw	So
		retlw	L16
		retlw	Ra
		retlw	L16
		retlw	Si
		retlw	L16
		retlw	Ra
		retlw	L16
		retlw	So
		retlw	L16

		retlw	Ra
		retlw	L2
;		retlw	Nn
;		retlw	L2

		retlw	0

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; "ピッ" ブザー音出力
buzzer_pi
		Sound_M		f_so, pi_tim
		return

		; "ポッ" ブザー音出力
buzzer_po
		Sound_M		f_doh, po_tim
		return

		; "ピピッ" ブザー音出力 (215 mS)
buzzer_pipi
		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_15ms
		call	buzzer_pi	;"ピッ" ブザー音出力
		return

		; "ピポッ" ブザー音出力 (230 mS)
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_30ms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ブッ" ブザー音出力
buzzer_bu
		Sound_M		f_do, bu_tim
		return

		; "ブー" ブザー音出力
buzzer_buu
		Sound_M		f_do, buu_tim
		return

		; "ブッブー" ブザー音出力 (450 mS)
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		movlw	100
		call	wait_w1ms
		call	buzzer_buu	;"ブー" ブザー音出力
		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)
;==========================================================================

		; 1m 秒 x W ウェイトルーチン
wait_w1ms
		movwf	wt1cnt		;1

w1m01		movlw	110		;1
		movwf	wt2cnt		;1

w1m02		goto	$ + 1		;2
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,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	wt1cnt,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

		; 15m 秒 ウェイトルーチン
wait_15ms
		movlw	15		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=1997*W+5
					;Total	(998*15+5)/4MHz*4 = 14.975 mS

		; 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

		; 85m 秒 ウェイトルーチン
wait_85ms
		movlw	85		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*85+5)/4MHz*4 = 84.835 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

		; 1 秒 ウェイトルーチン
wait_1s
		call	wait_500ms

		; 500m 秒 ウェイトルーチン
wait_500ms
		call	wait_250ms

		; 250m 秒 ウェイトルーチン
wait_250ms
		movlw	250		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*250+5)/4MHz*4 = 249.505 mS

;==========================================================================
;		割り込み処理
;==========================================================================

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

		btfsc	INTCON,RAIF	;RAポート変化割り込み か？
		goto	int_ra		;Yes
		goto	int_end		;(Illegal interrupt)

;---------------- タイマー０割り込み処理（ 200μS毎に割り込み）------------

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	sec_flg,0	;"秒"カウンタ更新フラグ = ON

		movf	sel_min,W
		btfsc	STATUS,Z	;"分"選択値 = 0 か？
		goto	int03		;Yes

		; カウントダウンのとき
int02		decfsz	sec_cnt,F	;"秒"カウンタ - 1 = 0 か？
		goto	int_end		;No

		movlw	60
		movwf	sec_cnt		;"秒"カウンタの設定
		decf	min_cnt,F	;"分"カウンタ - 1
		goto	int_end

		; カウントアップのとき
int03		btfsc	mon_flg,0	;監視フラグ = ON か？
		goto	int02		;Yes

		incf	sec_cnt,F	;"秒"カウンタ + 1
		movlw	60
		subwf	sec_cnt,W
		btfss	STATUS,Z	;"秒"カウンタ = 60 か？
		goto	int_end		;No

		clrf	sec_cnt		;"秒"カウンタ = 0
		incf	min_cnt,F	;"分"カウンタ + 1
		movlw	16
		subwf	min_cnt,W
		btfss	STATUS,Z	;"分"カウンタ - 16 = 0 か？
		goto	int_end		;No

		movlw	1
		movwf	min_cnt		;Yes. "分"カウンタ = 1
		incf	min15_cnt,F	;"15分"カウンタ + 1
		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

;---------------- RA ポート変化割り込み処理 -------------------------------

int_ra		bcf	INTCON,RAIF	;RAポート変化割込みフラグをクリア
		bcf	INTCON,RAIE	;RAポート変化割り込みを禁止
		bsf	STATUS,RP0	;バンク 1
		clrf	IOCA		;ポート変化割り込みbit をクリア
		bcf	STATUS,RP0	;バンク 0
;		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) 2019-2020 by M.Yamamoto"

		de	h'ff'

		; バックアップデータ

backup		de	h'03'		;"分" 既定値, タイマー設定値

;==========================================================================

		end			;プログラムの終了
