;***** KitchenTimer.asm ***************************************************
;
;	キッチン(カウントダウン)・タイマー
;
;	Copyright (C) 2010-2019   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2010/11/17  by M.Yamamoto )
;	coding:  Ver. 1.00   2010/11/23  初期バージョン
;	update:  Ver. 1.01   2010/11/27  スリープ機能の追加
;	update:  Ver. 1.02   2010/11/30  TMR0 基準時間発生の変更
;	update:  Ver. 1.03   2010/12/04  スイッチ設定データチェックの追加
;	bugfix:  Ver. 1.04   2013/08/17  チャルメラ音後の暴走回避
;	update:  Ver. 1.05   2013/08/18  ストップウオッチ機能の追加
;	update:  Ver. 1.06   2019/10/22  スリープ後の wake up を追加、
;					 カウントダウン／アップ中のＬＥＤ表示の変更
;
;******************************************************* PicAsm 0226 ******

;	Device: 16F628A	Clock: 10MHz (セラロック)

#ifdef comment

 <機能概要>

・本機はキッチンで使用することを主目的とし、表示は４桁のＬＥＤで行って見やすさと使いやすさを第
　一としている。

・本機の電源をオンにすると、"ピポッ" と開始ブザー音を出力後、バージョン番号がＬＥＤに約１.５秒
　間表示される。その後 EEPROM に記憶されている、前回設定したタイマー時間値が読み出されて、その
　内容がＬＥＤに表示される。

・このタイマー時間の設定は、10M:十分、1M:分、10S:十秒、1S:秒の４つのタクトスイッチで行い、最大
　"９９分５９秒" までが設定可能で、START スイッチがオンされるまでの間は いくらでも変更が可能で
　ある。

・10M:十分、1M:分、10S:十秒、1S:秒の４つのタクトスイッチは、そのままオン操作することにより該当
　の桁を１づつインクリメントする。またこのとき UP/DOWN/STOP スイッチを併用しながらオン操作する
　と、該当の桁を１づつデクリメントする。

・10M:十分、1M:分、1S:秒の３つのスイッチでは、"０" から "９" までの設定が、10S:十秒スイッチで
　は、"０" から "５" までの設定が可能であり、各桁の最大値を超える（インクリメント時）と "０" 
　に戻り、また最小値 "０" を超える（デクリメント時）と各桁の最大値に戻る。

・タイマー時間の設定が済み、START スイッチをオンすると、まずスイッチ入力した設定データの有効性
　チェックが行なわれ、もし "００分００秒" が設定された場合には (( "ブッブー" というブザー音を
　鳴らしてエラー表示をした後、再びタイマー時間の設定状態に戻る。))

　ここで機能の変更追加 (Ver.1.05) を行なった。下記（機能の変更追加）を参照。

・有効性チェックがＯＫだった場合（ "００分０１秒" ～ "９９分５９秒" ）には、次に今回設定された
　タイマー時間を次回に備えて EEPROM に再記録した後、１秒づつのカウントダウンが始まり、その内容
　が刻々とＬＥＤに表示される。　.......... なお、カウントダウン中は電池の消耗を減らすために、
　毎秒ごとに約 1/4 秒間だけのＬＥＤ表示になるように変更をした。(Ver.1.06)

・一方タイマー時間の設定中に、10M:十分、1M:分、10S:十秒、1S:秒、UP/DOWN/STOP スイッチの操作が
　されなくなって（最後にどれかを操作してから）１分が経過すると、ＬＥＤ表示は停止され "ブッブッ
　ブッブッブッブー" とゆっくりブザー音を出力してユーザに知らせた後、本機はスリープモードに移行
　する。これは本機が電池駆動のため、電源の消し忘れ等によってその無駄な消耗を防ぐのが目的のため
　である。　.......... ３分→１分に変更 (Ver.1.06) 

・(( 一旦スリープモードに移行すると本機では目覚めることはないので、タイマー動作を続ける場合は
　一度本機の電源をオフしたあと十数秒後に再び電源をオンにして、初めからやり直す必要がある。))

　ここで機能の変更 (Ver.1.06) を行なった。スリープモード中に START スイッチをオンすると、スリ
　ープが解除されてＬＥＤ表示が戻り、再びタイマー時間の設定を可能とする。

・また、カウントダウン中に UP/DOWN/STOP スイッチがオンされると、カウントダウンは停止され "ブッ
　ブー" というブザー音を出力後、今回設定したタイマー時間のＬＥＤ表示に戻り、再びタイマー時間の
　設定を可能とする。

・カウントダウンが進みやがてタイムアウトになると、それまでの間に操作された SELECT スイッチの位
　置によって "ピポッピポッ" というブザー音か、またはチャルメラのブザー音で知らせる。SELECT ス
　イッチが "１" に選択されていると前者の "ピポッピポッ" 音を５回、"２" に選択されていると後者
　のチャルメラ音を２回繰り返し出力する。

・その後、再び今回設定したタイマー時間のＬＥＤ表示に戻り、タイマー時間の設定を可能とする。

・（機能の変更追加）
　有効性チェックが行なわれ、もし "００分００秒" が設定された場合には、本機はストップウオッチと
　して機能する。 そして EEPROM の再記録は行なわれず以前のままで、１秒づつのカウントアップが始
　まり、その内容が刻々とＬＥＤに表示される。　.......... なお、カウントアップ中も毎秒ごとに約 
　1/4 秒間だけのＬＥＤ表示になるように変更をした。(Ver.1.06)

・簡単な操作でストップウオッチとして機能させるため、タイマー時間の設定状態のときに UP/DOWN/STOP 
　スイッチをオンしながら START スイッチをオンすると、現在ＬＥＤに何が表示されていても、瞬時に
　４桁分ともクリアされ "００分００秒" が設定される。

・カウントアップ中に UP/DOWN/STOP スイッチがオンされることがなく、ＬＥＤに "９９分５９秒" が表
　示されていると、次には "００分００秒" に再び戻り、初めからカウントアップを続ける。

・一方、カウントアップ中に UP/DOWN/STOP スイッチがオンされると、カウントアップは停止され "ブッ
　ブー" というブザー音を２回出力する。

・カウントアップが停止されてＬＥＤに表示されているカウントアップされた値、すなわちストップウオ
　ッチの値を確認後、再び UP/DOWN/STOP スイッチがオンされると、前回設定したタイマー時間のＬＥＤ
　表示に戻り、再びタイマー時間の設定を可能とする。

#endif

;	PIC16F628A のピンと用途

;	 (1) RA2: 7セグLED  1M 桁出力		(18) RA1: 7セグLED 10S 桁出力
;	 (2) RA3: 7セグLED 10M 桁出力		(17) RA0: 7セグLED  1S 桁出力
;	 (3) RA4: UP/DOWN/STOP スイッチ入力	(16) OSC1: オシレータ水晶入力
;	 (4) RA5: SELECT スイッチ入力		(15) OSC2: オシレータ水晶入力
;	 (5) VSS: 電源 GND			(14) VDD: 電源 +5V DC
;	 (6) RB0: a 出力 /  1S 桁スイッチ入力	(13) RB7: ブザー出力 / /BUSY 信号(debug)
;	 (7) RB1: b 出力 / 10S 桁スイッチ入力	(12) RB6: g 出力
;	 (8) RB2: c 出力 /  1M 桁スイッチ入力	(11) RB5: f 出力
;	 (9) RB3: d 出力 / 10M 桁スイッチ入力	(10) RB4: e 出力 / START スイッチ入力

;	*注.  RA4 の出力はオープンドレインのため、外部抵抗でプルアップしないと、High が
;	      出力されない。
;	      RA5 は入力専用で、出力ポートには使えない。

;==========================================================================

	list		p=pic16f628a		;デバイス情報
	include		p16f628a.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config  h'3f02'

;		  _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF
;		& _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

;==========================================================================
;		変数、定数の定義とレジスタ割付
;==========================================================================

;#define 	_debug			;TMR0 基準時間の調整中

#define 	ver_no	"1.06"

		radix	dec

ra0		equ	h'00'		; 1S の桁 7セグLED
ra1		equ	h'01'		;10S の桁 7セグLED
ra2		equ	h'02'		; 1M の桁 7セグLED
ra3		equ	h'03'		;10M の桁 7セグLED
udsw		equ	h'04'		;UP/DOWN/STOP スイッチ
spsw		equ	h'04'		;UP/DOWN/STOP スイッチ
selsw		equ	h'05'		;SELECT スイッチ

sw1		equ	h'00'		; 1S の桁スイッチ
sw2		equ	h'01'		;10S の桁スイッチ
sw3		equ	h'02'		; 1M の桁スイッチ
sw4		equ	h'03'		;10M の桁スイッチ
stsw		equ	h'04'		;START スイッチ

flg0		equ	0		;フラグの ON ビット
flg1		equ	1		;フラグの ON ビット

seg7_0		equ	b'01000000'	;-gfedcba Pattern 0
seg7_1		equ	b'01111001'	;	  Pattern 1
seg7_2		equ	b'00100100'	;	  Pattern 2
seg7_3		equ	b'00110000'	;	  Pattern 3
seg7_4		equ	b'00011001'	;	  Pattern 4
seg7_5		equ	b'00010010'	;	  Pattern 5
seg7_6		equ	b'00000010'	;	  Pattern 6
seg7_7		equ	b'01111000'	;	  Pattern 7
seg7_8		equ	b'00000000'	;	  Pattern 8
seg7_9		equ	b'00010000'	;	  Pattern 9
seg7_v		equ	b'01100011'	;	  Pattern v
seg7_off	equ	b'01111111'	;	  Pattern off

tm0_h_val	equ	256 - 125	;ハードタイマー０カウント値 (0.4 * 2 * 125 = 100μS)
xx		equ	-569			;補正値
tm0_s_val_h	equ	high (10000 + xx)	;ソフトタイマー０の high カウント値
tm0_s_val_l	equ	low  (10000 + xx)	;ソフトタイマー０の low  カウント値
;sleep_val	equ	60 * 3		;スリープカウント値				;
sleep_val	equ	60		;スリープカウント値				;(Ver.1.06 にて変更)

chatt		equ	50		;チャッタリング吸収用ウエイト時間
					;300μ*4=1.2msec --> (1.2msec x 50 = 60msec)
chatt2		equ	130		;ＳＷ連続誤動作吸収用ウエイト時間
					;300μ*4=1.2msec --> (1.2msec x 130 = 156msec)
					;300μ:１桁あたりの点灯時間、4:４桁分
					;1.2msec:１サイクルあたりの所要時間
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

poh		equ	high (65536 - 2389)	;ド (523.26 Hz)  at 10MHz
pol		equ	low  (65536 - 2389)	;
pih		equ	high (65536 - 3189)	;ソ (392.00 Hz)
pil		equ	low  (65536 - 3189)	;
buh		equ	high (65536 - 4778)	;ド (261.63 Hz)
bul		equ	low  (65536 - 4778)	;
polcnt		equ	100		;音長
pilcnt		equ	100		;音長
bulcnt		equ	100		;音長
buulcnt		equ	250		;音長

		cblock	h'20'
cnt10m					;10M 十分カウンタ
cnt01m					; 1M 分カウンタ
cnt10s					;10S 十秒カウンタ
cnt01s					; 1S 秒カウンタ

chatcnt					;チャッタリング吸収カウンタ
chat2cnt				;ＳＷ連続誤動作吸収カウンタ
updwnflg				;UP/DOWN フラグ

start_flg				;START フラグ
tout_flg				;タイムアウトフラグ
tm0_cnt_h				;ソフトタイマー０の high カウンタ
tm0_cnt_l				;ソフトタイマー０の low  カウンタ
sleep_cnt				;スリープカウンタ
led_flg					;LED 消灯フラグ					;(Ver.1.06 にて追加)

scale					;音階コードの保存
length					;音長の保存
tempo					;テンポ指定
repeat					;繰り返し指定
addr_high				;読み出す曲データの high アドレス
addr_low				;読み出す曲データの low アドレス
rep_addr_high				;繰り返し曲データの high アドレス
rep_addr_low				;繰り返し曲データの low アドレス

const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存
wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ
wt4cnt					;ウェイト用ループカウンタ
wt5cnt					;ウェイト用ループカウンタ
lp_cnt					;繰り返しカウンタ
work					;
		endc

		cblock	h'70'
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
		endc

;==========================================================================
;		プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	init
		org	4		;割り込みベクタ
		goto	interrupt

;==========================================================================
;	W に指定された 0～9 の数字を ポートB にセットする
;	 （PCL を操作する場合はプログラムを配置する位置に配慮すること）
;==========================================================================

seg7_set
		call	ptndata
#ifdef _debug
                movf    start_flg,F 
                btfsc   STATUS,Z        ;START フラグ = ON か？
                iorlw   h'80'           ;No, /BUSY 信号 OFF("H")
#endif
		movwf	PORTB
		return

ptndata		movwf	work
		movlw	high $		;;
		movwf	PCLATH		;;
		movf	work,W

		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
		retlw	seg7_v		;10	Version

		; 全セグ消灯パタン
seg7_off_set
		movlw	seg7_off	;LED off
#ifdef _debug
                movf    start_flg,F 
                btfsc   STATUS,Z        ;START フラグ = ON か？
                iorlw   h'80'           ;No, /BUSY 信号 OFF("H")
#endif
		movwf	PORTB
		return

;==========================================================================
;		音階用分周定数を取得(一部だけの省略設定)  at 10MHz
;==========================================================================

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 - 4778)	;28: ド    (261.63Hz)
		retlw	low  (65536 - 4778)
		retlw	high (65536 - 4510)	;29: ド＃  (277.18Hz)
		retlw	low  (65536 - 4510)
		retlw	high (65536 - 4257)	;30: レ    (293.66Hz)
		retlw	low  (65536 - 4257)
		retlw	high (65536 - 4018)	;31: レ＃  (311.13Hz)
		retlw	low  (65536 - 4018)
		retlw	high (65536 - 3792)	;32: ミ    (329.63Hz)
		retlw	low  (65536 - 3792)
		retlw	high (65536 - 3579)	;33: ファ  (349.23Hz)
		retlw	low  (65536 - 3579)
		retlw	high (65536 - 3379)	;34: ファ＃(369.99Hz)
		retlw	low  (65536 - 3379)
		retlw	high (65536 - 3189)	;35: ソ    (392.00Hz)
		retlw	low  (65536 - 3189)
		retlw	high (65536 - 3010)	;36: ソ＃  (415.30Hz)
		retlw	low  (65536 - 3010)
		retlw	high (65536 - 2841)	;37: ラ    (440.00Hz)
		retlw	low  (65536 - 2841)
		retlw	high (65536 - 2682)	;38: ラ＃  (466.16Hz)
		retlw	low  (65536 - 2682)
		retlw	high (65536 - 2531)	;39: シ    (493.88Hz)
		retlw	low  (65536 - 2531)
		retlw	high (65536 - 2389)	;40: ド    (523.26Hz)
		retlw	low  (65536 - 2389)

;==========================================================================
;		初期化処理
;==========================================================================

init
		; PIC16F628A 初期設定

		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'00110000'	;RA5-4: 入力, RA3-0: 出力
		movwf	TRISA		;ポートA の I/0 設定
		clrf	TRISB		;ポートB の I/O 設定, RB7-0: 出力

		movlw	b'10000000'	;bit7=1: プルアップ抵抗を使用しない
					;bit3=0: プリスケーラをTMR0タイマーに使用
					;bit2-0=000: プリスケーラのスケール値 1:2
		movwf	OPTION_REG	;OPTION_REG の設定

		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		movlw	b'00000001'	;bit7-6: 未使用
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON の設定

		bsf	INTCON,PEIE	;PEIE 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE  グローバル割り込み許可

		; 起動ブザー音の出力と ver_no データの表示

		movlw	h'0f'
		movwf	PORTA		;LED 全桁消灯
		call	buzzer_pipo	;"ピポッ" ブザー音出力

		call	ver_read	;ver_no データの読み出し
		clrf	led_flg		;LED 消灯フラグ = OFF				;(Ver.1.06 にて追加)

		movlw	5		;約 1.5 秒間表示
		movwf	wt5cnt		;1.2mS * 250 * 5
ini01		movlw	250
		movwf	wt4cnt
ini02		call	led_disp	;ver_no の 7セグLED 表示
		decfsz	wt4cnt,F
		goto	ini02
		decfsz	wt5cnt,F
		goto	ini01

		; EEPROM データの読み出し

ini03		movlw	cnt10m		;10M 十分カウンタ
		movwf	FSR		;間接アドレスに設定

		bsf	STATUS,RP0	;バンク 1
		movlw	eep_size
		movwf	EEADR		;EEPROM の記録アドレスを設定
		bcf	STATUS,RP0	;バンク 0

ini04		bsf	STATUS,RP0	;バンク 1
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し

		incf	EEADR,F		;記録アドレスの更新
		bcf	STATUS,RP0	;バンク 0

		movwf	INDF		;カウンタデータへ書き込み

		incf	FSR,F		;間接アドレスの更新
		movlw	cnt10m + 4
		subwf	FSR,W
		btfss	STATUS,Z	;書き込みアドレス 終了か?
		goto	ini04		;No

		; 各変数の初期設定

		clrf	chatcnt		;チャッタリング吸収カウンタの初期設定
		clrf	chat2cnt	;ＳＷ連続誤動作吸収カウンタの初期設定
		clrf	updwnflg	;UP/DOWN フラグの初期設定
		clrf	tout_flg	;タイムアウトフラグの初期設定
		clrf	start_flg	;START フラグの初期設定
		clrf	led_flg		;LED 消灯フラグ = OFF				;(Ver.1.06 にて追加)

		call	sleep_set	;スリープまでの時間設定
		goto	main

;==========================================================================

		; スリープまでの時間設定
sleep_set
		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	tm0_s_val_h	;ソフトタイマー０の high カウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	tm0_s_val_l	;ソフトタイマー０の low  カウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		movlw	sleep_val	;スリープカウント値
		movwf	sleep_cnt	;スリープカウンタの設定

		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		return

		; ver_no データの読み出し
ver_read
		movlw	cnt10m		;10M 十分カウンタ
		movwf	FSR		;間接アドレスに設定

		movlw	high ver_data	;ver_no データの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low ver_data	;ver_no データの先頭アドレスの low アドレス
		movwf	addr_low	;

ver01		call	kdt_read	;ver_no データの読み出し

		addlw	0
		btfsc	STATUS,Z	;h'00' か？
		goto	ver03		;Yes

		movwf	INDF		;カウンタデータへ書き込み

		sublw	'.'
		btfsc	STATUS,Z	;'.' か？
		goto	ver01		;Yes

		movlw	'0'
		subwf	INDF,W		;
		btfss	STATUS,C	;INDF < '0' か？
		goto	ver02		;Yes

		movlw	'0'
		subwf	INDF,F		;binary に変換

ver02		incf	FSR,F		;間接アドレスの更新
		goto	ver01		;No

ver03		return

ver_data	dt	10,ver_no,0

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main
		call	led_disp	;タイマーカウントの 7セグLED 表示

		btfsc	start_flg,flg0	;START フラグ = ON か？ (カウントダウン)
		goto	m03		;Yes

		btfsc	start_flg,flg1	;START フラグ = ON か？ (カウントアップ)
		goto	m09		;Yes

		; 各種スイッチのチェック

		movf	chat2cnt,F
		btfsc	STATUS,Z	;ＳＷ連続誤動作吸収カウンタ = 0 か？
		goto	m01		;Yes

		decfsz	chat2cnt,F	;ＳＷ連続誤動作吸収カウンタ - 1 = 0 か？
		goto	main		;No

m01		call	seg7_off_set
		bsf	PORTA,ra0	; 1S の桁を消灯

		btfss	PORTA,udsw	;UP/DOWN/STOP スイッチ = ON か？
		call	udsw_on		;Yes
		btfsc	PORTA,udsw	;UP/DOWN/STOP スイッチ = OFF か？
		call	udsw_off	;Yes

		bsf	STATUS,RP0	;バンク 1
		movlw	b'00011111'	;RB7-5: 出力, RB4-0: 入力
		movwf	TRISB		;ポートB の I/0 設定
		bcf	STATUS,RP0	;バンク 0

		btfss	PORTB,sw1	; 1S の桁スイッチ = ON か？
		call	sw1_on		;Yes
		btfss	PORTB,sw2	;10S の桁スイッチ = ON か？
		call	sw2_on		;Yes
		btfss	PORTB,sw3	; 1M の桁スイッチ = ON か？
		call	sw3_on		;Yes
		btfss	PORTB,sw4	;10M の桁スイッチ = ON か？
		call	sw4_on		;Yes

		btfss	PORTB,stsw	;START スイッチ = ON か？
		call	stsw_on		;Yes 

		bsf	STATUS,RP0	;バンク 1
		clrf	TRISB		;ポートB の I/O 設定, RB7-0: 出力
		bcf	STATUS,RP0	;バンク 0

		movf	sleep_cnt,F
		btfss	STATUS,Z	;sleep_cnt = 0 か？
		goto	main		;No

		; スリープモードに突入

m0z		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		movlw	h'0f'
		movwf	PORTA		;LED 全桁消灯

		movlw	5
		movwf	lp_cnt		;繰り返しカウンタ

m02		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_250ms
		call	wait_250ms
		call	wait_250ms
		decfsz	lp_cnt,F	;
		goto	m02

		call	buzzer_buu	;"ブー" ブザー音出力
		call	buzzer_buu	;"ブー" ブザー音出力
;;		sleep			;スリープ					;(Ver.1.06 にて削除)

;;;;;;;;;;;;;;;;									;
		bsf	STATUS,RP0	;バンク 1					;
		bsf	TRISB,4		;RB4 入力設定					;
		bcf	STATUS,RP0	;バンク 0					;
											;
m0x		bsf	INTCON,RBIE	;RBポート変化割り込みを許可			;
		sleep			;						;
		;									;
		;			;wake up					;
		btfsc	PORTB,4		;スイッチ操作 = あり か？			;
		goto	m0x		;No. 操作なしでポート変化 ... 再度 sleep	;
											;
		movlw	50								;(Ver.1.06 にて追加)
		call	wait_w1ms	;チャタリング吸収				;
											;
m0y		btfss	PORTB,4		;スイッチ操作 = なし（終った） か？		;
		goto	m0y		;No						;
											;
		movlw	50								;
		call	wait_w1ms	;チャタリング吸収				;
		bsf	STATUS,RP0	;バンク 1					;
		bcf	TRISB,4		;RB4 出力設定					;
		bcf	STATUS,RP0	;バンク 0					;
		goto	ini03		;						;
;;;;;;;;;;;;;;;;									;

		; カウントダウン中

m03		btfsc	PORTA,spsw	;UP/DOWN/STOP スイッチ = ON か？
		goto	m04		;No
					;Yes, (中断)
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		goto	m08

m04		btfss	tout_flg,flg0	;タイムアウトフラグ = ON か？
		goto	main		;No

		; タイムアウト

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		movf	cnt01s,W	; 1S 秒カウンタ値のパタンを
		call	seg7_set	;ポートB にセット
#ifdef _debug
		movlw	h'80'
		iorwf	PORTB,F		;/BUSY 信号 OFF("H")
		btfsc	PORTA,udsw	;UP/DOWN/STOP スイッチ = ON か？
		goto	$ - 1		;No
#endif
		btfss	PORTA,selsw	;SELECT スイッチ = ON か？
		goto	m06		;Yes

		; "ピポッピポッ" x 5 ブザー音出力

		movlw	5
		movwf	lp_cnt		;繰り返しカウンタ

m05		call	buzzer_pipo	;"ピポッ" ブザー音出力
		movlw	30
		call	wait_w1ms
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_250ms

		decfsz	lp_cnt,F	;
		goto	m05
		goto	m08

		; チャルメラ x 2 ブザー音出力

m06		movlw	2
		movwf	lp_cnt		;繰り返しカウンタ

m07		movlw	high charamela
		movwf	addr_high	;読み出す曲データの high アドレスを設定
		movlw	low  charamela
		movwf	addr_low	;読み出す曲データの low  アドレスを設定

		call	play_back	;曲データの再生
		call	wait_1s

		decfsz	lp_cnt,F	;
		goto	m07

m08		goto	ini03		;初期化処理(EEPROM データの読み出し)へジャンプ

		; カウントアップ中 (Ver.1.05 にて追加)

m09		btfsc	PORTA,spsw	;UP/DOWN/STOP スイッチ = ON か？
		goto	main		;No
					;Yes. (ストップ)
		; カウントストップ

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
#ifdef _debug
		movlw	h'80'
		iorwf	PORTB,F		;/BUSY 信号 OFF("H")
#endif
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		call	wait_250ms
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		clrf	start_flg	;START フラグの初期設定
		clrf	led_flg		;LED 消灯フラグ = OFF				;(Ver.1.06 にて追加)
		call	sleep_set	;スリープまでの時間設定				;

m10		call	led_disp	;タイマーカウントの 7セグLED 表示
		movf	sleep_cnt,F							;
		btfsc	STATUS,Z	;sleep_cnt = 0 か？				;(Ver.1.06 にて追加)
		goto	m0z		;Yes						;
											;
		btfsc	PORTA,spsw	;UP/DOWN/STOP スイッチ = ON か？
		goto	m10		;No

		goto	ini03

;==========================================================================

		; チャルメラ音出力データ
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

;==========================================================================
;		タイマーカウントの 7セグLED 表示
;==========================================================================

led_disp
		btfsc	led_flg,0	;LED 消灯フラグ = ON か？			;(Ver.1.06 にて追加)
		goto	led_01		;Yes						;

		; (10M 十分カウンタの処理)
		call	seg7_off_set
		bsf	PORTA,ra0	; 1S の桁を消灯
		bcf	PORTA,ra3	;10M の桁を点灯

		movf	cnt10m,W	;10M 十分カウンタ値のパタンを
		call	seg7_set	;ポートB にセット

		call	wait_300us	;１桁の表示時間

		; (1M 分カウンタの処理)
		call	seg7_off_set
		bsf	PORTA,ra3	;10M の桁を消灯
		bcf	PORTA,ra2	; 1M の桁を点灯

		movf	cnt01m,W	; 1M 分カウンタ値のパタンを
		call	seg7_set	;ポートB にセット

		call	wait_300us	;１桁の表示時間

		; (10S 十秒カウンタの処理)
		call	seg7_off_set
		bsf	PORTA,ra2	; 1M の桁を消灯
		bcf	PORTA,ra1	;10S の桁を点灯

		movf	cnt10s,W	;10S 十秒カウンタ値のパタンを
		call	seg7_set	;ポートB にセット

		call	wait_300us	;１桁の表示時間

		; (1S 秒カウンタの処理)
		call	seg7_off_set
		bsf	PORTA,ra1	;10S の桁を消灯
		bcf	PORTA,ra0	; 1S の桁を点灯

		movf	cnt01s,W	; 1S 秒カウンタ値のパタンを
		call	seg7_set	;ポートB にセット

		call	wait_300us	;１桁の表示時間

led_01		call	seg7_off_set							;(Ver.1.06 にて追加)
		bsf	PORTA,ra0	; 1S の桁を消灯					;
		return

;==========================================================================
;               stsw: START スイッチ = ON の処理 (Ver.1.05 にて変更追加)
;==========================================================================

stsw_on
		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	ston01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

ston01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	ston08		;No

		btfss	updwnflg,flg0	;UP/DOWN フラグ = 0 か？
		goto	ston02		;Yes

		clrf	cnt01s
		clrf	cnt10s
		clrf	cnt01m
		clrf	cnt10m

		movlw	chatt2		;ＳＷ連続誤動作吸収用ウエイト時間を
		movwf	chat2cnt	;ＳＷ連続誤動作吸収カウンタに設定
		call	sleep_set	;スリープまでの時間設定
		goto	ston08

		; スイッチ入力設定データの有効性チェック

ston02		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		movf	cnt01s,W
		btfss	STATUS,Z	;秒カウンタ = 0 か？
		goto	ston03		;No

		movf	cnt10s,W 
		btfss	STATUS,Z	;十秒カウンタ = 0 か？
		goto	ston03		;No

		movf	cnt01m,W
		btfss	STATUS,Z	;分カウンタ = 0 か？
		goto	ston03		;No

		movf	cnt10m,W
		btfss	STATUS,Z	;十分カウンタ = 0 か？
		goto	ston03		;No

;		(Ver.1.05 にて変更)
;		call	buzzer_bubuu	;Error: "ブッブー" ブザー音出力
;		call	sleep_set	;スリープまでの時間設定

		bsf	start_flg,flg1	;START フラグ = ON (カウントアッップ)
		goto	ston07

		; EEPROM データの読み出しと書き込み

ston03		movlw	cnt10m		;10M 十分カウンタ
		movwf	FSR		;間接アドレスに設定

		bsf	STATUS,RP0	;バンク 1
		movlw	eep_size
		movwf	EEADR		;EEPROM の記録アドレスを設定
		bcf	STATUS,RP0	;バンク 0

		; (読み出し)
ston04		bsf	STATUS,RP0	;バンク 1
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し
		bcf	STATUS,RP0	;バンク 0

		; (比較)
		subwf	INDF,W
		btfsc	STATUS,Z	;(INDF) = (EEDATA) か？
		goto	ston06		;Yes

		; (書き込み)
		movf	INDF,W		;書き込みデータを

		bsf	STATUS,RP0	;バンク 1
		movwf	EEDATA		;EEDATA に設定
		bsf	EECON1,WREN	;書き込みイネーブル = ON
		movlw	h'55'
		movwf	EECON2		;h'55' を EECON2 に書き込む
		movlw	h'aa'
		movwf	EECON2		;h'aa' を EECON2 に書き込む
		bsf	EECON1,WR	;書き込み制御 = ON
ston05		btfsc	EECON1,WR	;書き込み 終了か?
		goto	ston05
		bcf	STATUS,RP0	;バンク 0

		bcf	PIR1,EEIF	;書き込み完了割り込みフラグのクリア
		bsf	STATUS,RP0	;バンク 1
		bcf	EECON1,WREN	;書き込みイネーブル = OFF
		bcf	STATUS,RP0	;バンク 0

		; (アドレスの更新)
ston06		bsf	STATUS,RP0	;バンク 1
		incf	EEADR,F		;記録アドレスの更新
		bcf	STATUS,RP0	;バンク 0

		incf	FSR,F		;間接アドレスの更新
		movlw	cnt10m + 4
		subwf	FSR,W
		btfss	STATUS,Z	;書き込みアドレス 終了か?
		goto	ston04		;No

		bsf	start_flg,flg0	;START フラグ = ON (カウントダウン)

		; カウントダウン／アッップ・スタート

ston07		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	tm0_s_val_h	;ソフトタイマー０の high カウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	tm0_s_val_l	;ソフトタイマー０の low  カウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		clrf	led_flg		;LED 消灯フラグ = OFF				;(Ver.1.06 にて追加)
		bsf	INTCON,T0IE	;タイマー０割り込みを許可

ston08		return

;==========================================================================
;		SW1: 1S の桁スイッチ = ON の処理
;==========================================================================

sw1_on
		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	s1on01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

s1on01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	s1on04		;No

		btfsc	updwnflg,flg0	;UP/DOWN フラグ = 0 か？
		goto	s1on02		;No

		incf	cnt01s,F	;1S 秒カウンタの +1 更新

		movlw	10
		subwf	cnt01s,W	;cnt01s >= 10 か？
		btfsc	STATUS,C
		clrf	cnt01s		;Yes, 1S 秒カウンタ = 0 に設定
		goto	s1on03

s1on02		movlw	1
		subwf	cnt01s,F	;1S 秒カウンタの -1 更新
		btfsc	STATUS,C	;cnt01s >= 0 か？
		goto	s1on03		;Yes

		movlw	9
		movwf	cnt01s		;1S 秒カウンタ = 9 に設定

s1on03		movlw	chatt2		;ＳＷ連続誤動作吸収用ウエイト時間を
		movwf	chat2cnt	;ＳＷ連続誤動作吸収カウンタに設定
		call	sleep_set	;スリープまでの時間設定

s1on04		return

;==========================================================================
;		SW2: 10S の桁スイッチ = ON の処理
;==========================================================================

sw2_on
		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	s2on01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

s2on01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	s2on04		;No

		btfsc	updwnflg,flg0	;UP/DOWN フラグ = 0 か？
		goto	s2on02		;No

		incf	cnt10s,F	;10S 十秒カウンタの +1 更新
		movlw	6
		subwf	cnt10s,W	;cnt10s >= 6 か？
		btfsc	STATUS,C
		clrf	cnt10s		;Yes, 10S 十秒カウンタ = 0 に設定
		goto	s2on03

s2on02		movlw	1
		subwf	cnt10s,F	;10S 十秒カウンタの -1 更新
		btfsc	STATUS,C	;cnt10s >= 0 か？
		goto	s2on03		;Yes

		movlw	5
		movwf	cnt10s		;10S 十秒カウンタ = 5 に設定

s2on03		movlw	chatt2		;ＳＷ連続誤動作吸収用ウエイト時間を
		movwf	chat2cnt	;ＳＷ連続誤動作吸収カウンタに設定
		call	sleep_set	;スリープまでの時間設定

s2on04		return

;==========================================================================
;		SW3: 1M の桁スイッチ = ON の処理
;==========================================================================

sw3_on
		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	s3on01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

s3on01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	s3on04		;No

		btfsc	updwnflg,flg0	;UP/DOWN フラグ = 0 か？
		goto	s3on02		;No

		incf	cnt01m,F	;1M 分カウンタの +1 更新
		movlw	10
		subwf	cnt01m,W	;cnt01m >= 10 か？
		btfsc	STATUS,C
		clrf	cnt01m		;Yes, 1M 分カウンタ = 0 に設定
		goto	s3on03

s3on02		movlw	1
		subwf	cnt01m,F	;1M 分カウンタの -1 更新
		btfsc	STATUS,C	;cnt01m >= 0 か？
		goto	s3on03		;Yes

		movlw	9
		movwf	cnt01m		;1M 分カウンタ = 9 に設定

s3on03		movlw	chatt2		;ＳＷ連続誤動作吸収用ウエイト時間を
		movwf	chat2cnt	;ＳＷ連続誤動作吸収カウンタに設定
		call	sleep_set	;スリープまでの時間設定

s3on04		return

;==========================================================================
;		SW4: 10M の桁スイッチ = ON の処理
;==========================================================================

sw4_on
		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	s4on01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

s4on01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	s4on04		;No

		btfsc	updwnflg,flg0	;UP/DOWN フラグ = 0 か？
		goto	s4on02		;No

		incf	cnt10m,F	;10M 十分カウンタの +1 更新
		movlw	10
		subwf	cnt10m,W	;cnt10m >= 10 か？
		btfsc	STATUS,C
		clrf	cnt10m		;Yes, 10M 十分カウンタ = 0 に設定
		goto	s4on03

s4on02		movlw	1
		subwf	cnt10m,F	;10M 十分カウンタの -1 更新
		btfsc	STATUS,C	;cnt10m >= 0 か？
		goto	s4on03		;Yes

		movlw	9
		movwf	cnt10m		;10M 十分カウンタ = 9 に設定

s4on03		movlw	chatt2		;ＳＷ連続誤動作吸収用ウエイト時間を
		movwf	chat2cnt	;ＳＷ連続誤動作吸収カウンタに設定
		call	sleep_set	;スリープまでの時間設定

s4on04		return

;==========================================================================
;		udsw: UP/DOWN/BREAK スイッチ = ON の処理
;==========================================================================

udsw_on
		btfsc	updwnflg,flg0	;UP/DOWN フラグ = OFF か？
		goto	udon02		;No

		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	udon01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

udon01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	udon02		;No

		bsf	updwnflg,flg0	;UP/DOWN フラグ = ON
		call	sleep_set	;スリープまでの時間設定

udon02		return

;==========================================================================
;		udsw: UP/DOWN/BREAK スイッチ = OFF の処理
;==========================================================================

udsw_off
		btfss	updwnflg,flg0	;UP/DOWN フラグ = ON か？
		goto	udof02		;No

		movf	chatcnt,W
		btfss	STATUS,Z	;チャッタリング吸収カウンタ <> 0 か？
		goto	udof01		;Yes

		movlw	chatt + 1	;チャッタリング吸収用ウエイト時間を
		movwf	chatcnt		;チャッタリング吸収カウンタに設定

udof01		decfsz	chatcnt,F	;チャッタリング吸収カウンタ - 1 = 0 か？
		goto	udof02		;No

		bcf	updwnflg,flg0	;UP/DOWN フラグ = OFF

udof02		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	wt5cnt		;ループカウンタを設定

ply05		movlw	1
		call	wait_w1ms	;音長を (tempo * length) 倍で再生
		decfsz	wt5cnt,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,spsw	;STOP スイッチ = 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

;==========================================================================
;		ブザー音出力ルーチン
;==========================================================================

		; "ポッ" ブザー音出力
buzzer_po
		movlw	poh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	pol
		movwf	const_low	;音階用分周定数 low を設定
		movlw	polcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ピッ" ブザー音出力
buzzer_pi
		movlw	pih
		movwf	const_high	;音階用分周定数 high を設定
		movlw	pil
		movwf	const_low	;音階用分周定数 low を設定
		movlw	pilcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ピポッ" ブザー音出力
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		movlw	30
		call	wait_w1ms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ブッ" ブザー音出力
buzzer_bu
		movlw	buh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	bul
		movwf	const_low	;音階用分周定数 low を設定
		movlw	bulcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ブー" ブザー音出力
buzzer_buu
		movlw	buh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	bul
		movwf	const_low	;音階用分周定数 low を設定
		movlw	buulcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ブッブー" ブザー音出力
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_100ms
		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

;==========================================================================
;		ウェイト・ルーチン (10 MHz)
;==========================================================================

		; 10μ秒 ウェイトルーチン
wait_10us
		movlw	5		;1
w10u01		movwf	wt1cnt		;1
		nop			;1
		nop			;1
w10u02		nop			;1
		decfsz	wt1cnt,F	;1,2
		goto	w10u02		;2,0	1+1+1+1+(1+1+2)*4+(1+2+0)=23
		return			;2	23+2=25
					;Total	25/10MHz*4 = 0.00001 S = 10 μS

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	60		;1
		goto	w10u01		;2	1+2+(1+1+1+(1+1+2)*59+(1+2+0)+2)=247
					;Total	247/10MHz*4 = 0.0000988 S = 98.8 μS

		; 300μ秒 ウェイトルーチン
wait_300us
		movlw	184		;1
		goto	w10u01		;2	1+2+(1+1+1+(1+1+2)*184+(1+2+0)+2)=747
					;Total	747/10MHz*4 = 0.0002988 S = 298.8 μS

		; 1m 秒 x W ウェイトルーチン
wait_w1ms
		movwf	wt3cnt		;1
w1m01		movlw	10		;1
		movwf	wt2cnt		;1
		goto	$ + 1		;2
		goto	$ + 1		;2
w1m02		nop			;1
		call	wait_100us	;245	2+243
		decfsz	wt2cnt,F	;1,2
		goto	w1m02		;2,0	(1+245+1+2)*9+(1+245+2+0)=2489

		decfsz	wt3cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+2+2+2489+1+2)*(W-1)+(1+1+2+2+2489+2+0)=2498*W-1
		return			;2	1+(2498*W-1)+2=2498*W+2
					;Total	(2498*W+2)/10MHz*4 = 999.2*W + 0.8 μS

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100		;
		goto	wait_w1ms	;	1+2+(2498*100+2)=249805
					;Total	249805/10MHz*4 = 99922 μS = 99.922 mS

		; 200m 秒 ウェイトルーチン
wait_200ms
		movlw	200		;
		goto	wait_w1ms	;	1+2+(2498*200+2)=499605
					;Total	499605/10MHz*4 = 199842 μS = 199.842 mS

		; 250m 秒 ウェイトルーチン
wait_250ms
		movlw	250		;
		goto	wait_w1ms	;	1+2+(2498*250+2)=624505
					;Total	624505/10MHz*4 = 249802 μS = 249.802 mS

		; 約 1 秒 ウェイトルーチン
wait_1s
		movlw	d'10'		;
		movwf	wt4cnt		;
w1s01		call	wait_100ms	;	249805+2
		decfsz	wt4cnt,F	;
		goto	w1s01		;	1+1+(249807+1+2)*9+(249807+2+0)
		return			;	2498101+2
					;Total	2498103/10MHz*4 = 999241.2 μS = 1 S

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		btfsc	INTCON,T0IF	;タイマー０オーバフロー か？
		goto	int_0		;Yes

		btfsc	PIR1,TMR1IF	;タイマー１オーバフロー か？
		goto	int_1		;Yes

		btfsc	INTCON,RBIF	;RBポート変化割り込み か？			;(Ver.1.06 にて追加)
		goto	int_rb		;Yes						;
		goto	int_end		;(Illegal interrupt)

		; タイマー０割り込み処理

int_0		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						;(Ver.1.06 にて変更)
		goto	int04		;No						;

		movlw	tm0_s_val_h	;ソフトタイマー０の high カウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	tm0_s_val_l	;ソフトタイマー０の low  カウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		clrf	led_flg		;LED 消灯フラグ = OFF				;(Ver.1.06 にて追加)

		btfsc	start_flg,flg0	;START フラグ = ON か？
		goto	int02		;Yes

		btfsc	start_flg,flg1	;START フラグ = ON か？
		goto	int03		;Yes

	;;	decfsz	sleep_cnt,F	;スリープカウンタ = 0 か？
		decf	sleep_cnt,F
		goto	int_end		;No

int02		call	count_down	;タイマー・カウントダウン
		goto	int_end

int03		call	count_up	;ストップウオッチ・カウントアップ
		goto	int_end

int04		movf	start_flg,W							;
		btfsc	STATUS,Z	;START フラグ = ON か？				;
		goto	int_end		;No						;
											;
		movlw	tm0_s_val_h * 3 / 4 + 1						;(Ver.1.06 にて追加)
		subwf	tm0_cnt_h,W							;
		btfss	STATUS,C	;tm0_cnt_h < (tm0_s_val_h * 3 / 4 + 1) か？	;
		bsf	led_flg,0	;Yes. LED 消灯フラグ = ON			;
		goto	int_end								;

		; タイマー１割り込み処理

int_1		bcf	PIR1,TMR1IF	;タイマー１オーバフロー解除

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

		movlw	b'10000000'	;RB7: ブザー音出力, 対象ビットをセット
		xorwf	PORTB,F		;出力をビット反転
		goto	int_end								;
											;
		; RB ポート変化割り込み処理						;(Ver.1.06 にて追加)
											;
int_rb		bcf	INTCON,RBIF	;RBポート変化割り込みフラグをクリア		;
		bcf	INTCON,RBIE	;RBポート変化割り込みを禁止			;
;		goto	int_end

		; レジスタの復帰

int_end		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰

;==========================================================================

		; タイマー・カウントダウン
count_down
		decfsz	cnt01s,W	;秒カウンタ - 1 = 0 か？
		goto	cdn01		;No

		movf	cnt10s,W 
		btfss	STATUS,Z	;十秒カウンタ = 0 か？
		goto	cdn01		;No

		movf	cnt01m,W
		btfss	STATUS,Z	;分カウンタ = 0 か？
		goto	cdn01		;No

		movf	cnt10m,W
		btfss	STATUS,Z	;十分カウンタ = 0 か？
		goto	cdn01		;No

		decf	cnt01s,F	;秒カウンタ - 1
		bsf	tout_flg,flg0	;タイムアウトフラグ ON 設定
		goto	cdn05

cdn01		movf	cnt01s,W
		btfsc	STATUS,Z	;秒カウンタ = 0 か？
		goto	cdn02		;Yes
		decf	cnt01s,F	;秒カウンタ - 1
		goto	cdn05

cdn02		movlw	9
		movwf	cnt01s		;秒カウンタ = 9 設定
		movf	cnt10s,W 
		btfsc	STATUS,Z	;十秒カウンタ = 0 か？
		goto	cdn03		;Yes
		decf	cnt10s,F	;十秒カウンタ - 1
		goto	cdn05

cdn03		movlw	5 
		movwf	cnt10s		;十秒カウンタ = 5 設定
		movf	cnt01m,W
		btfsc	STATUS,Z	;分カウンタ = 0 か？
		goto	cdn04		;Yes
		decf	cnt01m,F	;分カウンタ - 1
		goto	cdn05

cdn04		movlw	9
		movwf	cnt01m		;分カウンタ = 9 設定
		movf	cnt10m,W
		btfsc	STATUS,Z	;十分カウンタ = 0 か？
		goto	cdn05		;Yes
		decf	cnt10m,F	;十分カウンタ - 1

cdn05		return

		; ストップウオッチ・カウントアップ (Ver.1.05 にて追加)
count_up
		incf	cnt01s,F	;秒カウンタ + 1
		movlw	10
		subwf	cnt01s,W
		btfss	STATUS,C	;秒カウンタ >= 10 か？
		goto	cup01		;No

		clrf	cnt01s		;秒カウンタ = 0

		incf	cnt10s,F	;十秒カウンタ + 1
		movlw	6
		subwf	cnt10s,W
		btfss	STATUS,C	;十秒カウンタ >= 6 か？
		goto	cup01		;No

		clrf	cnt10s		;十秒カウンタ = 0

		incf	cnt01m,F	;分カウンタ + 1
		movlw	10
		subwf	cnt01m,W
		btfss	STATUS,C	;分カウンタ >= 10 か？
		goto	cup01		;No

		clrf	cnt01m		;分カウンタ = 0

		incf	cnt10m,F	;十分カウンタ + 1
		movlw	10
		subwf	cnt10m,W
		btfss	STATUS,C	;十分カウンタ >= 10 か？
		goto	cup01		;No

		clrf	cnt10m		;十分カウンタ = 0

cup01		return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2010-2019 by M.Yamamoto"

		de	h'ff'

eep_size	equ	$ - eep_st	;EEPROM データサイズ

;		de	h'ff'		;タイマー設定値の記録位置

		de	h'00',h'00',h'00',h'00'

;==========================================================================

		end			;プログラムの終了
